【问题标题】:how can I export this interactive plot to view in a browser without jupyter?如何在没有 jupyter 的情况下导出此交互式绘图以在浏览器中查看?
【发布时间】:2020-11-04 13:12:38
【问题描述】:

我在 python 中有这个交互式绘图:

import ipywidgets as widgets
import plotly.graph_objects as go 
from numpy import linspace


def leaf_plot(sense, spec):
    fig = go.Figure()

    x = linspace(0,1,101)
    x[0] += 1e-16
    x[-1] -= 1e-16

    positive =  sense*x/(sense*x + (1-spec)*(1-x)) 
                                                    #probability a person is infected, given a positive test result, 
                                                    #P(p|pr) = P(pr|p)*P(p)/P(pr)
                                                    #        = P(pr|p)*P(p)/(P(pr|p)*P(p) + P(pr|n)*P(n))
                                                    #        =   sense*P(p)/(  sense*P(p) +(1-spec)*P(n))
    negative =  1-spec*(1-x)/((1-sense)*x + spec*(1-x))

    fig.add_trace(
        go.Scatter(x=x, y  = positive, name="Positive",marker=dict( color='red'))
    )

    fig.add_trace(
        go.Scatter(x=x, y  = negative, 
                   name="Negative", 
                   mode = 'lines+markers',
                   marker=dict( color='green'))
    )
 
    fig.update_xaxes(title_text = "Base Rate")
    fig.update_yaxes(title_text = "Post-test Probability")
    fig.show()

sense_ = widgets.FloatSlider(
    value=0.5,
    min=0,
    max=1.0,
    step=0.01,
    description='Sensitivity:',
    disabled=False,
    continuous_update=False,
    orientation='horizontal',
    readout=True,
    readout_format='.2f',
)

spec_ = widgets.FloatSlider(
    value=0.5,
    min=0,
    max=1.0,
    step=0.01,
    description='Specificity:',
    disabled=False,
    continuous_update=False,
    orientation='horizontal',
    readout=True,
    readout_format='.2f',
)
ui = widgets.VBox([sense_, spec_])

out = widgets.interactive_output(leaf_plot, {'sense': sense_, 'spec': spec_})

display(ui, out)

如何导出它,以便在浏览器中将其视为独立网页,例如 HTML,同时保留交互性,例如在https://gabgoh.github.io/COVID/index.html?

使用 plotly 的 fig.write_html() 选项,我得到一个独立的网页,但这样我会丢失滑块。

经过一些修改,plotly 最多允许单个滑块(ipywidgets 不包含在 plotly 图形对象中)。

另外,在情节上,上述滑块基本上控制了预先计算的轨迹的可见性(参见例如https://plotly.com/python/sliders/),这限制了交互性(有时参数空间很大)。

最好的方法是什么?

(我不一定需要坚持使用 plotly/ipywidgets)

【问题讨论】:

  • 是的!您需要在保存功能中使用 plotly 指定类型

标签: python plotly jupyter ipywidgets


【解决方案1】:

用plotly,创建图形后,保存:

fig.write_html("path/to/file.html")

在函数中也试试这个参数:

animation_opts:字典或无(默认无) 要传递给函数的自定义动画参数的字典 Plotly.js 中的 Plotly.animate。看 https://github.com/plotly/plotly.js/blob/master/src/plots/animation_attributes.js 可用选项。如果图形不包含则无效 帧,或 auto_play 为 False。

否则,请在此处查看一些建议:https://community.plotly.com/t/export-plotly-and-ipywidgets-as-an-html-file/18579

【讨论】:

  • 正如 OP 中所指出的,这会失去很多交互性。所有的滑块和其他 ipywidgets 都消失了。它们不是情节图形对象的一部分
  • 你知道这里用的是什么后端吗:gabgoh.github.io/COVID/index.html
【解决方案2】:

您需要进行一些修改,但您可以使用dashHeroku 实现您想要的。

首先你需要修改leaf_plot()来返回一个图形对象。

from numpy import linspace


def leaf_plot(sense, spec):
    fig = go.Figure()

    x = linspace(0,1,101)
    x[0] += 1e-16
    x[-1] -= 1e-16

    positive = sense*x/(sense*x + (1-spec)*(1-x)) 
    negative = 1-spec*(1-x)/((1-sense)*x + spec*(1-x))

    fig.add_trace(
        go.Scatter(x=x, y  = positive, name="Positive",marker=dict( color='red'))
    )

    fig.add_trace(
        go.Scatter(x=x, y  = negative, 
                   name="Negative", 
                   mode = 'lines+markers',
                   marker=dict( color='green'))
    )
    
    fig.update_layout(
    xaxis_title="Base rate",
    yaxis_title="After-test probability",
    )

    return fig

然后编写dash应用程序:

from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output


# Build App
app = JupyterDash(__name__)
app.layout = html.Div([
    html.H1("Interpreting Test Results"),
    dcc.Graph(id='graph'),
    html.Label([
        "sensitivity",
        dcc.Slider(
            id='sensitivity-slider',
            min=0,
            max=1,
            step=0.01,
            value=0.5,
            marks = {i: '{:5.2f}'.format(i) for i in linspace(1e-16,1-1e-16,11)}
        ),
    ]),
    html.Label([
        "specificity",
        dcc.Slider(
            id='specificity-slider',
            min=0,
            max=1,
            step=0.01,
            value=0.5,
            marks = {i: '{:5.2f}'.format(i) for i in linspace(1e-16,1-1e-16,11)}
        ),
    ]),
])

# Define callback to update graph
@app.callback(
    Output('graph', 'figure'),
    Input("sensitivity-slider", "value"),
    Input("specificity-slider", "value")
)
def update_figure(sense, spec):
    return leaf_plot(sense, spec)

# Run app and display result inline in the notebook
app.run_server()

如果您在 jupyter notebook 中执行此操作,您将只能在本地访问您的应用。

如果你想发布,可以试试Heroku

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-20
    • 1970-01-01
    • 2019-08-17
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    相关资源
    最近更新 更多