我想用鼠标在堆栈图中移动单个图形并立即更新图形。这些值不仅应该在图表中更改(图形),还应该更新带有值的列表,以便我可以将它们打印在文件中。
是否可以使用matplotlib在python中实现它,或者你会推荐别的东西吗?实现需要在python中。 Matplotlib被推荐给我,但是如果这个包不可能或者有更好的包,请发表评论。如果您有代码示例,请随时分享。
x轴表示时间(从今天到未来),y轴表示资源的数量。当一个值被削减时,不可能将图形移动到过去(左)!= 0.你可以将任何图形移动到未来(右边),没有任何东西被削减。 例如,我不能向左移动“O”,但我可以向左移动“R”和“Y”(只有一次)。
在示例中,我使用的列表只有6个条目,但您可以想象它们总是很长。
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 one right
R = [0, 1, 2, 1, 1, 1]
Y = [0, 0, 2, 1, 2, 1]
O = [5, 2, 1, 1, 1, 1]
我定义了一个图并添加了一个子图,现在我使用stackplot函数来绘制我的数据。
fig = plt.figure()
ax1 = fig.add_subplot(111)
stackPlots = ax1.stackplot(x-ax, R, Y, O)
感谢“ImportanceOfBeingErnest”!我添加了3个事件并将它们连接起来
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):
for stack_p in stackPlots:
contains, attrd = stack_p.contains(event)
if contains:
selected_stack = stack_p
break
if not contains:
return
# I can change the color, but how can I 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)
当我现在点击图表时,它会将其颜色更改为黑色。所以我知道我有正确的,但我想移动它。 “stackplot”方法返回“PolyCollection”列表。我想我应该重做整个情节,但我需要找出哪个“PolyCollection”对应哪个数组(R,Y,O)......
感谢您的帮助!
答案 0 :(得分:1)
我认为这个问题需要分为两个主要部分。由于移动堆栈图的一个堆栈不仅是图形移动,而且需要绘制具有更改数据的新堆栈图,因此(a)首先找到计算新数据的方法和( b)然后提供一种方法,用该新数据重绘该图。
我们需要一种方法将数组内的一行向左或向右移动,这样输出数组可能在执行移动的一侧有一列。这可以通过以下方式完成:
import numpy as np
class Moveable():
def __init__(self, x,y):
self.x = x
self.y = y
def move(self, row, by):
if by >0:
for i in range(by):
self.moveright(row)
self.sanitize()
else:
for i 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]
用法例如是
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 that 0 is not part of the x array any more,
# but that we have 6 as new column on the right side of matrix
现在我们可以使用上面的内容,一旦鼠标选择了一个堆栈并向左或向右移动一些数量,就用新的堆栈图更新轴。
import matplotlib.pyplot as 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
for 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:
by = 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()
结果可能如下所示
我在这里忽略了motion_notify_event,因为我们实际上只需要鼠标拖动的起点和终点来获取要更新的堆栈。