【问题标题】:Jupyter notebook with detachable, floating and draggable widget?带有可拆卸、浮动和可拖动小部件的 Jupyter 笔记本?
【发布时间】:2019-09-05 09:19:47
【问题描述】:

在 Windows 10 上通过 Anaconda (Navigator v. 1.9.7) 使用 Jupyter Notebook (v. 6.0.0)。考虑这样一种情况,我在顶部有一个 ipywidgets 滑块,然后中间有一个完整的文本,然后响应滑块的底部图形。这是 Firefox 中此类网页的图片,已缩小以便可以完整显示:

显然,这很难使用 - 在这种情况下,我更喜欢“分离”包含滑块的小部件,并将其向下拖动到图形所在的位置,然后操纵滑块;在那种情况下,我也不必使用缩小的网页渲染。然后在完成操作后,我想单击一个按钮,并将小部件重新附加到它所在的位置。

但是,我不确定,我如何在 Jupyter notebook 中使用ipywidgets 实现这个?我发现的唯一接近此的东西是[Question] Maintain position of floating widget when browser tab is closed · Issue #2520 · jupyter-widgets/ipywidgets,这似乎意味着需要对 JavaScript 进行干预。

这里是重新创建屏幕截图的代码(在包含滑块的小部件中已经有一个“分离”按钮,除了它除了更​​改其文本之外什么都不做):

单元格 1 - Python 3:

import plotly.graph_objs as go
import numpy as np
from ipywidgets import widgets, Layout
from IPython.display import display
from IPython.display import Markdown as md

inSlider = widgets.FloatSlider(
    value=1.0,
    min=0.0,
    max=10.0,
    step=0.01,
    description='In:',
    continuous_update=True
)
output2 = widgets.Output()

def on_detButton_click(b):
    if b.description == "Detach": b.description = "Attach"
    else: b.description = "Detach"

detButton = widgets.Button(description="Detach")
detButton.on_click(on_detButton_click)

myctlwidget = widgets.VBox([widgets.HBox([inSlider, detButton]), output2])
display(myctlwidget)

单元格 2 是 Markdown - 粘贴在本文末尾;

单元 3 - Python 3:

fig = go.FigureWidget( layout=go.Layout() )
fig.add_trace(go.Scatter(x=[0,10], y=[0,10],
                    mode='lines',
                    name='Test plot'))
# set range to prevent autoranging when slider sets a new value
fig.update_yaxes(range=[0, 11])

def update_graph(change):
    with fig.batch_update():
        curval = inSlider.value
        fig.data[0].y=[0, curval]

inSlider.observe(update_graph, names="value")

widgets.VBox([fig])

单元格 2 - Markdown(注意每行末尾的两个空格,以引入换行符)

Test paragraph 0  
Some text 0, 0.... some text 0

Test paragraph 1  
Some text 1, 1.... some text 1

Test paragraph 2  
Some text 2, 2.... some text 2

Test paragraph 3  
Some text 3, 3.... some text 3

Test paragraph 4  
Some text 4, 4.... some text 4

Test paragraph 5  
Some text 5, 5.... some text 5

Test paragraph 6  
Some text 6, 6.... some text 6

Test paragraph 7  
Some text 7, 7.... some text 7

Test paragraph 8  
Some text 8, 8.... some text 8

Test paragraph 9  
Some text 9, 9.... some text 9

Test paragraph 10  
Some text 10, 10.... some text 10

Test paragraph 11  
Some text 11, 11.... some text 11

Test paragraph 12  
Some text 12, 12.... some text 12

Test paragraph 13  
Some text 13, 13.... some text 13

Test paragraph 14  
Some text 14, 14.... some text 14

Test paragraph 15  
Some text 15, 15.... some text 15

Test paragraph 16  
Some text 16, 16.... some text 16

Test paragraph 17  
Some text 17, 17.... some text 17

Test paragraph 18  
Some text 18, 18.... some text 18

Test paragraph 19  
Some text 19, 19.... some text 19

Test paragraph 20  
Some text 20, 20.... some text 20

Test paragraph 21  
Some text 21, 21.... some text 21

Test paragraph 22  
Some text 22, 22.... some text 22

Test paragraph 23  
Some text 23, 23.... some text 23

Test paragraph 24  
Some text 24, 24.... some text 24

Test paragraph 25  
Some text 25, 25.... some text 25

Test paragraph 26  
Some text 26, 26.... some text 26

Test paragraph 27  
Some text 27, 27.... some text 27

Test paragraph 28  
Some text 28, 28.... some text 28

Test paragraph 29  
Some text 29, 29.... some text 29

Test paragraph 30  
Some text 30, 30.... some text 30

【问题讨论】:

    标签: jupyter-notebook ipywidgets


    【解决方案1】:

    好的,我想我已经成功了 - 谢天谢地,这个版本的 Jupyter 笔记本会自动加载 jquery-ui,所以我可以使用 .draggable() ...

    注意:

    • 将整个背景 div 设置为可拖动,这意味着即使您只想移动滑块头部,整个元素也会被拖动 - 因此必须改用拖动手柄(以允许正确使用滑块本身)李>
    • 分离/可拖动元素通常会覆盖其他元素(根据需要),除了在具有绘图图的单元格中 - 一旦可拖动元素在此处释放(无论它是否发生在绘图上图本身,或可能存在于同一单元格输出中的其他 ipywidgets),该元素不能再被单击以拖动! (但是,如果手柄最终位于左右两个细边框中,则可以单击/拖动它)

    如果有人想出解决(第二个)问题的方法,我很乐意听到。

    与此同时,解决方法是在包含绘图图的单元格输出下方放置一个普通的 Markdown 单元格,然后该单元格将能够正确“托管”拖动的滑块元素。这是在这种情况下修复的样子(小“(h)”是句柄):

    这是我的解决方法:

    单元格 1 - Python 3:

    import plotly.graph_objs as go
    import numpy as np
    from ipywidgets import widgets, Layout
    from IPython.display import display, Javascript
    from IPython.display import Markdown as md
    
    inSlider = widgets.FloatSlider(
        value=1.0,
        min=0.0,
        max=10.0,
        step=0.01,
        description='In:',
        continuous_update=True
    )
    output2 = widgets.Output()
    
    def on_detButton_click(b):
        if b.description == "Detach": 
            b.description = "Attach"
            # must wrap in display() - Javascript() call on its own does not effectuate!
            # https://stackoverflow.com/questions/15193640/jquery-ui-draggable-reset-to-original-position
            # NOTE: in spite of zIndex manipulation: do NOT place dragged widget over textarea (it will lose focus),
            # also, it will be under a plot.ly diagram regardless!
            display(Javascript("""
            var $dragwidget = $("div.myctlwidget").parent();
            $dragwidget.data({
                'originalLeft': $dragwidget.css('left'),
                'originalTop': $dragwidget.css('top'),
                'originalZindex': $dragwidget.css('z-index')
            });
            $dragwidget.css({ 'z-index': 5000});
            $dragwidget.draggable({ disabled: false, handle: "div.myctlhandle" });
            """))
        else:
            b.description = "Detach"
            display(Javascript("""
            var $dragwidget = $("div.myctlwidget").parent();
            $dragwidget.draggable({ disabled: true });
            $dragwidget.css({
                'left': $dragwidget.data('originalLeft'),
                'top': $dragwidget.data('originalTop'),
                'z-index': $dragwidget.data('originalZindex'),
            });
            """))
    
    detButton = widgets.Button(description="Detach")
    detButton.on_click(on_detButton_click)
    
    # NB: Button still is visually clickable, even when disabled :(
    handleButton = widgets.Label("(h)", _dom_classes = ['myctlhandle'])
    
    myctlwidget = widgets.VBox([widgets.HBox([inSlider, detButton, handleButton])], _dom_classes = ['myctlwidget'])
    display(myctlwidget)
    #myctlwidget._dom_classes = ['myctlwidget'] # nowork; only added as argument to VBox _dom_classes works!
    #print(myctlwidget._dom_classes)
    

    单元 3 - Python 3:

    fig = go.FigureWidget( layout=go.Layout() )
    fig.add_trace(go.Scatter(x=[0,10], y=[0,10],
                        mode='lines',
                        name='Test plot'))
    # set range to prevent autoranging
    fig.update_yaxes(range=[0, 11])
    
    def update_graph(change):
        with fig.batch_update():
            curval = inSlider.value
            fig.data[0].y=[0, curval]
    
    inSlider.observe(update_graph, names="value")
    
    #spacer = widgets.VBox([widgets.Text(":                     :"), widgets.Label(":                     :")]) # nope
    
    display(md("Markdown here does NOT work as spacer!\n\n... does NOT work as spacer!"))
    display(widgets.VBox([fig]))
    

    【讨论】:

    猜你喜欢
    • 2015-07-24
    • 1970-01-01
    • 1970-01-01
    • 2022-12-09
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    • 2017-10-01
    • 1970-01-01
    相关资源
    最近更新 更多