如何将 ipywidget 滑块的默认位置更改为 matplotlib 图的一侧?
How to change the default position of a ipywidget slider to the side of a matplotlib figure?
我正在寻找一种方法来将垂直 IntSlider 的位置更改为 matplotlib 图的右侧。这是代码:
from ipywidgets import interact, fixed, IntSlider
import numpy as np
from matplotlib import pyplot as plt
%matplotlib notebook
fig = plt.figure(figsize=(8,4))
xs = np.random.random_integers(0, 5000, 50)
ys = np.random.random_integers(0, 5000, 50)
ax = fig.add_subplot(111)
scat, = ax.plot(xs, ys, 'kx', markersize=1)
ax.grid(which='both', color='.25', lw=.1)
ax.set_aspect('equal'), ax.set_title('Rotate')
def rotate(theta, xs, ys):
new_xs = xs * np.cos(np.deg2rad(theta)) - ys * np.sin(np.deg2rad(theta))
new_xs -= new_xs.min()
new_ys = xs * np.sin(np.deg2rad(theta)) + ys * np.cos(np.deg2rad(theta))
new_ys -= new_ys.min()
return new_xs, new_ys
def update_plot(theta, xs, ys):
new_xs, new_ys = rotate(theta, xs, ys)
scat.set_xdata(new_xs), scat.set_ydata(new_ys)
ax.set_xlim(new_xs.min() - 500, new_xs.max() + 500)
ax.set_ylim(new_ys.min() - 500, new_ys.max() + 500)
w = interact(update_plot,
theta=IntSlider(min=-180, max=180, step=5,value=0, orientation='vertical'),
xs=fixed(xs),
ys=fixed(ys))
这是我的:
这就是我想要的:
可能有一个非常简单的方法可以做到这一点,但我自己想不出来。
我试图将 fig
和 interactive
小部件都放入 VBox
然后用 IPython.display
包装 VBox
但它没有工作。
无法在示例中找到对此的直接解决方案。
编辑 1:
ipywidgets 提供了一个 Output()
class 来捕获输出区域并在小部件上下文中使用它。
我会想办法使用它的。
这是对象:
https://github.com/jupyter-widgets/ipywidgets/blob/master/ipywidgets/widgets/widget_output.py
您可以通过创建交互式小部件然后将 children
加载到 HBox
来解决此问题。交互的子部件遵循这个约定; (widget_0, widget_1 ..., output) 其中元组的最后一个成员是控件小部件的输出。您可以在声明之前或之后定义 HBox 的布局。 Read more on the layouts available here.
以下解决方案有几个注意事项;该图最初可能不会显示,您可能必须在它出现之前调整控件,其次,当使用 %matplotlib notebook
魔法时,控件可能会导致更新时出现大量闪烁。除此之外,我认为这应该可以像您想要的那样工作;
from IPython.display import display
from ipywidgets import interactive, fixed, IntSlider, HBox, Layout
import numpy as np
import matplotlib.pylab as plt
%matplotlib notebook
def rotate(theta, xs, ys):
new_xs = xs * np.cos(np.deg2rad(theta)) - ys * np.sin(np.deg2rad(theta))
new_xs -= new_xs.min()
new_ys = xs * np.sin(np.deg2rad(theta)) + ys * np.cos(np.deg2rad(theta))
new_ys -= new_ys.min()
return new_xs, new_ys
def update_plot(theta, xs, ys):
fig = plt.figure(figsize=(8,4))
ax = fig.add_subplot(111)
scat, = ax.plot(xs, ys, 'kx', markersize=1)
ax.grid(which='both', color='.25', lw=.1)
ax.set_aspect('equal'), ax.set_title('Rotate')
new_xs, new_ys = rotate(theta, xs, ys)
scat.set_xdata(new_xs), scat.set_ydata(new_ys)
ax.set_xlim(new_xs.min() - 500, new_xs.max() + 500)
ax.set_ylim(new_ys.min() - 500, new_ys.max() + 500)
xs = np.random.randint(0, 5000, 50)
ys = np.random.randint(0, 5000, 50)
w = interactive(update_plot,
theta=IntSlider(min=-180, max=180, step=5, value=0,orientation='vertical'),
xs=fixed(xs),
ys=fixed(ys))
# Define the layout here.
box_layout = Layout(display='flex', flex_flow='row', justify_content='space-between', align_items='center')
display(HBox([w.children[1],w.children[0]], layout=box_layout))
更新:
这是来自 ipywidgets gitter 的 Jason Grout 的解决方案。
from IPython.display import display, clear_output
from ipywidgets import interact, fixed, IntSlider, HBox, Layout, Output, VBox
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
def rotate(theta, xs, ys):
new_xs = xs * np.cos(np.deg2rad(theta)) - ys * np.sin(np.deg2rad(theta))
new_xs -= new_xs.min()
new_ys = xs * np.sin(np.deg2rad(theta)) + ys * np.cos(np.deg2rad(theta))
new_ys -= new_ys.min()
return new_xs, new_ys
out = Output(layout={'width': '300px', 'height': '300px'})
def update_plot(change):
theta = change['new'] # new slider value
with out:
clear_output(wait=True)
fig = plt.figure(figsize=(4,4))
ax = fig.add_subplot(111)
scat, = ax.plot(xs, ys, 'kx', markersize=1)
ax.grid(which='both', color='.25', lw=.1)
ax.set_aspect('equal'), ax.set_title('Rotate')
new_xs, new_ys = rotate(theta, xs, ys)
scat.set_xdata(new_xs), scat.set_ydata(new_ys)
ax.set_xlim(new_xs.min() - 500, new_xs.max() + 500)
ax.set_ylim(new_ys.min() - 500, new_ys.max() + 500)
plt.show()
xs = np.random.randint(0, 5000, 50)
ys = np.random.randint(0, 5000, 50)
slider = IntSlider(min=-180, max=180, step=5, value=0, orientation='vertical')
slider.observe(update_plot, 'value')
update_plot({'new': slider.value})
display(HBox([out, slider]))
我决定使用 bqplot 而不是 matplotlib 来尝试这个例子,结果证明它更简单。
import numpy as np
from bqplot import pyplot as plt
from IPython.display import display
from ipywidgets import interactive, fixed, IntSlider, HBox, Layout
plt.figure(min_aspect_ratio=1, max_aspect_ratio=1)
xs = np.random.randint(0, 5000 + 1, 100)
ys = np.random.randint(0, 5000 + 1, 100)
scat = plt.scatter(xs, ys)
def rotate(theta, xs, ys):
new_xs = xs * np.cos(np.deg2rad(theta)) - ys * np.sin(np.deg2rad(theta))
new_xs -= new_xs.min()
new_ys = xs * np.sin(np.deg2rad(theta)) + ys * np.cos(np.deg2rad(theta))
new_ys -= new_ys.min()
return new_xs, new_ys
def update_plot(theta, xs, ys):
new_xs, new_ys = rotate(theta, xs, ys)
scat.x, scat.y = new_xs, new_ys
w = interactive(update_plot,
theta=IntSlider(min=-180, max=180, step=5,value=0, orientation='vertical'),
xs=fixed(xs),
ys=fixed(ys))
box_layout = Layout(display='flex', flex_flow='row', justify_content='center', align_items='center')
display(HBox([plt.current_figure(), w], layout=box_layout))
bqplot
旨在成为一个交互式小部件。通过这种方式,它可以简单地添加到输出中,而不必将其包装到 update_plot
函数中。
来自 bqplot
文档:
In bqplot, every single attribute of the plot is an interactive
widget. This allows the user to integrate any plot with IPython
widgets to create a complex and feature rich GUI from just a few
simple lines of Python code.
我会保留已接受的 James 答案,因为它回答了原始问题。
我正在寻找一种方法来将垂直 IntSlider 的位置更改为 matplotlib 图的右侧。这是代码:
from ipywidgets import interact, fixed, IntSlider
import numpy as np
from matplotlib import pyplot as plt
%matplotlib notebook
fig = plt.figure(figsize=(8,4))
xs = np.random.random_integers(0, 5000, 50)
ys = np.random.random_integers(0, 5000, 50)
ax = fig.add_subplot(111)
scat, = ax.plot(xs, ys, 'kx', markersize=1)
ax.grid(which='both', color='.25', lw=.1)
ax.set_aspect('equal'), ax.set_title('Rotate')
def rotate(theta, xs, ys):
new_xs = xs * np.cos(np.deg2rad(theta)) - ys * np.sin(np.deg2rad(theta))
new_xs -= new_xs.min()
new_ys = xs * np.sin(np.deg2rad(theta)) + ys * np.cos(np.deg2rad(theta))
new_ys -= new_ys.min()
return new_xs, new_ys
def update_plot(theta, xs, ys):
new_xs, new_ys = rotate(theta, xs, ys)
scat.set_xdata(new_xs), scat.set_ydata(new_ys)
ax.set_xlim(new_xs.min() - 500, new_xs.max() + 500)
ax.set_ylim(new_ys.min() - 500, new_ys.max() + 500)
w = interact(update_plot,
theta=IntSlider(min=-180, max=180, step=5,value=0, orientation='vertical'),
xs=fixed(xs),
ys=fixed(ys))
这是我的:
这就是我想要的:
可能有一个非常简单的方法可以做到这一点,但我自己想不出来。
我试图将 fig
和 interactive
小部件都放入 VBox
然后用 IPython.display
包装 VBox
但它没有工作。
无法在示例中找到对此的直接解决方案。
编辑 1:
ipywidgets 提供了一个 Output()
class 来捕获输出区域并在小部件上下文中使用它。
我会想办法使用它的。
这是对象: https://github.com/jupyter-widgets/ipywidgets/blob/master/ipywidgets/widgets/widget_output.py
您可以通过创建交互式小部件然后将 children
加载到 HBox
来解决此问题。交互的子部件遵循这个约定; (widget_0, widget_1 ..., output) 其中元组的最后一个成员是控件小部件的输出。您可以在声明之前或之后定义 HBox 的布局。 Read more on the layouts available here.
以下解决方案有几个注意事项;该图最初可能不会显示,您可能必须在它出现之前调整控件,其次,当使用 %matplotlib notebook
魔法时,控件可能会导致更新时出现大量闪烁。除此之外,我认为这应该可以像您想要的那样工作;
from IPython.display import display
from ipywidgets import interactive, fixed, IntSlider, HBox, Layout
import numpy as np
import matplotlib.pylab as plt
%matplotlib notebook
def rotate(theta, xs, ys):
new_xs = xs * np.cos(np.deg2rad(theta)) - ys * np.sin(np.deg2rad(theta))
new_xs -= new_xs.min()
new_ys = xs * np.sin(np.deg2rad(theta)) + ys * np.cos(np.deg2rad(theta))
new_ys -= new_ys.min()
return new_xs, new_ys
def update_plot(theta, xs, ys):
fig = plt.figure(figsize=(8,4))
ax = fig.add_subplot(111)
scat, = ax.plot(xs, ys, 'kx', markersize=1)
ax.grid(which='both', color='.25', lw=.1)
ax.set_aspect('equal'), ax.set_title('Rotate')
new_xs, new_ys = rotate(theta, xs, ys)
scat.set_xdata(new_xs), scat.set_ydata(new_ys)
ax.set_xlim(new_xs.min() - 500, new_xs.max() + 500)
ax.set_ylim(new_ys.min() - 500, new_ys.max() + 500)
xs = np.random.randint(0, 5000, 50)
ys = np.random.randint(0, 5000, 50)
w = interactive(update_plot,
theta=IntSlider(min=-180, max=180, step=5, value=0,orientation='vertical'),
xs=fixed(xs),
ys=fixed(ys))
# Define the layout here.
box_layout = Layout(display='flex', flex_flow='row', justify_content='space-between', align_items='center')
display(HBox([w.children[1],w.children[0]], layout=box_layout))
更新:
这是来自 ipywidgets gitter 的 Jason Grout 的解决方案。
from IPython.display import display, clear_output
from ipywidgets import interact, fixed, IntSlider, HBox, Layout, Output, VBox
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
def rotate(theta, xs, ys):
new_xs = xs * np.cos(np.deg2rad(theta)) - ys * np.sin(np.deg2rad(theta))
new_xs -= new_xs.min()
new_ys = xs * np.sin(np.deg2rad(theta)) + ys * np.cos(np.deg2rad(theta))
new_ys -= new_ys.min()
return new_xs, new_ys
out = Output(layout={'width': '300px', 'height': '300px'})
def update_plot(change):
theta = change['new'] # new slider value
with out:
clear_output(wait=True)
fig = plt.figure(figsize=(4,4))
ax = fig.add_subplot(111)
scat, = ax.plot(xs, ys, 'kx', markersize=1)
ax.grid(which='both', color='.25', lw=.1)
ax.set_aspect('equal'), ax.set_title('Rotate')
new_xs, new_ys = rotate(theta, xs, ys)
scat.set_xdata(new_xs), scat.set_ydata(new_ys)
ax.set_xlim(new_xs.min() - 500, new_xs.max() + 500)
ax.set_ylim(new_ys.min() - 500, new_ys.max() + 500)
plt.show()
xs = np.random.randint(0, 5000, 50)
ys = np.random.randint(0, 5000, 50)
slider = IntSlider(min=-180, max=180, step=5, value=0, orientation='vertical')
slider.observe(update_plot, 'value')
update_plot({'new': slider.value})
display(HBox([out, slider]))
我决定使用 bqplot 而不是 matplotlib 来尝试这个例子,结果证明它更简单。
import numpy as np
from bqplot import pyplot as plt
from IPython.display import display
from ipywidgets import interactive, fixed, IntSlider, HBox, Layout
plt.figure(min_aspect_ratio=1, max_aspect_ratio=1)
xs = np.random.randint(0, 5000 + 1, 100)
ys = np.random.randint(0, 5000 + 1, 100)
scat = plt.scatter(xs, ys)
def rotate(theta, xs, ys):
new_xs = xs * np.cos(np.deg2rad(theta)) - ys * np.sin(np.deg2rad(theta))
new_xs -= new_xs.min()
new_ys = xs * np.sin(np.deg2rad(theta)) + ys * np.cos(np.deg2rad(theta))
new_ys -= new_ys.min()
return new_xs, new_ys
def update_plot(theta, xs, ys):
new_xs, new_ys = rotate(theta, xs, ys)
scat.x, scat.y = new_xs, new_ys
w = interactive(update_plot,
theta=IntSlider(min=-180, max=180, step=5,value=0, orientation='vertical'),
xs=fixed(xs),
ys=fixed(ys))
box_layout = Layout(display='flex', flex_flow='row', justify_content='center', align_items='center')
display(HBox([plt.current_figure(), w], layout=box_layout))
bqplot
旨在成为一个交互式小部件。通过这种方式,它可以简单地添加到输出中,而不必将其包装到 update_plot
函数中。
来自 bqplot
文档:
In bqplot, every single attribute of the plot is an interactive widget. This allows the user to integrate any plot with IPython widgets to create a complex and feature rich GUI from just a few simple lines of Python code.
我会保留已接受的 James 答案,因为它回答了原始问题。