2017-08-02 94 views
1

我正在尋找一種方法來改變垂直IntSlider的位置在matplotlib圖的右側。下面是代碼:如何將ipywidget滑塊的默認位置更改爲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)) 

這是我有:

enter image description here

這就是我想要的:

enter image description here

有可能是一個非常簡單的方式做到這一點,但我無法弄清楚自己。

我試圖把雙方figinteractive部件成VBox然後包裹VBoxIPython.display並沒有奏效。

在示例中找不到直接解決方案。

EDIT1:

ipywidgets提供一種Output()類捕獲的輸出區域和使用它的插件上下文內。

我會試着弄清楚如何使用它。

這是對象: https://github.com/jupyter-widgets/ipywidgets/blob/master/ipywidgets/widgets/widget_output.py

+0

你碰巧試過我的解決方案嗎? –

+1

是的,我認爲你是在正確的軌道上。如果你找到一種方法,通過從update_plot函數中展開圖形和座標軸的結構來實現它,我會接受你的答案。 在Output()對象上花費很多。我認爲這將解決我們的問題。 –

回答

1

您可以通過創建一個互動的小部件,然後加載childrenHBox解決這個問題。互動的子部件遵循這個約定; (widget_0,widget_1 ...,output),其中元組的最後一個成員是控件的輸出。您可以在聲明之前或之後定義HBox的佈局。 Read more on the layouts available here

以下解決方案有一些注意事項;圖形可能不會在最初出現時顯示出來,您可能必須在控件出現之前對其進行調整,其次使用魔術時控件可能導致更新時發生大量閃爍。除此之外,我認爲這應該像你想要的那樣工作;

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賈森灌漿的解決方案。

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])) 
+1

你部分解決了這個問題,但是在update_plot函數中包裝了matplotlib圖的結構導致了這種不好的刷新行爲,並且該圖在第一次更新滑塊時生成。可能有一種方法可以通過它內部的matplotlib捕獲輸出。 選中此項: https://github.com/jupyter-widgets/ipywidgets/blob/master/ipywidgets/widgets/widget_output.py –

+0

@BrunoRuasDePinho閃爍可能與您使用的瀏覽器或版本有關您正在使用的ipywidgets正如[本期]中所述(https://github.com/jupyter-widgets/ipywidgets/issues/1532)。使用'%matplotlib inline'代替''matplotlib notebook''可以看到一些改進,但是你使用了一些交互功能。所以IDK可能會像現在這樣好。我會繼續尋找,但至少讓我對局部soln :) upvote –

+1

肯定詹姆斯!謝謝!! –

2

我決定用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文檔:

在bqplot,情節的每一個屬性是一個互動的 部件。這允許用戶將任何繪圖與IPython 窗口小部件集成在一起,以創建一個複雜且功能豐富的GUI,只需幾行簡單的Python代碼即可完成。

我會繼續接受詹姆斯的答案,因爲它回答了原來的問題。