简体   繁体   中英

Drag and move a graph line with mouse in matplotlib of python

I am trying to produce an interactive graph in python's matplotlib. I have two sets of data, one is drawn as scatter plot and other is line plot. My minimal code is as follows.

import numpy as np
import matplotlib.pyplot as plt

model = np.array([(0.310, -0.687), (0.407, -0.355), (0.455, -0.142), (0.504, 0.061), (0.552, 0.238), 
                  (0.601,  0.380), (0.698,  0.549), (0.746,  0.581), (0.795, 0.587), (0.859, 0.567), 
                  (0.956,  0.511), (1.053,  0.473), (1.150,  0.489), (1.199, 0.523), (1.296, 0.640), 
                  (1.393,  0.812), (1.490,  0.981), (1.587,  1.189), (1.684, 1.386), (1.781, 1.572), 
                  (1.878, 1.766)])

obser = np.array([(0.212, -0.114), (0.199, 0.017), (0.259, 0.020), (0.199, 0.076), (0.297, 0.082), 
                  (0.735, 0.085), (0.641, 0.104), (0.791, 0.104), (0.681, 0.109), (0.606, 0.132), 
                  (0.262, 0.135), (0.813, 0.137), (0.334, 0.157), (0.565, 0.165), (0.647, 0.170), 
                  (0.876, 0.174), (0.746, 0.186), (0.509, 0.197), (0.398, 0.203), (0.693, 0.207), 
                  (0.829, 0.215), (0.299, 0.226), (0.585, 0.228), (0.549, 0.242), (0.430, 0.242), 
                  (0.637, 0.253), (0.511, 0.257), (0.918, 0.268), (0.813, 0.269), (0.746, 0.271), 
                  (0.336, 0.288), (0.449, 0.297), (0.398, 0.299), (0.783, 0.306), (0.578, 0.312), 
                  (0.871, 0.330), (0.515, 0.345), (0.468, 0.353), (0.818, 0.380), (0.936, 0.391), 
                  (0.889, 0.416), (0.876, 0.503), (1.027, 0.522), (1.040, 0.601), (0.965, 0.656), 
                  (1.130, 0.796), (1.224, 0.845), (1.261, 0.964), (1.378, 1.149)])

fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(9,6))
fig.subplots_adjust(wspace=0.5, hspace=0)

model2 = model - (0.37, 0.32)

ax1.invert_yaxis()
ax1.set_xlabel("BmV")
ax1.set_ylabel("UmB")
ax1.scatter(obser[:, 0], obser[:, 1], s=2, c="black")
ax1.plot(model[:, 0], model[:, 1], linewidth=1, c="red")
ax1.text(0.7, 0.96, 'Before', verticalalignment='top', horizontalalignment='left', 
    transform = ax1.transAxes, color = 'black', fontsize=12)

ax2.invert_yaxis()
ax2.set_xlabel("BmV")
ax2.set_ylabel("UmB")
ax2.scatter(obser[:, 0], obser[:, 1], s=2, c="black")
ax2.plot(model2[:, 0], model2[:, 1], linewidth=1, c="red")
ax2.text(0.8, 0.96, 'After', verticalalignment='top', horizontalalignment='left', 
    transform = ax2.transAxes, color = 'black', fontsize=12)

plt.show()

I want to drag and move the red line plot with mouse from "before" location to "after" location.

How can we do that?

Before and After case

Here is my working example.

import numpy as np
import matplotlib.pyplot as plt

class MoveGraphLine(object):
    def __init__(self, ax, graf, obj, eubv):
        self.ax = ax
        self.figcanvas = self.ax.figure.canvas
        self.graf = graf
        self.obj = obj
        self.kayma = 0.0
        self.ebv, self.eub = eubv
        self.moved = None
        self.point = None
        self.pressed = False
        self.start = False

        self.figcanvas.mpl_connect('button_press_event', self.mouse_press)
        self.figcanvas.mpl_connect('button_release_event', self.mouse_release)
        self.figcanvas.mpl_connect('motion_notify_event', self.mouse_move)

    def mouse_release(self, event):
        if self.ax.get_navigate_mode()!= None: return
        if not event.inaxes: return
        if event.inaxes != self.ax: return
        if self.pressed: 
            self.pressed = False
            self.start = False
            self.point = None
            self.ebv -= self.kayma
            self.obj = self.moved
            return

    def mouse_press(self, event):
        if self.ax.get_navigate_mode()!= None: return
        if not event.inaxes: return
        if event.inaxes != self.ax: return
        if self.start: return
        self.point = event.xdata
        self.pressed = True

    def mouse_move(self, event):
        if self.ax.get_navigate_mode()!= None: return
        if not event.inaxes: return
        if event.inaxes != self.ax: return
        if not self.pressed: return
        self.start = True

        self.kayma = self.point - event.xdata
        keub = 0.72 * self.kayma + 0.025 * self.kayma**2
        self.moved = self.obj - [self.kayma, keub]
        mvdx, mvdy = self.moved[:, 0], self.moved[:, 1]

        self.graf.remove()
        self.graf, = self.ax.plot(mvdx, mvdy, linewidth=1.1, c="b")

        self.figcanvas.draw()


model = np.array([(0.310, -0.687), (0.407, -0.355), (0.455, -0.142), (0.504, 0.061), (0.552, 0.238), 
                  (0.601,  0.380), (0.698,  0.549), (0.746,  0.581), (0.795, 0.587), (0.859, 0.567), 
                  (0.956,  0.511), (1.053,  0.473), (1.150,  0.489), (1.199, 0.523), (1.296, 0.640), 
                  (1.393,  0.812), (1.490,  0.981), (1.587,  1.189), (1.684, 1.386), (1.781, 1.572), 
                  (1.878, 1.766)])

obser = np.array([(0.212, -0.114), (0.199, 0.017), (0.259, 0.020), (0.199, 0.076), (0.297, 0.082), 
                  (0.735, 0.085), (0.641, 0.104), (0.791, 0.104), (0.681, 0.109), (0.606, 0.132), 
                  (0.262, 0.135), (0.813, 0.137), (0.334, 0.157), (0.565, 0.165), (0.647, 0.170), 
                  (0.876, 0.174), (0.746, 0.186), (0.509, 0.197), (0.398, 0.203), (0.693, 0.207), 
                  (0.829, 0.215), (0.299, 0.226), (0.585, 0.228), (0.549, 0.242), (0.430, 0.242), 
                  (0.637, 0.253), (0.511, 0.257), (0.918, 0.268), (0.813, 0.269), (0.746, 0.271), 
                  (0.336, 0.288), (0.449, 0.297), (0.398, 0.299), (0.783, 0.306), (0.578, 0.312), 
                  (0.871, 0.330), (0.515, 0.345), (0.468, 0.353), (0.818, 0.380), (0.936, 0.391), 
                  (0.889, 0.416), (0.876, 0.503), (1.027, 0.522), (1.040, 0.601), (0.965, 0.656), 
                  (1.130, 0.796), (1.224, 0.845), (1.261, 0.964), (1.378, 1.149)])


obv, oub =obser[:, 0], obser[:, 1]

fig, ax1 = plt.subplots(nrows=1, ncols=1, figsize=(5.31,6.79))
fig.subplots_adjust(left=0.14, bottom=0.08, right=0.95, top=0.97, wspace=0, hspace=0)

shift = (model.mean(axis=0) - obser.mean(axis=0))
sebv = shift[0]
seub = 0.72 * sebv + 0.025 * sebv**2

ax1.invert_yaxis()
ax1.set_xlabel("BmV")
ax1.set_ylabel("UmB")
ax1.set_ylim(2, -1)
ax1.set_xlim(-0.5, 2)
ax1.scatter(obv, oub, s=2, c="k")
gmdl, = ax1.plot(model[:, 0], model[:, 1], linewidth=1.1, c="b")

moveline = MoveGraphLine(ax1, gmdl, model, (sebv, seub))

plt.show()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM