提问人:Ben 提问时间:11/16/2023 更新时间:11/22/2023 访问量:31
添加下一个/上一个按钮以绘制破折号
Add next/previous buttons to plotly dash
问:
达世币应用程序主要有两个图,其中第一个用于显示第二个图中的数据。这是通过在第一个数据点中选择一个数据点,它将加载一个连接的数据框以显示在第二个数据框中。
现在,我想在第一个图中添加下一个/上一个按钮,以便通过按钮在数据点之间切换,而不仅仅是使用鼠标。但是我已经努力了很长一段时间,但我仍然无法控制。哎呀,我的脑袋被我尝试过的所有事情弄得头晕目眩,我现在很困惑,我不知道该如何进行或尝试其他什么。这就是为什么我感谢任何能够继续前进的帮助。
我有这个数据帧:
df2.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100080 entries, 0 to 100079
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Device 100080 non-null category
1 time 100080 non-null datetime64[ns]
2 time2 100080 non-null float64
3 Path 100080 non-null category
4 variable 100080 non-null object
5 value 100080 non-null float64
6 path 100080 non-null category
dtypes: category(3), datetime64[ns](1), float64(2), object(1)
memory usage: 3.3+ MB
有了这个数据:
Device time time2 Path variable value path
0 A 2022-09-27 11:57:26.801999 0.0 C:\Users\2022_09_27_11_57_26_,80.csv V+ 7.985262 C:\Users\2022_09_27_11_57_26_,80.csv
1 A 2022-09-27 11:57:26.802199 0.0002 C:\Users\2022_09_27_11_57_26_,80.csv V+ 7.981362 C:\Users\2022_09_27_11_57_26_,80.csv
2 A 2022-09-27 11:57:26.802399 0.0004 C:\Users\2022_09_27_11_57_26_,80.csv V+ 7.981687 C:\Users\2022_09_27_11_57_26_,80.csv
3 A 2022-09-27 11:57:26.802599 0.0006000000000000001 C:\Users\2022_09_27_11_57_26_,80.csv V+ 7.983637 C:\Users\2022_09_27_11_57_26_,80.csv
4 A 2022-09-27 11:57:26.802799 0.0008 C:\Users\2022_09_27_11_57_26_,80.csv V+ 7.983637 C:\Users\2022_09_27_11_57_26_,80.csv
5 A 2022-09-27 11:57:26.802999 0.001 C:\Users\2022_09_27_11_57_26_,80.csv V+ 7.984612 C:\Users\2022_09_27_11_57_26_,80.csv
6 A 2022-09-27 11:57:26.803199 0.0012000000000000001 C:\Users\2022_09_27_11_57_26_,80.csv V+ 7.983637 C:\Users\2022_09_27_11_57_26_,80.csv
7 A 2022-09-27 11:57:26.803399 0.0014 C:\Users\2022_09_27_11_57_26_,80.csv V+ 7.982012 C:\Users\2022_09_27_11_57_26_,80.csv
...
这是我的布局:
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, title='Dashboard', external_stylesheets=external_stylesheets, assets_folder = 'assets')
colors = {
'background': '#000000',
'text': '#f3ff00'
}
# Define the app
app.layout = html.Div(
children = [
html.Div([
html.H4('Dauertest'),
html.Div(children = ""),
# Draw graph
dcc.Graph(id = 'General'
, figure={}
),
dcc.RadioItems(
id="signals",
options = ['V+', 'V-', 'I_A', 'I_fil'],
value = 'V+',
inline=True
),
html.Br(),
dcc.Graph(id = 'Zoomed'
#, figure={}
#, hoverData = {'points': [{'customdata': df2['path'][0]}]}
),
html.Br(),
]),
html.Br(),
html.Br(),
html.Br(),
# New row
html.Div([
html.Div([
dcc.Dropdown(
id="select",
options = list(all_df['Device'].unique()),
value = list(all_df['Device'].unique()[0])
),
dcc.Graph(id = 'shared'
, figure={}
),
#], className='six columns'),
], className='twelve columns'),
], className='row')
])
和这些图:
#%% Plot 1
@app.callback(
Output("General", "figure"),
Input("signals", "value")
)
def update_scatter_chart(signals):
df3 = df2.query('variable==@signals').groupby('path').first()
fig_general = px.scatter(df3
, x = "time"
, y = 'value'
, custom_data = ['Path']
, color = 'Device'
, symbol = 'variable'
, hover_name = "Path"
, opacity = 0.75
, template = 'plotly_dark'
, marginal_y = "rug"
, title = "All devices <br><sup> Only the first data point of below selected variable plus of each error file</sup>"
, labels=dict(x = "absolute time")
)
fig_general.update_layout(
clickmode = 'event+select'
, xaxis = {'domain': [0.0, 0.85]}
, xaxis2 = {'domain': [0.86, 0.97]}
#, xaxis3 = {'domain': [0.85, 1.0]}
, transition_duration = 500
, autosize = True
, height = 700
, hovermode = 'closest'
)
fig_general.update_traces(marker = dict(size = 16,
line=dict(width = 2,
color = 'rgba(255, 255, 255, 0.3)'),
opacity = 0.75
)
, selected_marker = dict(size = 20
, opacity = 0.95
, color='rgba( 240, 240, 240, 0.95)')
, unselected = dict(marker = dict(opacity = 0.75)
)
, hovertemplate="<br>".join([
"time: %{x}",
"value: %{y}",
])
)
return fig_general
#%% Plot 2
def update_zoom_chart(df5, device_name):
fig_zoom = px.scatter(df5
, x = "time2"
, y = 'value'
, color = 'variable'
, symbol = 'variable'
#, hover_name = "Device"
, opacity = 0.7
, template = 'plotly_dark'
, title = device_name
, color_discrete_map = {"I_A": 'orangered', "I_fil" : 'lawngreen', "V+" : "dodgerblue", "V-" : "chocolate"}
, labels = dict(x = "t / ms", y = "value")
)
fig_zoom.update_xaxes( nticks = 10 )
fig_zoom.update_traces(marker = dict(
size = 5
)
)
fig_zoom.update_layout(
transition_duration = 500
, autosize = True
, height = 600
, hovermode='x unified'
, hoverlabel=dict(
bgcolor="rgba(0, 0, 0, 0.4)",
font_size=14,
font_family="Rockwell"
)
)
return fig_zoom
答:
1赞
Troy D
11/22/2023
#1
在此示例中,左侧有一个散点图。当您在任何数据点上计时时,它会在下拉菜单中选择突出显示的项目。更新该下拉菜单后,右侧的两个折线图将更新。因此,您可以通过单击散点图中的数据点来选择项目,也可以在下拉菜单中逐项查看,以显示列表中的所有数据点。我还添加了一个“上一个”和“下一个”按钮,您可以单击该按钮循环浏览下拉菜单中的项目。如果您只想要没有下拉菜单的上一个/下一个按钮,也可以使用 dcc.Store() 来保存当前选择而不是下拉菜单。
from dash import Dash, html, dcc, Input, State, Output, callback, ctx
import pandas as pd
import plotly.express as px
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = Dash(__name__, external_stylesheets=external_stylesheets)
df = pd.read_csv('https://plotly.github.io/datasets/country_indicators.csv')
country_list = df['Country Name'].unique().tolist()
app.layout = html.Div([
html.Div([
html.Div([
dcc.Dropdown(
df['Indicator Name'].unique(),
'Fertility rate, total (births per woman)',
id='crossfilter-xaxis-column',
),
dcc.RadioItems(
['Linear', 'Log'],
'Linear',
id='crossfilter-xaxis-type',
labelStyle={'display': 'inline-block', 'marginTop': '5px'}
)
],
style={'width': '49%', 'display': 'inline-block'}),
html.Div([
dcc.Dropdown(
df['Indicator Name'].unique(),
'Life expectancy at birth, total (years)',
id='crossfilter-yaxis-column'
),
dcc.RadioItems(
['Linear', 'Log'],
'Linear',
id='crossfilter-yaxis-type',
labelStyle={'display': 'inline-block', 'marginTop': '5px'}
)
], style={'width': '49%', 'float': 'right', 'display': 'inline-block'})
], style={
'padding': '10px 5px'
}),
html.Div([
dcc.Graph(
id='crossfilter-indicator-scatter',
hoverData={'points': [{'customdata': 'Japan'}]}
)
], style={'width': '49%', 'display': 'inline-block', 'padding': '0 20'}),
html.Div([
dcc.Graph(id='x-time-series'),
dcc.Graph(id='y-time-series'),
], style={'display': 'inline-block', 'width': '49%'}),
html.Div(dcc.Slider(
df['Year'].min(),
df['Year'].max(),
step=None,
id='crossfilter-year--slider',
value=df['Year'].max(),
marks={str(year): str(year) for year in df['Year'].unique()}
), style={'width': '49%', 'padding': '0px 20px 20px 20px'}),
dcc.Dropdown(
df['Country Name'].unique(),
id='country',
),
html.Button('Previous', id='btn-nclicks-1', n_clicks=0),
html.Button('Next', id='btn-nclicks-2', n_clicks=0),
])
@callback(
Output('crossfilter-indicator-scatter', 'figure'),
Input('crossfilter-xaxis-column', 'value'),
Input('crossfilter-yaxis-column', 'value'),
Input('crossfilter-xaxis-type', 'value'),
Input('crossfilter-yaxis-type', 'value'),
Input('crossfilter-year--slider', 'value'))
def update_graph(xaxis_column_name, yaxis_column_name,
xaxis_type, yaxis_type,
year_value):
dff = df[df['Year'] == year_value]
fig = px.scatter(x=dff[dff['Indicator Name'] == xaxis_column_name]['Value'],
y=dff[dff['Indicator Name'] == yaxis_column_name]['Value'],
hover_name=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name']
)
fig.update_traces(customdata=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'])
fig.update_xaxes(title=xaxis_column_name, type='linear' if xaxis_type == 'Linear' else 'log')
fig.update_yaxes(title=yaxis_column_name, type='linear' if yaxis_type == 'Linear' else 'log')
fig.update_layout(margin={'l': 40, 'b': 40, 't': 10, 'r': 0}, hovermode='closest')
return fig
def create_time_series(dff, axis_type, title):
fig = px.scatter(dff, x='Year', y='Value')
fig.update_traces(mode='lines+markers')
fig.update_xaxes(showgrid=False)
fig.update_yaxes(type='linear' if axis_type == 'Linear' else 'log')
fig.add_annotation(x=0, y=0.85, xanchor='left', yanchor='bottom',
xref='paper', yref='paper', showarrow=False, align='left',
text=title)
fig.update_layout(height=225, margin={'l': 20, 'b': 30, 'r': 10, 't': 10})
return fig
@callback(
Output('x-time-series', 'figure'),
Input('crossfilter-xaxis-column', 'value'),
Input('crossfilter-xaxis-type', 'value'),
Input('country', 'value'))
def update_x_timeseries(xaxis_column_name, axis_type, input_country):
country_name = input_country
dff = df[df['Country Name'] == country_name]
dff = dff[dff['Indicator Name'] == xaxis_column_name]
title = '<b>{}</b><br>{}'.format(country_name, xaxis_column_name)
return create_time_series(dff, axis_type, title)
@callback(
Output('y-time-series', 'figure'),
Input('crossfilter-yaxis-column', 'value'),
Input('crossfilter-yaxis-type', 'value'),
Input('country', 'value'))
def update_y_timeseries(yaxis_column_name, axis_type, input_country):
dff = df[df['Country Name'] == input_country]
dff = dff[dff['Indicator Name'] == yaxis_column_name]
return create_time_series(dff, axis_type, yaxis_column_name)
@callback(
Output('country', 'value'),
Input('crossfilter-indicator-scatter', 'clickData'),
Input('crossfilter-yaxis-column', 'value'),
Input('crossfilter-yaxis-type', 'value'),
Input('btn-nclicks-1', 'n_clicks'),
Input('btn-nclicks-2', 'n_clicks'),
State('country', 'value'),
)
def update_y_timeseries(clickData, yaxis_column_name, axis_type, n_clicks_1, n_clicks_2, current_country):
if ctx.triggered_id is None:
return country_list[0]
elif "btn-nclicks-1" == ctx.triggered_id:
index = country_list.index(current_country)
try:
next_country = country_list[index - 1]
except:
next_country = country_list[0]
return next_country
elif "btn-nclicks-2" == ctx.triggered_id:
index = country_list.index(current_country)
try:
next_country = country_list[index + 1]
except:
next_country = country_list[0]
return next_country
return clickData['points'][0]['customdata']
if __name__ == '__main__':
app.run(debug=True)
评论
0赞
Ben
11/23/2023
嗨,@Troy,谢谢,我明天会试试!只是为了我的理解,当我正确地得到你时,你会在下拉项而不是数据点(根据要求)切换“仅”吗?没有冒犯。
1赞
Troy D
11/23/2023
嗨,@Ben。在此示例中,每个数据点都显示在下拉菜单中,因此您可以通过在散点图中单击数据点、从下拉列表中进行选择或使用按钮循环浏览数据点来选择数据点。下拉项与散点图相同。下拉菜单不是必需的,如果您愿意,可以将当前选择保存在 dcc.Store() 中。您只需要一些保存当前所选数据点的方法。
评论