【问题标题】:How to add values from selectedData input to a list?如何将 selectedData 输入中的值添加到列表中?
【发布时间】:2022-01-01 12:47:52
【问题描述】:

我构建了一个 Plotly Dash Web 应用程序来显示传感器数据。我想要一张可以选择车站的地图,因此我可以看到时间序列图。

这是我现在的回调:

@app.callback(
    Output('time_series1', 'figure'),
    Input('map_sensors', 'selectedData'))

def display_selected_data(selectedData):
    if selectedData is None: # Plot whole Dataframe if nothing is selected.
        fig = px.line(data_frame=df, x='date.utc', y='value', color='location')
    
        return fig
    
    else:
        selectedData['points'][0]['customdata'][0] # This line shows me the name of the location and I want to add this to a list
        return 

我可以在所选数据中显示位置。现在我的问题是,如何将其添加到列表中?

我的目标是像dff2 = df[df.location.isin(selected_locations)] 这样过滤数据框,以便我只绘制选定的位置。

我现在的完整应用:

from jupyter_dash import JupyterDash
import plotly.graph_objs as go
from dash import Dash, dcc, html, Input, Output, State
import pandas as pd
import plotly.express as px
import json

loc = pd.read_csv('location_sensors.csv')
df = pd.read_csv('measurement.csv')
style = {'width': '50%', 'height': '500px', 'float': 'left'}

# Build small example app.
app = dash.Dash(__name__)

styles = {
    'pre': {
        'border': 'thin lightgrey solid',
        'overflowX': 'scroll'
    }
}

fig_map = px.scatter_mapbox(loc, lat="lat", lon="lon", hover_name="location", 
                           hover_data={'location':True, 'lat':False, 'lon':False}, zoom=3, height=600,
                           color='location', mapbox_style="open-street-map")
fig_map.update_layout(clickmode='event+select')

app.layout =   html.Div([
        dcc.Graph(id='map_sensors', figure=fig_map , className='six columns'),
      
    html.Div([dcc.Graph(
                    id='time_series1',
                    style={'height': 400}
                ),
])
])

@app.callback(
    Output('time_series1', 'figure'),
    Input('map_sensors', 'selectedData'))

def display_selected_data(selectedData):
    if selectedData is None:
        fig = px.line(data_frame=df, x='date.utc', y='value', color='location')
    
        return fig
    
    else:
        # Here I want to filter the dataframe to the selected locations.
        return 
    
if __name__ == '__main__':
    app.run_server()

位置 csv 数据:

lat,lon,location
51.20966,4.43182,BETR801
48.83722,2.3939,FR04014
51.49467,-0.13193,London Westminster

时间序列数据: https://github.com/pandas-dev/pandas/blob/master/doc/data/air_quality_long.csv

【问题讨论】:

  • 我认为一个问题是,当你点击地图上的一个位置后,它会变灰,当你再次点击同一个灰显的位置时,输入selectedData将是None这意味着应用不会知道您重新点击了该点。

标签: python plotly plotly-dash


【解决方案1】:

对于您的@app.callback 装饰器,我认为您希望您的输入是clickData 而不是selectionData。如果您查看文档here 中的第一个示例,一旦您单击地图上的某个位置并且它是灰色的,当您稍后再次单击它时,clickData 将输入带有标记信息的字典,而 selectionData 将输入null(这意味着如果你使用selectionData而不是clickData,当你再次点击一个点后,破折号将无法识别)

然后,您可以拥有一个动态列表,该列表会根据用户选择和取消选择的位置而变化。也是一个非常小的点,但我将您的 DataFrame 变量名称从 loc 更改为 locs,因为 .loc 是 pandas DataFrame 方法。

from jupyter_dash import JupyterDash
import plotly.graph_objs as go
import dash
from dash import Dash, dcc, html, Input, Output, State
import pandas as pd
import plotly.express as px
import json

locs = pd.read_csv('location_sensors.csv')
df = pd.read_csv('https://raw.githubusercontent.com/pandas-dev/pandas/master/doc/data/air_quality_long.csv')

style = {'width': '50%', 'height': '500px', 'float': 'left'}

# Build small example app.
app = dash.Dash(__name__)

styles = {
    'pre': {
        'border': 'thin lightgrey solid',
        'overflowX': 'scroll'
    }
}

fig_map = px.scatter_mapbox(locs, lat="lat", lon="lon", hover_name="location", 
                           hover_data={'location':True, 'lat':False, 'lon':False}, zoom=3, height=600,
                           color='location', mapbox_style="open-street-map")

fig_map.update_layout(clickmode='event+select')

app.layout = html.Div([
    dcc.Graph(id='map_sensors', figure=fig_map , className='six columns'),
    html.Div([dcc.Graph(
        id='time_series1',
        style={'height': 400}
        ),
    ])
])

## define a list that will hold the columns of the dataframe
## this will be used to modify the px.line chart
selected_locations = list(locs['location'])

@app.callback(
    Output('time_series1', 'figure'),
    Input('map_sensors', 'clickData'))
def display_selected_data(clickData):
    ## when the app initializes
    if clickData is None:
        fig = px.line(data_frame=df, x='date.utc', y='value', color='location')

    ## when the user clicks on one of the loc points
    else:
        selection = clickData['points'][0]['customdata'][0]
        if selection in selected_locations:
            selected_locations.remove(selection)
        else:
            selected_locations.append(selection)
        fig = px.line(data_frame=df[df.location.isin(selected_locations)], x='date.utc', y='value', color='location')
    return fig
    
if __name__ == '__main__':
    app.run_server(debug=True)

【讨论】:

  • 谢谢您,非常感谢您的努力。我选择selectdedData 的原因是,这样可以在按下 shift 和 cntl 的情况下选择多个位置。您的解决方案非常聪明,但是在尝试之后,例如,当我单击第三个位置时,我得到了一个空图。有没有办法用selectedData 的值动态填充和清空选择列表,还是因为null 而建议不要使用它?
  • 我可以在有时间的时候进行更多研究,但我想说您可能需要在 selectedDataclickData 之间做出选择。如果您使用selectedData,您将能够使用 shift 和 cntrl 选择多个位置,但由于null 问题,您将无法重新选择任何内容。如果您使用clickData,您可以选择和取消选择每个位置,当您取消选择所有内容时,这将导致一个空白图表,除非您有一个条件,例如取消选择所有内容意味着应用程序实际上显示了所有内容
  • 感谢您的努力,我非常感谢。我解决了。我使用了您解决方案的某些部分以及社区中的某些部分。 community.plotly.com/t/…
  • 不客气@Gobrel!很高兴您能够解决问题
猜你喜欢
  • 2018-07-26
  • 2019-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
  • 2019-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多