使用Plotly为子图添加按钮
我刚接触Plotly,想为每个子图添加按钮,而不是为整个图形添加按钮。但我找不到方法来实现这个功能。
有没有人能帮我一下,教我该怎么做?
这是我的代码:
def plot_data(data, filename):
"""
Plotting the data
param data: data to plot.
param filename: file name to write the output in.
return: None.
"""
subplot_titles_tuple = get_titles(data)
fig = make_subplots(shared_xaxes=False,rows=len(data), cols=1, subplot_titles=subplot_titles_tuple)
for i, segment in enumerate(data):
trace = go.Scatter(x=segment['x'], y=segment['y'], mode='lines', name=f"Plot {i + 1}") # change the name of the plot
#print('im here',segment['x'] )
fig.add_trace(trace,row=i+1,col=1)
# Set subplot titles
fig.update_layout(title=f"Plots for {filename}")
# Set x-axis and y-axis titles according to segment data
x_title = segment.get('x_array_label', 'RCM') # Default to 'X-axis' if 'x_array_label' is not present
y_title = segment.get('y_array_label', 'Y-axis') # Default to 'Y-axis' if 'y_array_label' is not present
fig.update_xaxes(title_text=x_title, row=i + 1, col=1)
fig.update_yaxes(title_text=y_title, row=i + 1, col=1)
### Buttons for the user to change in the plot
fig.update_layout(
updatemenus=[
dict(
buttons=[
dict(label="Linear", method="relayout", args=[{"yaxis.type": "linear"}]),
dict(label="Log", method="relayout", args=[{"yaxis.type": "log"}]),
dict(label="Points", method="restyle", args=[{"mode": "markers"}]),
dict(label="Line", method="restyle", args=[{"mode": "lines+markers"}]),
],
direction="down",
showactive=True,
x=1,
xanchor="left",
y=0.9,
yanchor="top"
)
]
)
# change xlim and ylim
xlim_slider = widgets.FloatRangeSlider(
value=[min(segment['x']), max(segment['x'])], # Initial limits based on data
min=min(segment['x']),
max=max(segment['x']),
step=0.1,
description='xlim:',
continuous_update=False
)
ylim_slider = widgets.FloatRangeSlider(
value=[min(segment['y']), max(segment['y'])], # Initial limits based on data
min=min(segment['y']),
max=max(segment['y']),
step=0.1,
description='ylim:',
continuous_update=False
)
# Function to update xlim and ylim
def update_plot(xlim, ylim):
fig.update_xaxes(range=xlim)
fig.update_yaxes(range=ylim)
# Connect sliders to update function
widgets.interactive(update_plot, xlim=xlim_slider, ylim=ylim_slider)
# Show or save the plot
plot_filename = f"{os.path.splitext(filename)[0]}_plots.html"
plot_path = os.path.join(os.getcwd(), plot_filename)
fig.write_html(plot_path)
print(f"All plots saved in {plot_filename}")
这是我得到的结果:截图。
我希望这些选项出现在每个子图上,而不是整个图表上。
1 个回答
0
主要的问题是,fig.update_layout(updatemenus=[...])
这个代码是在一个循环里执行的,所以每次循环的时候,updatemenus
这个列表会被覆盖,而不是在原来的基础上增加内容。布局中的 title
也是同样的问题,不过因为布局配置是针对整个图形的,所以你只能设置一个标题,但看起来你已经通过 subplot_titles
解决了这个问题。
关于更新 y 轴类型的按钮,你需要指定轴的 ID(比如 yaxis
、yaxis2
等),这个 ID 要和子图的索引对应。
至于调用 restyle 方法的按钮,你需要指定一个跟对应子图上存在的 trace(数据轨迹)相关的索引列表(也就是说,trace 的索引不一定和子图的索引相匹配)。
fig = make_subplots(shared_xaxes=False,rows=len(data), cols=1, subplot_titles=subplot_titles_tuple)
fig.update_layout(title=f"Plots for {filename}")
updatemenus = []
btn_y = [0.9, 0.4]
for i, segment in enumerate(data):
trace = go.Scatter(x=segment['x'], y=segment['y'], mode='lines', name=f"Plot {i + 1}") # change the name of the plot
#print('im here',segment['x'] )
fig.add_trace(trace,row=i+1,col=1)
# Set x-axis and y-axis titles according to segment data
x_title = segment.get('x_array_label', 'RCM') # Default to 'X-axis' if 'x_array_label' is not present
y_title = segment.get('y_array_label', 'Y-axis') # Default to 'Y-axis' if 'y_array_label' is not present
fig.update_xaxes(title_text=x_title, row=i + 1, col=1)
fig.update_yaxes(title_text=y_title, row=i + 1, col=1)
yaxis_id = 'yaxis' if i == 0 else f'yaxis{i+1}'
updatemenus.extend([
dict(
buttons=[
dict(label="Linear", method="relayout", args=[{f"{yaxis_id}.type": "linear"}]),
dict(label="Log", method="relayout", args=[{f"{yaxis_id}.type": "log"}])
],
direction="down",
showactive=True,
active=0,
x=1,
xanchor="left",
y=btn_y[i],
yanchor="top"
),
dict(
buttons=[
dict(label="Points", method="restyle", args=[{"mode": "markers"}, [i]]),
dict(label="Line", method="restyle", args=[{"mode": "lines+markers"}, [i]]),
],
direction="down",
showactive=True,
active=1,
x=1,
xanchor="left",
y=btn_y[i]-0.05,
yanchor="top"
)
])
fig.update_layout(updatemenus=updatemenus)