首页 > 解决方案 > `line_mapbox` 和第二个图之间的交叉过滤器

问题描述

我是新手plotly,想可视化正在运行的活动中的数据。假设我有一个包含以下列的数据框:

df = pd.DataFrame(
    {
        "time": time,
        "latitude": latitude,
        "longitude": longitude,
        "altitude": altitude,
        "heartrate": heartrate,
    }
)

我想要两个图,一个是绘制纬度与经度的地图,另一个是绘制时间与心率(或高度)的图。但我希望将两个情节联系起来。因此,如果我在第二个图中选择 y 范围,我只想在地图上看到那些经纬度对,它们各自的时间值在我在第二个图中选择的范围内。同样,如果我在地图上选择点,我想在该点选择中寻找最小和最大时间值,并希望仅在第二个图中绘制这些点。

这是带有一些虚拟数据的屏幕截图: 在此处输入图像描述

我不知道如何链接这两个情节,所以任何帮助表示赞赏!源代码在这里给出:

import dash
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objs as go

app = dash.Dash()
server = app.server

np.random.seed(0)
# Random dummy data
n = 100
time = np.linspace(0, 1, n)
latitude = 50 + 0.001 * np.cumsum(np.random.randn(n))
longitude = 2 + 0.001 * np.cumsum(np.random.randn(n))
altitude = (time - 0.5) ** 2
heartrate = 100 + np.cumsum(np.random.randn(n))
df = pd.DataFrame(
    {
        "time": time,
        "latitude": latitude,
        "longitude": longitude,
        "altitude": altitude,
        "heartrate": heartrate,
    }
)

fig = px.line_mapbox(df, lat="latitude", lon="longitude", zoom=12, height=800)
fig.update_layout(mapbox_style="stamen-terrain")


app.layout = html.Div(
    [
        html.Div(
            [
                dcc.Graph(id="mymap", figure=fig),
            ]
        ),
        html.Div(
            [
                dcc.Graph(id="time-series"),
                dcc.Dropdown(
                    id="column",
                    options=[
                        {"label": i, "value": i} for i in ["altitude", "heartrate"]
                    ],
                    value="altitude",
                ),
            ]
        ),
    ]
)


def lineplot(x, y, title="", axis_type="Linear"):
    return {
        "data": [go.Scatter(x=x, y=y, mode="lines")],
    }


@app.callback(
    dash.dependencies.Output("time-series", "figure"),
    [
        dash.dependencies.Input("column", "value"),
    ],
)
def update_timeseries(column):
    x = df["time"]
    y = df[column]
    return lineplot(x, y)


app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})


if __name__ == "__main__":
    app.run_server(debug=True)

标签: pythonplotlyplotly-dash

解决方案


好吧,这是一个选项,我将线图框更改为 Scattermapbox,以便您可以选择框

并查看地图图中所选数据的代码和折线图中的过滤器

import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output, State
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objs as go

app = dash.Dash()
server = app.server

np.random.seed(0)
# Random dummy data
n = 100
time = np.linspace(0, 1, n)
latitude = 50 + 0.001 * np.cumsum(np.random.randn(n))
longitude = 2 + 0.001 * np.cumsum(np.random.randn(n))
altitude = (time - 0.5) ** 2
heartrate = 100 + np.cumsum(np.random.randn(n))
df = pd.DataFrame(
    {
        "time": time,
        "latitude": latitude,
        "longitude": longitude,
        "altitude": altitude,
        "heartrate": heartrate,
    }
)

fig = go.Figure(go.Scattermapbox(
    mode = "markers+lines",
    lon = df.longitude,
    lat = df.latitude,
    marker = {'size': 10}))
fig.update_layout(
    mapbox={
        'style': "stamen-terrain",
        'center' : dict(
            lat=50,
            lon=2
        ),
        'zoom': 12})


app.layout = html.Div(
    [
        html.Div(
            [
                dcc.Graph(id="mymap", figure=fig),
            ]
        ),
        html.Div(
            [
                dcc.Graph(id="time-series"),
                dcc.Dropdown(
                    id="column",
                    options=[
                        {"label": i, "value": i} for i in ["altitude", "heartrate"]
                    ],
                    value="altitude",
                ),
            ]
        ),
    ]
)


def lineplot(x, y, title="", axis_type="Linear"):
    return {
        "data": [go.Scatter(x=x, y=y, mode="lines")],
    }


@app.callback(
    Output("time-series", "figure"),
    [
        Input("column", "value"),
        Input("mymap", "selectedData")
    ],
)
def update_timeseries(column, selectedData):
    # add filter data by selectData points
    temp = df
    if selectedData is not None:
        sel_data = pd.DataFrame(selectedData['points'])
        temp = df.loc[(df.latitude.isin(sel_data.lat)) & (df.longitude.isin(sel_data.lon))]
    x = temp["time"]
    y = temp[column]
    return lineplot(x, y)


app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})


if __name__ == "__main__":
    app.run_server(debug=True)

在此处输入图像描述


推荐阅读