Dash 应用程序不会绘制但没有任何错误

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

我有一个试图绘制的嵌套字典。用户 select 使用 dcc.SingleDatePicker 设置日期,然后使用 dcc.Store 存储该日期。该日期值用于打开和修改服务器上的文件,文件中的数据保存在字典中。然后,用户可以 select 几个不同的选项来显示不同类型的时间序列数据,这些都是嵌套字典中的键。这是一些示例数据:

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

但是这段代码没有任何错误,但是不会出图。这是 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}}
})

我不明白为什么 valsif 语句不起作用。

编辑:打印时 final_dict[model][weight][available_crops][vals] 我得到这个错误:

TypeError: unhashable type: 'dict'

vals 不能是字典。这就是您在尝试打印时收到 TypeError: unhashable type: 'dict' 错误的原因。

基本上,这不起作用,因为键必须是可散列的。作为一般规则,只有不可变对象(字符串、整数、浮点数、冻结集、不可变元组)是可哈希的(尽管可能存在例外)。

要将 dict 用作​​键,您需要先将其转换为可以进行哈希处理的内容。如果您希望用作键的字典只包含不可变值,您可以像这样创建一个可散列的表示:

key = frozenset(dict_key.items())

参考: