嗯,显然,这是可能的 - 但是男孩,要获得所有这些信息,以便获得一个可行的示例是 困难 ...
首先,这些是我安装的版本:
$ 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>