Eli Turasky
Eli Turasky

Reputation: 1061

Dash app will not plot but doesn't have any errors

I have a nested dictionary that I am trying to plot. The user selects a date, using dcc.SingleDatePicker, which then gets stored using dcc.Store. That date value is used to open and modify files on a server, with the data from the files being saved in a dictionary. Then, the user is able to select several different options to display different types of time series data, which are all keys in the nested dictionary. Here is some sample data:

from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
from pandas import Timestamp
import plotly.graph_objs as go
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import numpy as np
from plotly.subplots import make_subplots
import plotly.express as px
from dash.exceptions import PreventUpdate
import pandas as pd
import numpy as np
from datetime import timedelta
import glob
import datetime as dt


final_dict={'model': {'weight': {'available_crop': {'Temperature': array([[0.23393528, 0.80483263, 0.90419904, 0.66941807, 0.08487945,
            0.16660603, 0.20534141, 0.55365599, 0.93233112, 0.77310289]]),
    'Total Snow': array([[0.36390678, 0.36823791, 0.45548315, 0.74191525, 0.85447262,
            0.81513686, 0.31969021, 0.18464316, 0.73136418, 0.73813535]]),
    'Total Precip': array([[0.49129492, 0.56115172, 0.16307671, 0.55762181, 0.54295637,
            0.04989331, 0.52099107, 0.60878435, 0.93648063, 0.20966815]]),
    'time': DatetimeIndex(['2020-10-06 00:00:00', '2020-10-06 06:00:00',
                   '2020-10-06 12:00:00', '2020-10-06 18:00:00',
                   '2020-10-07 00:00:00', '2020-10-07 06:00:00',
                   '2020-10-07 12:00:00', '2020-10-07 18:00:00',
                   '2020-10-08 00:00:00', '2020-10-08 06:00:00'],
                  dtype='datetime64[ns]', freq='6H'),
    '24H Delta Precip': array([[0.42823413, 0.77462331, 0.8945953 , 0.42222802, 0.5682175 ,
            0.65584275, 0.10777537, 0.79867524, 0.67943749, 0.25435023]]),
    '24H Delta Temp': array([[0.15606615, 0.80767068, 0.86591964, 0.74255143, 0.72830876,
            0.94198463, 0.8370685 , 0.10685995, 0.59854699, 0.33812799]])}}}}


app = JupyterDash(external_stylesheets=[dbc.themes.SLATE])
model_list=['EC ENS', 'EC OP', 'GFS ENS', 'GFS OP']
crop_list=['corn', 'soybeans', 'winterwheat', 'springwheat']
weight_list=['Production', 'Area']
column_list=['Temperature', 'Total Snow', 'Total Precip']

controls = dbc.Card(
    [dcc.Store(id='date_output'),
         dbc.FormGroup([
                dcc.DatePickerSingle(
                    id='my-date-picker-single',
                    min_date_allowed=dt.date(2018, 4, 17),
                    max_date_allowed=dt.date(2020, 10, 6),
                    initial_visible_month=dt.date(2020, 10, 6),
                    date=dt.date(2020, 10, 6)
            ),
        ],
    ),
        dbc.FormGroup(
                dcc.RadioItems(
                    id='hour_radio',
                    options=[{'label': '00z', 'value': '00z'},
                            {'label': '12z', 'value': '12z'}],
                    value='00z',
                    labelStyle={'display': 'inline-block'},
                    inputStyle={"margin-left": "15px","margin-right": "5px"}
                ),
            ),


       dbc.FormGroup(
            [dbc.Label("Model"),
                dcc.Dropdown(
                    id='model_dd',
                    options=[{'label': k, 'value': k} for k in model_list],
                    value=model_list[0],
                    clearable=False
                ),
            ]
        ),
        dbc.FormGroup(
            [dbc.Label("Crop"),
                dcc.Dropdown(
                    id='crop_dd',
                    options=[{'label': i.title(), 'value': i} for i in crop_list],
                    value=crop_list[0],
                    clearable=False
                ),
            ]
        ),           
        dbc.FormGroup(
            [dbc.Label("Weighting"),
                dcc.Dropdown(
                    id='weight_dd',
                    options=[{'label': i, 'value': i} for i in weight_list],
                    value=weight_list[0],
                    clearable=False
                ),
            ]
        ),
        dbc.FormGroup(
            [dbc.Label("Forecast Variable"),
                dcc.Dropdown(
                    id='columns_dd',
                    options=[{'label': i, 'value': i} for i in column_list],
                    value=column_list[0],
                    clearable=False
                ),
            ]
        ),
         dbc.FormGroup(
                dcc.RadioItems(
                    id='units_radio',
                    options=[{'label': 'Metric', 'value': 'Metric'},
                            {'label': 'Imperial', 'value': 'Imperial'}],
                    value='Metric',
                    labelStyle={'display': 'inline-block'},
                    inputStyle={"margin-left": "20px","margin-right": "5px"}
                ),
        ),

    ],
    body=True,
)


app.layout = dbc.Container(
    [
        html.Hr(),
        dbc.Row([
            dbc.Col([
                dbc.Row([
                    dbc.Col(controls)
                ],  align="start"), 
            ],xs = 2)
            ,
            dbc.Col([
                dbc.Row([
                    dbc.Col([html.Div(id = 'plot_title')],)
                ]),
                dbc.Row([
                    dbc.Col(dcc.Graph(id="crop-graph")),
                ]),
                dbc.Row([
                    dbc.Col([html.Div(id = 'date_picker')],)
                ]),
            ])
        ],), 
    ],
    fluid=True,
)



@app.callback(
    Output('date_output', 'data'),
    [Input('my-date-picker-single', 'date'),
     Input('hour_radio', 'value')])
    
    
def update_output(data, radio2):
    if radio2=='00z':
        data = pd.to_datetime(data)
    
    elif radio2=='12z':
        data = pd.to_datetime(data)
        data=data+dt.timedelta(hours=12)
    return data
       
@app.callback(
    Output('crop-graph', 'figure'),
    [Input('model_dd', 'value'),
     Input('weight_dd', 'value'),
     Input('crop_dd', 'value'),
     Input('columns_dd', 'value'),
     Input('units_radio', 'value'),
     Input('date_output', 'data')])
    
def make_graph(model, weight, available_crops, vals, radio, data):
    
    
    date_string = pd.to_datetime(data).strftime('%Y%m%d_%H')
    #use the date object that was stored using dcc.Store to format and modify files from machine. End up with final_dict, which is in form final_dict[model][weight][available_crops][vals] (see sample data above), where vals is a dictionary with each key representing a selection from the column_dd dropdown.

    fig = make_subplots(specs=[[{"secondary_y": True}]])
    
    if radio=='Metric':
        if weight == 'Production':
            
            df_delta_prod_temp = pd.concat([pd.DataFrame(final_dict[model][weight][available_crops]['time'], columns=['time']), pd.DataFrame(final_dict[model][weight][available_crops]['24h Delta Temp'], columns=['24h Delta Temp'])], axis=1).set_index('time').resample('24h').mean().reset_index()
            df_delta_prod_precip = pd.concat([pd.DataFrame(final_dict[model][weight][available_crops]['time'], columns=['time']), pd.DataFrame(final_dict[model][weight][available_crops]['24h Delta Precip'], columns=['24h Delta Precip'])], axis=1).set_index('time').resample('24h').mean().reset_index()

            if vals=='Temperature':
                fig.add_trace(go.Scatter(x=final_dict[model][weight][available_crops]['time'], y=final_dict[model][weight][available_crops][vals]-273,
                                        mode = 'lines', line=dict(color='red', width=4),
                                        hovertemplate='Date: %{x|%d %b %H%M} UTC<br>Temp: %{y:.2f} C<extra></extra>'), secondary_y=True)
                fig.add_trace(go.Bar(x=df_delta_prod_temp['time'],
                                 y=df_delta_prod_temp['24h Delta Temp'],
                                 marker_color = "white", opacity=1,hovertemplate='Date: %{x|%d %b}<br>Delta: %{y:.2f} C<extra></extra>'),
                          secondary_y=False)
                fig.update_yaxes(title_text="<b>Temp (C)<b>", color='red', secondary_y=True)
                fig.update_yaxes(title_text="<b>24hr Forecast Change (C)</b>", secondary_y=False)
    ​print(fig)
    return fig

However, this code doesn't have any errors, but won't plot. Here is the print out of fig

Figure({
    'data': [],
    'layout': {'height': 800,
               'paper_bgcolor': '#272B30',
               'plot_bgcolor': '#272B30',
               'showlegend': False,
               'template': '...',
               'width': 1500,
               'xaxis': {'anchor': 'y', 'domain': [0.0, 0.94]},
               'yaxis': {'anchor': 'x', 'automargin': True, 'domain': [0.0, 1.0], 'showgrid': False, 'zeroline': False},
               'yaxis2': {'anchor': 'x',
                          'automargin': True,
                          'overlaying': 'y',
                          'showgrid': True,
                          'side': 'right',
                          'zeroline': False}}
})

I don't understand why the if statement for vals is not working.

Edit: When printing final_dict[model][weight][available_crops][vals] I get this error:

TypeError: unhashable type: 'dict'

Upvotes: 1

Views: 333

Answers (1)

Sumant Agnihotri
Sumant Agnihotri

Reputation: 522

vals cannot be a dictionary. This is why you are getting the TypeError: unhashable type: 'dict' error when trying to print.

Basically, this does not work because the keys have to be hashable. As a general rule, only immutable objects (strings, integers, floats, frozensets, tuples of immutables) are hashable (though exceptions are possible).

To use a dict as a key you need to turn it into something that may be hashed first. If the dict you wish to use as key consists of only immutable values, you can create a hashable representation of it like this:

key = frozenset(dict_key.items())

Refrence: https://stackoverflow.com/a/13264725/11622114

Upvotes: 1

Related Questions