bd3
bd3

Reputation: 101

Dash Python - Making subplots when multiple parameters are selected

I am trying to make an interactive plot where a user would select a location, then a time, and then one of a list of parameters. I am able to plot a basic plot of each parameter, but what I want to do is that when multiple parameters from the list are selected, a stacked subplot begins to form for each parameter. I have what I thought was a loop that is correct, but it doesn't seem to run through it to make the subplots.

Looking for some help on how to do add subplots under the conditions of more than one parameter selected.

Code below:

import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output, State
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
import glob
import os
import plotly.subplots as sp
pd.options.mode.chained_assignment = None

path = r'C:\path'
all_files = glob.glob(os.path.join(path, "*.csv"))
print(all_files)

#create list of columns for pd.read_table
col_list = list(range(0, 24))

df = pd.concat(map(pd.read_csv, all_files))

df['run_time'] = pd.to_datetime(df['run_time'])
df['forecast_time'] = pd.to_datetime(df['forecast_time'])
df['r_hour'] = df['run_time'].dt.hour
df = df.astype({'r_hour': str})


# create a list of our conditions
conditions = [
    (df['lat'] > 10),
    (df['lat'] < 10)
    ]

# create a list of the values we want to assign for each condition
values = ['k', 'w']
df['location'] = np.select(conditions, values)
df = df.drop(columns=['lat','lon'])
print(df)

#Build App
app = dash.Dash(__name__)

app.layout = html.Div(
    [
        dcc.Dropdown(
            id="location",
            options=[{'label': 'K', 'value': 'k'},
                     {'label': 'W', 'value': 'w'}],
            value="location",
            placeholder='Select a location',
        ),
        dcc.Dropdown(
            id="r_hour",
            options=[{'label': '00Z', 'value': '0'},
                     {'label': '06Z', 'value': '6'},
                     {'label': '12Z', 'value': '12'},
                     {'label': '18Z', 'value': '18'}],
            value="r_hour",
            placeholder="Select a forecast time",
        ),
        dcc.Dropdown(
            id="parameter",
            options=[{"label": x, "value": x} for x in df["parameter"].unique()],
            value="param",
            placeholder='Select a parameter',
            multi=True
        ),
        dcc.Graph(id="graph1", figure={}
        ),
    ]
)
print(len(df.parameter.unique()))
dff = df[(df.location=='w') & (df.r_hour=='0') & (df.parameter.isin(['CAPE']))]
print(dff)
@app.callback(
    Output("graph1", "figure"),
    Input("location", "value"),
    Input("r_hour", "value"),
    Input('parameter', 'value'),
    )
def update_graph1(loc, r_hour, parameter):
    if len(loc) == 0:
        return dash.no_update
    else:
        dff = df[(df.location == loc) & (df.r_hour == r_hour) & (df.parameter.isin(parameter))]
        print(loc, r_hour, parameter)
        print(len(parameter))
        print(range(len(parameter)))
        if len(parameter) > 1:
            fig = sp.make_subplots(rows=(len(parameter)), cols=1)
            for n in range(len(parameter)):
                print(n)
                fig.append_trace(px.scatter(dff, x='forecast_time', y=dff.columns[5:10], row=n, col=1))
        else:
            print(dff)
            fig = px.scatter(dff, x='forecast_time', y=dff.columns[5:10])
    return fig


# Run app and display result inline in the notebook
if __name__ == '__main__':
    app.run_server(debug=True)

Example of data:

    run_time    forecast_time   parameter   mean    max min ci_low  ci_high r_hour  loc
9/14/2016 12:00 9/14/2016 18:00 APCP    0.041483684 0.127401644 0.009763785 0.029901197 0.060754167 12  w
9/14/2016 12:00 9/15/2016 0:00  APCP    0.037159666 0.140004013 0.000519685 0.026262613 0.056544125 12  w
9/14/2016 12:00 9/15/2016 6:00  APCP    0.053111446 0.163689065 0.009968509 0.038685651 0.075773072 12  w
9/14/2016 12:00 9/15/2016 12:00 APCP    0.02625966  0.083563037 0.004811026 0.01951379  0.036598051 12  w
9/14/2016 12:00 9/15/2016 18:00 APCP    0.037727973 0.10328352  0.007964571 0.028584858 0.05144924  12  w
9/14/2016 12:00 9/14/2016 12:00 CAPE    2531.348    2783.08 2364.6  2484.948    2583.0745   12  w
9/14/2016 12:00 9/14/2016 18:00 CAPE    2343.2995   2618.87 1895.03 2240.252    2419.445    12  w
9/14/2016 12:00 9/15/2016 0:00  CAPE    2270.763    2521.38 1965.84 2203.535    2334.4885   12  w
9/14/2016 12:00 9/15/2016 6:00  CAPE    2422.276    2637.64 2000.03 2340.4395   2476.8495   12  w
9/14/2016 12:00 9/15/2016 12:00 CAPE    2560.587    2765.51 2167.7  2484.0775   2621.121    12  w
9/14/2016 12:00 9/15/2016 18:00 CAPE    2434.641    2643.32 2177.51 2375.872    2485.731    12  w
9/14/2016 12:00 9/14/2016 12:00 WSPD    13.67982033 14.92190326 11.93637952 13.28460204 14.01356071 12  w
9/14/2016 12:00 9/14/2016 18:00 WSPD    13.00873562 14.51315919 11.61153561 12.670458   13.35743091 12  w
9/14/2016 12:00 9/15/2016 0:00  WSPD    13.15495082 14.50841618 11.95527281 12.86944934 13.47149018 12  w
9/14/2016 12:00 9/15/2016 6:00  WSPD    12.25102442 13.75337432 10.89424146 11.92889921 12.55852141 12  w
9/14/2016 12:00 9/15/2016 12:00 WSPD    13.61138813 14.97033537 11.80458902 13.27546662 13.8712801  12  w
9/14/2016 12:00 9/15/2016 18:00 WSPD    11.86885821 13.08368289 10.74028982 11.607135   12.14320021 12  w
9/14/2016 18:00 9/15/2016 0:00  APCP    0.034182499 0.079354374 0.003188978 0.025235644 0.044085457 18  w
9/14/2016 18:00 9/15/2016 6:00  APCP    0.046251403 0.144504015 0.006216539 0.034403562 0.064499641 18  w
9/14/2016 18:00 9/15/2016 12:00 APCP    0.029244504 0.23320485  0.005094491 0.016554536 0.07372189  18  w
9/14/2016 18:00 9/15/2016 18:00 APCP    0.024053163 0.087622095 0.002917324 0.016503159 0.03626065  18  w
9/14/2016 18:00 9/14/2016 18:00 CAPE    2435.6345   2712.71 2094.12 2370.4595   2499.1125   18  w
9/14/2016 18:00 9/15/2016 0:00  CAPE    2276.4495   2400.68 2040.39 2231.341    2310.1765   18  w
9/14/2016 18:00 9/15/2016 6:00  CAPE    2443.665    2747.34 2135.22 2382.9555   2505.553    18  w
9/14/2016 18:00 9/15/2016 12:00 CAPE    2499.848    2758.34 2242.96 2442.4635   2557.9475   18  w
9/14/2016 18:00 9/15/2016 18:00 CAPE    2445.8005   2623    2252.07 2392.139    2496.5585   18  w
9/14/2016 18:00 9/14/2016 18:00 WSPD    12.80103404 14.36857011 11.76708975 12.54172344 13.11939702 18  w
9/14/2016 18:00 9/15/2016 0:00  WSPD    13.2089427  15.63134179 11.92824288 12.92959876 13.63760661 18  w
9/14/2016 18:00 9/15/2016 6:00  WSPD    12.72761899 13.52581477 11.74122287 12.46831392 12.95820863 18  w
9/14/2016 18:00 9/15/2016 12:00 WSPD    13.78891527 14.57733477 12.43695412 13.5125545  13.98578588 18  w
9/14/2016 18:00 9/15/2016 18:00 WSPD    11.80539318 12.4321654  10.59583493 11.54830383 11.9986291  18  w
9/14/2016 12:00 9/14/2016 18:00 APCP    0.024927179 0.057874047 0.011023628 0.020621271 0.032037025 12  k
9/14/2016 12:00 9/15/2016 0:00  APCP    0.012142526 0.072992165 0   0.006259058 0.024529935 12  k
9/14/2016 12:00 9/15/2016 6:00  APCP    0.0341449   0.0889843   0.003606301 0.02528151  0.045535458 12  k
9/14/2016 12:00 9/15/2016 12:00 APCP    0.013788196 0.058086646 0.000535433 0.008549217 0.022687808 12  k
9/14/2016 12:00 9/15/2016 18:00 APCP    0.007568902 0.024826785 0.001023623 0.005498428 0.011116148 12  k
9/14/2016 12:00 9/14/2016 12:00 CAPE    1915.985    2022.58 1724.18 1877.471    1944.124    12  k
9/14/2016 12:00 9/14/2016 18:00 CAPE    1765.312    1976.54 1571.52 1723.748    1808.896    12  k
9/14/2016 12:00 9/15/2016 0:00  CAPE    1903.907    2111.48 1630.76 1849.207    1955.516    12  k
9/14/2016 12:00 9/15/2016 6:00  CAPE    2022.187    2218.66 1744.28 1971.346    2066.359    12  k
9/14/2016 12:00 9/15/2016 12:00 CAPE    2117.713    2289.48 1977.74 2080.877    2160.069    12  k
9/14/2016 12:00 9/15/2016 18:00 CAPE    2035.243    2287.06 1737.66 1966.873    2093.823    12  k
9/14/2016 12:00 9/14/2016 12:00 WSPD    11.51403081 12.90299913 9.348005138 11.02996656 11.91310878 12  k
9/14/2016 12:00 9/14/2016 18:00 WSPD    10.66348483 12.10730058 8.536612865 10.2005094  11.04692859 12  k
9/14/2016 12:00 9/15/2016 0:00  WSPD    10.81256637 12.22364593 9.74415303  10.53260001 11.1350116  12  k
9/14/2016 12:00 9/15/2016 6:00  WSPD    11.10226976 12.35115476 9.882793516 10.80288164 11.39107227 12  k
9/14/2016 12:00 9/15/2016 12:00 WSPD    11.26334728 12.6892719  9.999631254 10.97207787 11.57319938 12  k
9/14/2016 12:00 9/15/2016 18:00 WSPD    9.835853253 11.13364239 7.475216637 9.385502624 10.13933703 12  k
9/14/2016 18:00 9/15/2016 0:00  APCP    0.017726388 0.074779568 0.002259844 0.011548038 0.028326    18  k
9/14/2016 18:00 9/15/2016 6:00  APCP    0.027098834 0.054606329 0.001393702 0.020021664 0.0343012   18  k
9/14/2016 18:00 9/15/2016 12:00 APCP    0.020631507 0.119322899 0.002086615 0.010669297 0.0426827   18  k
9/14/2016 18:00 9/15/2016 18:00 APCP    0.005209452 0.012196857 0   0.003969687 0.006824413 18  k
9/14/2016 18:00 9/14/2016 18:00 CAPE    1764.579    1914.96 1525.46 1722.144    1800.189    18  k
9/14/2016 18:00 9/15/2016 0:00  CAPE    1904.978    2052.38 1701.34 1861.194    1941.033    18  k
9/14/2016 18:00 9/15/2016 6:00  CAPE    2043.728    2209.68 1761.32 1989.58 2086.367    18  k
9/14/2016 18:00 9/15/2016 12:00 CAPE    2123.021    2258    1954.9  2085.106    2155.768    18  k
9/14/2016 18:00 9/15/2016 18:00 CAPE    2079.35 2397.08 1745.22 2011.772    2135.195    18  k
9/14/2016 18:00 9/14/2016 18:00 WSPD    10.30410353 11.91721456 8.248297085 9.838215725 10.75774552 18  k
9/14/2016 18:00 9/15/2016 0:00  WSPD    10.9400117  12.43605914 9.573964769 10.59848982 11.28932813 18  k
9/14/2016 18:00 9/15/2016 6:00  WSPD    11.46127399 12.81606087 10.4988286  11.2154979  11.73633011 18  k
9/14/2016 18:00 9/15/2016 12:00 WSPD    11.17043143 12.43677466 9.707966369 10.84331329 11.49746871 18  k
9/14/2016 18:00 9/15/2016 18:00 WSPD    9.871976672 11.04788095 8.228105178 9.523215227 10.15348249 18  k

Upvotes: 2

Views: 1027

Answers (1)

Tobi208
Tobi208

Reputation: 1376

As per my research, it's not possible to generate a single plot the way you would like to. If you take a look at the plotly subplots documentation, you'll notice that subplots can only be populated with traces that are graph objects. The px.scatter() figure you're generating for a single parameter is already made up of multiple traces. A subplot cannot be populated with figures, only traces.

First, I adjusted your code to produce subplots. Disregarding your dataframe manipulation and only focusing on the plotly syntax, there are some errors I found in this part:

for n in range(len(parameter)):
    fig.append_trace(px.scatter(dff, x='forecast_time', y=dff.columns[5:10], row=n, col=1))
  1. As mentioned, the trace needs to a graph object and not a figure.

  2. The row count starts at 1, not 0.

  3. row, col are parameters for append_trace, so they need to be moved outside their current bracket.

  4. You'd need to filter dff for the right parameter in either case.

Here's my full code and data that produces subplots

import dash
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from dash import dcc, html
from dash.dependencies import Input, Output


df = pd.read_csv('values.csv')
df.astype({
    'run_time': 'datetime64',
    'forecast_time': 'datetime64',
    'parameter': 'string',
    'mean': 'float64',
    'max': 'float64',
    'min': 'float64',
    'ci_low': 'float64',
    'ci_high': 'float64',
    'r_hour': 'int64',
    'loc': 'string'
})


app = dash.Dash(__name__)
app.layout = html.Div(
    [
        dcc.Dropdown(
            id="location",
            options=[{'label': 'K', 'value': 'k'},
                     {'label': 'W', 'value': 'w'}],
            value='w',
            placeholder='Select a location',
        ),
        dcc.Dropdown(
            id="r_hour",
            options=[{'label': '00Z', 'value': 0},
                     {'label': '06Z', 'value': 6},
                     {'label': '12Z', 'value': 12},
                     {'label': '18Z', 'value': 18}],
            value='12',
            placeholder="Select a forecast time",
        ),
        dcc.Dropdown(
            id="parameter",
            options=[{"label": x, "value": x} for x in df["parameter"].unique()],
            placeholder='Select a parameter',
            value='CAPE',
            multi=True
        ),
        dcc.Graph(id="graph1", figure={}),
    ]
)


@app.callback(
    Output("graph1", "figure"),
    Input("location", "value"),
    Input("r_hour", "value"),
    Input('parameter', 'value'),
)
def update_graph1(loc, r_hour, parameter):
    if loc is None or r_hour is None or parameter is None:
        return dash.no_update

    parameter = parameter if isinstance(parameter, list) else [parameter]
    dff = df[(df['loc'] == loc) & (df['r_hour'] == int(r_hour)) & (df['parameter'].isin(parameter))]

    if len(parameter) > 1:
        fig = make_subplots(rows=len(parameter), cols=1)
        r = 1
        for p in parameter:
            fig.append_trace(
                go.Scatter(x=dff['forecast_time'], y=dff[dff['parameter'] == p]['mean']),
                row=r, col=1
            )
            r += 1
        return fig

    return px.scatter(dff, x='forecast_time', y=['mean', 'max', 'min', 'ci_low', 'ci_high'])


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

run_time,forecast_time,parameter,mean,max,min,ci_low,ci_high,r_hour,loc
9/14/2016 12:00,9/14/2016 18:00,APCP,0.041483684,0.127401644,0.009763785,0.029901197,0.060754167,12,w
9/14/2016 12:00,9/15/2016 0:00,APCP,0.037159666,0.140004013,0.000519685,0.026262613,0.056544125,12,w
9/14/2016 12:00,9/15/2016 6:00,APCP,0.053111446,0.163689065,0.009968509,0.038685651,0.075773072,12,w
9/14/2016 12:00,9/15/2016 12:00,APCP,0.02625966,0.083563037,0.004811026,0.01951379,0.036598051,12,w
9/14/2016 12:00,9/15/2016 18:00,APCP,0.037727973,0.10328352,0.007964571,0.028584858,0.05144924,12,w
9/14/2016 12:00,9/14/2016 12:00,CAPE,2531.348,2783.08,2364.6,2484.948,2583.0745,12,w
9/14/2016 12:00,9/14/2016 18:00,CAPE,2343.2995,2618.87,1895.03,2240.252,2419.445,12,w
9/14/2016 12:00,9/15/2016 0:00,CAPE,2270.763,2521.38,1965.84,2203.535,2334.4885,12,w
9/14/2016 12:00,9/15/2016 6:00,CAPE,2422.276,2637.64,2000.03,2340.4395,2476.8495,12,w
9/14/2016 12:00,9/15/2016 12:00,CAPE,2560.587,2765.51,2167.7,2484.0775,2621.121,12,w
9/14/2016 12:00,9/15/2016 18:00,CAPE,2434.641,2643.32,2177.51,2375.872,2485.731,12,w
9/14/2016 12:00,9/14/2016 12:00,WSPD,13.67982033,14.92190326,11.93637952,13.28460204,14.01356071,12,w
9/14/2016 12:00,9/14/2016 18:00,WSPD,13.00873562,14.51315919,11.61153561,12.670458,13.35743091,12,w
9/14/2016 12:00,9/15/2016 0:00,WSPD,13.15495082,14.50841618,11.95527281,12.86944934,13.47149018,12,w
9/14/2016 12:00,9/15/2016 6:00,WSPD,12.25102442,13.75337432,10.89424146,11.92889921,12.55852141,12,w
9/14/2016 12:00,9/15/2016 12:00,WSPD,13.61138813,14.97033537,11.80458902,13.27546662,13.8712801,12,w
9/14/2016 12:00,9/15/2016 18:00,WSPD,11.86885821,13.08368289,10.74028982,11.607135,12.14320021,12,w
9/14/2016 18:00,9/15/2016 0:00,APCP,0.034182499,0.079354374,0.003188978,0.025235644,0.044085457,18,w
9/14/2016 18:00,9/15/2016 6:00,APCP,0.046251403,0.144504015,0.006216539,0.034403562,0.064499641,18,w
9/14/2016 18:00,9/15/2016 12:00,APCP,0.029244504,0.23320485,0.005094491,0.016554536,0.07372189,18,w
9/14/2016 18:00,9/15/2016 18:00,APCP,0.024053163,0.087622095,0.002917324,0.016503159,0.03626065,18,w
9/14/2016 18:00,9/14/2016 18:00,CAPE,2435.6345,2712.71,2094.12,2370.4595,2499.1125,18,w
9/14/2016 18:00,9/15/2016 0:00,CAPE,2276.4495,2400.68,2040.39,2231.341,2310.1765,18,w
9/14/2016 18:00,9/15/2016 6:00,CAPE,2443.665,2747.34,2135.22,2382.9555,2505.553,18,w
9/14/2016 18:00,9/15/2016 12:00,CAPE,2499.848,2758.34,2242.96,2442.4635,2557.9475,18,w
9/14/2016 18:00,9/15/2016 18:00,CAPE,2445.8005,2623,2252.07,2392.139,2496.5585,18,w
9/14/2016 18:00,9/14/2016 18:00,WSPD,12.80103404,14.36857011,11.76708975,12.54172344,13.11939702,18,w
9/14/2016 18:00,9/15/2016 0:00,WSPD,13.2089427,15.63134179,11.92824288,12.92959876,13.63760661,18,w
9/14/2016 18:00,9/15/2016 6:00,WSPD,12.72761899,13.52581477,11.74122287,12.46831392,12.95820863,18,w
9/14/2016 18:00,9/15/2016 12:00,WSPD,13.78891527,14.57733477,12.43695412,13.5125545,13.98578588,18,w
9/14/2016 18:00,9/15/2016 18:00,WSPD,11.80539318,12.4321654,10.59583493,11.54830383,11.9986291,18,w
9/14/2016 12:00,9/14/2016 18:00,APCP,0.024927179,0.057874047,0.011023628,0.020621271,0.032037025,12,k
9/14/2016 12:00,9/15/2016 0:00,APCP,0.012142526,0.072992165,0,0.006259058,0.024529935,12,k
9/14/2016 12:00,9/15/2016 6:00,APCP,0.0341449,0.0889843,0.003606301,0.02528151,0.045535458,12,k
9/14/2016 12:00,9/15/2016 12:00,APCP,0.013788196,0.058086646,0.000535433,0.008549217,0.022687808,12,k
9/14/2016 12:00,9/15/2016 18:00,APCP,0.007568902,0.024826785,0.001023623,0.005498428,0.011116148,12,k
9/14/2016 12:00,9/14/2016 12:00,CAPE,1915.985,2022.58,1724.18,1877.471,1944.124,12,k
9/14/2016 12:00,9/14/2016 18:00,CAPE,1765.312,1976.54,1571.52,1723.748,1808.896,12,k
9/14/2016 12:00,9/15/2016 0:00,CAPE,1903.907,2111.48,1630.76,1849.207,1955.516,12,k
9/14/2016 12:00,9/15/2016 6:00,CAPE,2022.187,2218.66,1744.28,1971.346,2066.359,12,k
9/14/2016 12:00,9/15/2016 12:00,CAPE,2117.713,2289.48,1977.74,2080.877,2160.069,12,k
9/14/2016 12:00,9/15/2016 18:00,CAPE,2035.243,2287.06,1737.66,1966.873,2093.823,12,k
9/14/2016 12:00,9/14/2016 12:00,WSPD,11.51403081,12.90299913,9.348005138,11.02996656,11.91310878,12,k
9/14/2016 12:00,9/14/2016 18:00,WSPD,10.66348483,12.10730058,8.536612865,10.2005094,11.04692859,12,k
9/14/2016 12:00,9/15/2016 0:00,WSPD,10.81256637,12.22364593,9.74415303,10.53260001,11.1350116,12,k
9/14/2016 12:00,9/15/2016 6:00,WSPD,11.10226976,12.35115476,9.882793516,10.80288164,11.39107227,12,k
9/14/2016 12:00,9/15/2016 12:00,WSPD,11.26334728,12.6892719,9.999631254,10.97207787,11.57319938,12,k
9/14/2016 12:00,9/15/2016 18:00,WSPD,9.835853253,11.13364239,7.475216637,9.385502624,10.13933703,12,k
9/14/2016 18:00,9/15/2016 0:00,APCP,0.017726388,0.074779568,0.002259844,0.011548038,0.028326,18,k
9/14/2016 18:00,9/15/2016 6:00,APCP,0.027098834,0.054606329,0.001393702,0.020021664,0.0343012,18,k
9/14/2016 18:00,9/15/2016 12:00,APCP,0.020631507,0.119322899,0.002086615,0.010669297,0.0426827,18,k
9/14/2016 18:00,9/15/2016 18:00,APCP,0.005209452,0.012196857,0,0.003969687,0.006824413,18,k
9/14/2016 18:00,9/14/2016 18:00,CAPE,1764.579,1914.96,1525.46,1722.144,1800.189,18,k
9/14/2016 18:00,9/15/2016 0:00,CAPE,1904.978,2052.38,1701.34,1861.194,1941.033,18,k
9/14/2016 18:00,9/15/2016 6:00,CAPE,2043.728,2209.68,1761.32,1989.58,2086.367,18,k
9/14/2016 18:00,9/15/2016 12:00,CAPE,2123.021,2258,1954.9,2085.106,2155.768,18,k
9/14/2016 18:00,9/15/2016 18:00,CAPE,2079.35,2397.08,1745.22,2011.772,2135.195,18,k
9/14/2016 18:00,9/14/2016 18:00,WSPD,10.30410353,11.91721456,8.248297085,9.838215725,10.75774552,18,k
9/14/2016 18:00,9/15/2016 0:00,WSPD,10.9400117,12.43605914,9.573964769,10.59848982,11.28932813,18,k
9/14/2016 18:00,9/15/2016 6:00,WSPD,11.46127399,12.81606087,10.4988286,11.2154979,11.73633011,18,k
9/14/2016 18:00,9/15/2016 12:00,WSPD,11.17043143,12.43677466,9.707966369,10.84331329,11.49746871,18,k
9/14/2016 18:00,9/15/2016 18:00,WSPD,9.871976672,11.04788095,8.228105178,9.523215227,10.15348249,18,k

Since your plan isn't feasible, what are your alternatives? You could produce multiple graphs. Thankfully, plotly allows for dynamic callbacks:

import dash
import pandas as pd
import plotly.express as px
from dash import dcc, html
from dash.dependencies import Input, Output


df = pd.read_csv('values.csv')
df.astype({
    'run_time': 'datetime64',
    'forecast_time': 'datetime64',
    'parameter': 'string',
    'mean': 'float64',
    'max': 'float64',
    'min': 'float64',
    'ci_low': 'float64',
    'ci_high': 'float64',
    'r_hour': 'int64',
    'loc': 'string'
})
PS = list(df["parameter"].unique())


app = dash.Dash(__name__)
app.layout = html.Div(
    [
        dcc.Dropdown(
            id="location",
            options=[{'label': 'K', 'value': 'k'},
                     {'label': 'W', 'value': 'w'}],
            value='w',
            placeholder='Select a location',
        ),
        dcc.Dropdown(
            id="r_hour",
            options=[{'label': '00Z', 'value': 0},
                     {'label': '06Z', 'value': 6},
                     {'label': '12Z', 'value': 12},
                     {'label': '18Z', 'value': 18}],
            value='12',
            placeholder="Select a forecast time",
        ),
        dcc.Dropdown(
            id="parameter",
            options=[{"label": p, "value": p} for p in PS],
            placeholder='Select a parameter',
            value='CAPE',
            multi=True
        ),
        *[dcc.Graph(id=p, figure={}, style={'display': 'none'}) for p in PS]
    ]
)


@app.callback(
    [Output(p, 'figure') for p in PS],
    [Output(p, 'style') for p in PS],
    Input("location", "value"),
    Input("r_hour", "value"),
    Input('parameter', 'value')
)
def update_graph1(loc, r_hour, parameter):
    if loc is None or r_hour is None or parameter is None:
        return dash.no_update

    parameter = parameter if isinstance(parameter, list) else [parameter]
    dff = df[(df['loc'] == loc) & (df['r_hour'] == int(r_hour)) & (df['parameter'].isin(parameter))]

    figures = [{} for _ in range(len(PS))]
    styles = [{'display': 'none'} for _ in range(len(PS))]

    for p in parameter:
        pi = PS.index(p)
        figures[pi] = px.scatter(
            dff[dff['parameter'] == p],
            x='forecast_time', y=['mean', 'max', 'min', 'ci_low', 'ci_high']
        )
        styles[pi]['display'] = 'block'

    return *figures, *styles


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

Here's the result:

enter image description here

Explanation

I create a dcc.Graph for every unique parameter and set its display style to none on default. I use the parameter as an ID to determine the index of the graph in the list of unique paramters, but you could just aswell create a mapping for that.

Then, I create a callback for each Graph figure and for each Graph style with the list comprehensions you can see. In the function, I filter the data, create default figures (empty) and styles (hidden), and for each user-selected parameter, I create a real figure and set its display style to block, which turns it visible.

The * operator I use in various places is to unpack a collection. E.g. [1, 2, 3, *[4, 5]] -> [1, 2, 3, 4, 5]

Upvotes: 2

Related Questions