matplotlib - How to move a graph in a stack plot with the mouse in python -
problem
i want move single graph in stack plot mouse , update plot instantly. values shouldn't change in plot (graphical), list values should updated, can print them in file.
question
is possible implement in python matplotlib or recommend me else? implementation need in python. matplotlib recommended me, if it's not possible package or there better 1 please leave comment. when have code example feel free share it.
example
the x-axis represent time (from today future) , y-axis anmount of resources. isn't possible move graph past (left) when value cut of != 0. can move graph future (right), nothing get's cut. example can't move "o" left, can move "r" , "y" (only 1 time) left.
in example used lists 6 entries, imagine long enought.
values:
x-ax = [0, 1, 2, 3, 4, 5] y-ax = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] r = [0, 1, 2, 1, 1, 1] y = [0, 2, 1, 2, 1, 0] o = [5, 2, 1, 1, 1, 1] after moving y 1 right r = [0, 1, 2, 1, 1, 1] y = [0, 0, 2, 1, 2, 1] o = [5, 2, 1, 1, 1, 1]
what have
i define figure , add subplot, use stackplot function plot data.
fig = plt.figure() ax1 = fig.add_subplot(111) stackplots = ax1.stackplot(x-ax, r, y, o)
thanks "importanceofbeingernest"! added 3 events , connected them
cid_press = fig.canvas.mpl_connect('button_press_event', on_press) cid_release = fig.canvas.mpl_connect('button_release_event', on_release) cid_move = fig.canvas.mpl_connect('motion_notify_event', motion_notify) def on_press(event): if(event.button == 1): stack_p in stackplots: contains, attrd = stack_p.contains(event) if contains: selected_stack = stack_p break if not contains: return # can change color, how can move it? selected_stack .set_facecolors('black') plt.draw() print("clicked on", attrd, selected_stack) #print('you pressed', event.button, event.xdata, event.ydata) def on_release(event): if (event.button == 1): print('you released', event.button, event.xdata, event.ydata) def motion_notify(event): if (event.button == 1): return print('you moved', event.button, event.xdata, event.ydata)
when click on graph changes it's color black. know i've got right one, want move it. "stackplot" method returns list of "polycollection". think should redo whole plot, need find out "polycollection" correspond array (r, y, o)...
thanks help!
i think problem needs separated 2 main parts. since moving 1 stack of stackplot not graphical movement, requires draw new stackplot changed data, 1 (a) first find way calculate new data , (b) provide way plot redone new data.
(a) move row along columns in data
we need way move 1 row inside array left or right, such output array may have 1 column more on side towards movement performed. done in following way:
import numpy np class moveable(): def __init__(self, x,y): self.x = x self.y = y def move(self, row, by): if >0: in range(by): self.moveright(row) self.sanitize() else: in range(-int(by)): self.moveleft(row) self.sanitize() def moveright(self,row): x = np.zeros(len(self.x)+1) x[:len(self.x)] = self.x[:] x[-1] = self.x[-1]+1 y = np.zeros((self.y.shape[0], len(self.x)+1)) y[:, :len(self.x)] = self.y[:,:] y[row,0] = 0 y[row,1:] = self.y[row,:] self.x=x self.y=y def moveleft(self,row): x = np.zeros(len(self.x)+1) x[1:len(self.x)+1] = self.x[:] x[0] = self.x[0]-1 y = np.zeros((self.y.shape[0], len(self.x)+1)) y[:, 1:len(self.x)+1] = self.y[:,:] y[row,-1] = 0 y[row,:-1] = self.y[row,:] self.x=x self.y=y def sanitize(self): if (self.y[:,0] == 0.).all(): self.x = self.x[1:] self.y = self.y[:,1:] if (self.y[:,-1] == 0.).all(): self.x = self.x[:-1] self.y = self.y[:,:-1]
the usage e.g. be
x = [0, 1, 2, 3, 4, 5] r = [0, 1, 2, 1, 1, 1] y = [0, 2, 1, 2, 1, 0] o = [5, 2, 1, 1, 1, 1] m= moveable(np.array(x), np.array([r, y, o])) m.move(row=2, by=1) print(m.x) # prints [ 1. 2. 3. 4. 5. 6.] print(m.y) # [[ 1. 2. 1. 1. 1. 0.] # [ 2. 1. 2. 1. 0. 0.] # [ 5. 2. 1. 1. 1. 1.]] # note 0 not part of x array more, # have 6 new column on right side of matrix
(b) new stackplot when mouse dragged
now can use above update axes new stackplot once mouse selects stack , moved amount left or right.
import matplotlib.pyplot plt class stackmover(): def __init__(self, ax, x,y, **kw): self.m = moveable(np.array(x), np.array(y)) self.xp = none self.ax = ax self.kw = kw self.stackplot = self.ax.stackplot(self.m.x, self.m.y, **self.kw) self.c1 = self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press) self.c2 = self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release) def on_press(self,event): self.xp = none if(event.button != 1): return self.row = 0 stack_p in self.stackplot: contains, attrd = stack_p.contains(event) if contains: break self.row += 1 if not contains: return self.xp = event.xdata def on_release(self,event): if(event.button != 1): return if self.xp != none: = int(event.xdata - self.xp) self.m.move(self.row, by) self.ax.clear() self.stackplot = self.ax.stackplot(self.m.x, self.m.y, **self.kw) self.ax.figure.canvas.draw_idle() self.xp = none x = [0, 1, 2, 3, 4, 5] r = [0, 1, 2, 1, 1, 1] y = [0, 2, 1, 2, 1, 0] o = [5, 2, 1, 1, 1, 1] fig, ax = plt.subplots() stackplots = stackmover(ax, x, [r, y, o]) plt.show()
the result may this
i have neglected motion_notify_event here, need start , end point of mouse drag obtain stack update.
Comments
Post a Comment