我想使用ipython notebook小部件为内联matplotlib图添加一定程度的交互性。
一般情况下,情节可能很重,我只想更新情节的特定元素。我知道小部件内置的限制功能有助于不会泛滥内核,但是当情节采取30秒时,我不想等待这么长时间来更新一行。
通过阅读example notebooks我能够创建一个基本示例,其中我将一个十字光标(由2个滑块驱动)添加到mpl轴。
问题是图形显示两次。这是代码(单元格1):
fig, ax = plt.subplots()
ax.plot([3,1,2,4,0,5,3,2,0,2,4])
......数字显示......,单元格2(编辑:感谢Thomas K的改进):
vline = ax.axvline(1)
hline = ax.axhline(0.5)
def set_cursor(x, y):
vline.set_xdata((x, x))
hline.set_ydata((y, y))
display(fig)
最后(单元格3):
interact(set_cursor, x=(1, 9, 0.01), y=(0, 5, 0.01))
再次显示小部件的数字。
所以问题是:
修改
根据this notebook,我发现了一个ipython配置旋钮,可以禁止数字显示
%config InlineBackend.close_figures = False
虽然示例笔记本有效,但我无法弄清楚如何单独使用此选项(没有链接示例中提供的上下文管理器类)来隐藏图形显示。
编辑2
我找到InlineBackend.close_figures
可配置的some documentation。
编辑3
由@shadanan回答引发,我想澄清一下,我的目的是将光标添加到现有图形,而不是在每个光标移动时从头开始重绘图形。合并单个细胞中的3个细胞:
fig, ax = plt.subplots()
ax.plot([3,1,2,4,0,5,3,2,0,2,4])
vline = ax.axvline(1)
hline = ax.axhline(0.5)
def set_cursor(x, y):
vline.set_xdata((x, x))
hline.set_ydata((y, y))
display(fig)
interact(set_cursor, x=(1, 9, 0.01), y=(0, 5, 0.01))
它“应该”有效,但事实并非如此。第一次执行单元格时,它显示了2个数字。小部件交互后,仅显示1个数字。这是一种“奇怪的行为”,需要像@shadanan回答中所示的解决方法。 ipython开发者可以对此发表评论吗?这是一个错误吗?
答案 0 :(得分:5)
解决方案结果非常简单。为避免显示第一个数字,我们只需在close()
来电之前添加interact
来电。
回想一下这个问题的例子,像这样的单元格会正确显示一个交互式图形(而不是两个):
fig, ax = plt.subplots()
ax.plot([3,1,2,4,0,5,3,2,0,2,4])
plt.close(fig)
vline = ax.axvline(1)
hline = ax.axhline(0.5)
def set_cursor(x, y):
vline.set_xdata((x, x))
hline.set_ydata((y, y))
display(fig)
interact(set_cursor, x=(1, 9, 0.01), y=(0, 5, 0.01))
更简洁的方法是定义函数add_cursor
(在单独的单元格或脚本中):
def add_cursor(fig, ax):
plt.close(fig)
vline = ax.axvline(1, color='k')
hline = ax.axhline(0.5, color='k')
def set_cursor(x, y):
vline.set_xdata((x, x))
hline.set_ydata((y, y))
display(fig)
interact(set_cursor, x=ax.get_xlim(), y=ax.get_ylim())
然后在我们想要添加交互式游标时调用它:
fig, ax = plt.subplots()
ax.plot([3,1,2,4,0,5,3,2,0,2,4])
add_cursor(fig, ax)
答案 1 :(得分:3)
您可以使用新的(ish)notebook
后端以非常直接的方式执行此操作
%matplotlib notebook
import matplotlib.pyplot as plt
from IPython.html.widgets import interactive
fig, ax = plt.subplots()
ax.plot(range(5))
vline = ax.axvline(1, color='k')
hline = ax.axhline(0.5, color='k')
def set_cursor(x, y):
vline.set_xdata((x, x))
hline.set_ydata((y, y))
ax.figure.canvas.draw_idle()
并在另一个单元格中:
interactive(set_cursor, x=ax.get_xlim(), y=ax.get_ylim())
每次移动光标时,这仍会重新绘制整个图形,因为notebook
目前不支持blitting(正在https://github.com/matplotlib/matplotlib/pull/4290上工作)
答案 2 :(得分:2)
我有一个hacky解决方法,只显示一个数字。问题似乎是代码中有两个点生成一个数字,实际上,我们只想要第二个,但是我们无法通过抑制第一个来逃避。解决方法是使用第一个用于第一次执行,第二个用于所有后续执行。这里有一些代码可以根据初始化标志在两者之间切换:
%matplotlib inline
import matplotlib.pyplot as plt
from IPython.html.widgets import interact, interactive, fixed
from IPython.html import widgets
from IPython.display import clear_output, display, HTML
class InteractiveCursor(object):
initialized = False
fig = None
ax = None
vline = None
hline = None
def initialize(self):
self.fig, self.ax = plt.subplots()
self.ax.plot([3,1,2,4,0,5,3,2,0,2,4])
self.vline = self.ax.axvline(1)
self.hline = self.ax.axhline(0.5)
def set_cursor(self, x, y):
if not self.initialized:
self.initialize()
self.vline.set_xdata((x, x))
self.hline.set_ydata((y, y))
if self.initialized:
display(self.fig)
self.initialized = True
ic = InteractiveCursor()
def set_cursor(x, y):
ic.set_cursor(x, y)
interact(set_cursor, x=(1, 9, 0.01), y=(0, 5, 0.01));
我的意见是,这应该被视为一个错误。我尝试使用面向对象的界面,它也有同样的问题。