【问题标题】:Possible to control a plotly diagram in Jupyter from markdown links?可以从降价链接控制 Jupyter 中的绘图图吗?
【发布时间】:2021-10-26 15:00:43
【问题描述】:

我想使用 Plotly,在 Jupyter 中绘制一个相当简单的线图,比如:

import plotly.graph_objs as go
from plotly.subplots import make_subplots

figSubs = go.FigureWidget(
    make_subplots(rows=2, cols=1, specs = [[{}], [{}]], vertical_spacing = 0.05)
)
figSubs.add_trace(
    go.Scatter(mode='lines+markers', x=[0, 1, 2, 3, 4], y=[0, 1000, 990, 980, 970], name='Test', marker={'color': 'red'}, xaxis="x1"),
    row=1, col=1
)
figSubs.update_layout(margin=go.layout.Margin(l=20,t=10,b=10,pad=4))

我找到了https://towardsdatascience.com/interactive-visualization-of-decision-trees-with-jupyter-widgets-ca15dd312084,它使用from ipywidgets import interactive 来获取交互式小部件,可以控制 Plotly 情节。

但是,我想要的是有 Markdown 链接,更改 Plotly 图。更具体地说,我想更改范围 - 所以如果我们继续 Plotly: How to set the range of the y axis?How to force Plot.ly Python to use a given yaxis range? ,我希望有如下链接:

  • [click here for yrange of 0-1000](???) 将执行 figSubs['layout']['yaxis1'].update(range=[0, 1000], autorange=False)
  • [click here for yrange of 950-1000](???) 将执行 figSubs['layout']['yaxis1'].update(range=[950, 1000], autorange=False)

在大部分 Plotly 设置代码都在 Python 中的 Jupyter Notebook 中,这样的事情是否可行?

【问题讨论】:

    标签: python jupyter-notebook plotly


    【解决方案1】:

    嗯,显然,这是可能的 - 但是男孩,要获得所有这些信息,以便获得一个可行的示例是 困难 ...

    首先,这些是我安装的版本:

    $ python3 --version
    Python 3.8.10
    $ pip3 list | grep 'jupyter \|nbextensions\|plotly'
    jupyter                           1.0.0
    jupyter-contrib-nbextensions      0.5.1
    jupyter-nbextensions-configurator 0.4.1
    plotly                            5.2.2
    

    还有一些关键点:

    请注意,在此示例中:

    • 有一个 Plotly/IPython 交互式下拉菜单,可独立更改绘图范围
    • 有一个 Python 函数可以调整范围,这里既可以从 Python 也可以从 JavaScript(链接)调用它

    话虽如此,这应该是一个工作示例;在第一个单元格中,使用生成图形的 Python 代码(因此,定义为代码单元格):

    
    import plotly.graph_objs as go
    import pandas as pd
    from plotly.subplots import make_subplots
    # import plotly.io as pio # https://plotly.com/python/getting-started-with-chart-studio/
    from IPython.display import display, HTML
    
    df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/volcano.csv")
    
    figSubs = go.FigureWidget(
        make_subplots(rows=2, cols=1, specs = [[{}], [{}]], vertical_spacing = 0.05)
    )
    figSubs.add_trace(
        go.Scatter(mode='lines+markers', x=df["V1"], y=df["V55"], name='Test1', marker={'color': 'red'}, xaxis="x1"),
        row=1, col=1
    )
    figSubs.add_trace(
        go.Scatter(mode='lines+markers', x=[0, 1, 2, 3, 4], y=[0, 990, 980, 970, 960], name='Test21', marker={'color': 'blue'}, xaxis="x1"),
        row=2, col=1
    )
    figSubs.add_trace(
        go.Scatter(mode='lines+markers', x=[0, 1, 2, 3, 4], y=[0, 980, 970, 960, 950], name='Test22', marker={'color': 'violet'}, xaxis="x1"),
        row=2, col=1
    )
    figSubs.update_layout(margin=go.layout.Margin(l=20,t=10,b=10,pad=4))
    figSubs.update_yaxes(zeroline=True,showline=True,zerolinewidth=1,zerolinecolor="#000", row=1, col=1)
    figSubs.update_yaxes(zeroline=True,showline=True,zerolinewidth=1,zerolinecolor="#000", row=2, col=1)
    
    # Add dropdown
    figSubs.update_layout(
        updatemenus=[
            dict(
                buttons=list([
                    dict(
                        args=[{"yaxis.range": [0, 1000], "yaxis.autorange": False, "row": 1, "col": 1}],
                        label="[0, 1000]",
                        method="relayout"
                    ),
                    dict(
                        args=[{"yaxis.range": [100, 200], "yaxis.autorange": False}],
                        label="[100, 200]",
                        method="relayout"
                    )
                ]),
                direction="down",
                pad={"r": 10, "t": 10},
                showactive=True,
                x=0.1,
                xanchor="left",
                y=1.12,
                yanchor="top"
            ),
        ]
    )
    
    # the Python function to adjust the Y range of the first plot - which is also called from JavaScript
    def PsetMyYRange(ymin, ymax, dodraw=True):
        figSubs['layout']['yaxis'].update(range=[ymin, ymax], autorange=False)
        #figSubs.update_yaxes(range=[ymin, ymax]) # changes both!
        #figSubs.update_layout(margin=go.layout.Margin(l=200,t=100,b=100,pad=40))
        #figSubs.show() # do NOT call this, else cannot manupulate the plot via JavaScript calls of this function later on!
        if dodraw:
            display(figSubs) #MUST have this to update the plot from JavaScript->Python; note with Plotly in a Jupyter extension, there is no `Plotly` javascript object accessible on the page! 
        return "{}; {}; {}".format(figSubs, ymin, ymax) # just for the console.log printout
    
    PsetMyYRange(110,120,dodraw=False) # call once to make sure it also works from here; but don't "draw", else we get two plots
    
    #figSubs.show()    # NOTE: .show() at end, will prevent the PsetMyYRange being able to redraw!
    #pio.show(figSubs) # NOTE: also pio.show() at end, will prevent the PsetMyYRange being able to redraw!
    display(figSubs)   # ... display() works fine however
    

    第二个单元格,本应是 OP 中所需的“Markdown links”单元格,再次必须是代码单元格,使用 %%html 魔术命令:

    %%html
    <script type='text/javascript'>
    window.executePython = function(python) {
        return new Promise((resolve, reject) => {
            var callbacks = {
                iopub: {
                    output: (data) => resolve(data.content.text.trim())
                }
            };
            Jupyter.notebook.kernel.execute(`print(${python})`, callbacks);    
        });
    }
    
    function setMyYRange(ymin, ymax){
      // NONE of the below quite works - we must call via Promise:
      //objstring = IPython.notebook.kernel.execute("global figSubs; print(figSubs)");
      //prevstring = IPython.notebook.kernel.execute("print(Jupyter.notebook.get_prev_cell())");
      //runstring = "global figSubs; figSubs['layout']['yaxis'].update(range=["+ymin+", "+ymax+"], autorange=False)";
      //console.log("setMyYRange " + ymin + " " + ymax + " ... " + objstring + " ... " + prevstring + " ... " + runstring);
      //IPython.notebook.kernel.execute(runstring);
    
      // the only thing needed for the code to work:
      window.executePython("PsetMyYRange("+ymin+","+ymax+")")
        .then(result => console.log(result));
    }
    </script>
    
    <a onclick="javascript:setMyYRange(0,1000);" href="javascript:void(0);">here (0,1000)</a>
    <a onclick="javascript:setMyYRange(100,200);" href="javascript:void(0);">here (100,200)</a>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-23
      • 2021-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      相关资源
      最近更新 更多