Component Registration in self.callback_map KeyError : '.figure'

Hello,

So I use Dash App with Django (Django Plotly Dash) and want to deploy to Heroku.

When I am running in local, I am getting this error, but still displays graph. When I deploy to Heroku, it won’t show anything.

In local:


In heroku:

When I want to delete old output component or want to add a new one, it gives keyerror. It’s in the self.callback_map[target_id][‘inputs’], even when what I change is the Output.

"for component_registration in self.callback_map[target_id][‘inputs’]:
KeyError: ‘grafik_jlh_sekolah.figure’"

So I have
@app.callback(
[Output(component_id=‘output_container’, component_property=‘children’),
Output(component_id=‘grafik_jlh_sekolah’, component_property=‘figure’)],
[Input(component_id=‘select_filter’, component_property=‘value’),
Input(component_id=‘dropdown_provinsi’, component_property=‘value’),
Input(component_id=‘dropdown_kokab’, component_property=‘value’),
Input(component_id=‘dropdown_kec’, component_property=‘value’)]
)

and I want to remove the first output (Output(component_id=‘output_container’))

Also, I want to add a new callback
@app.callback(
[Output(component_id=‘choropleth_sekolah’, component_property=‘figure’)],
[Input(component_id=‘radio_button_choropleth’, component_property=‘value’)]
)

But then, it will give me error
"for component_registration in self.callback_map[target_id][‘inputs’]:
KeyError: ‘choropleth_sekolah.figure’"

My problem is similar to case 14207. But it’s not working for me. I have searched google and try to debug but still unable to solve the problem. Please help.

Thank you so much :smiley:

This is the fullcode. I give ************** sign to highlight which part that causes the problem.

import pandas as pd
import numpy as np
import json

import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go

from dash.dependencies import Input, Output
from django_plotly_dash import DjangoDash
from django.db.models import Count

from schools.models import Provinsi, KotaKab, Kecamatan, Kelurahan

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css', dbc.themes.BOOTSTRAP]

app = DjangoDash('VisualisasiStatistikSekolah', external_stylesheets=external_stylesheets)

# ------------------------------------------------------------------------------
# Import and clean data
# print('kepanggil')

global data_provinsi, data_kokab, data_kec, data_kel, df_choropleth, geodata
data_provinsi = pd.DataFrame.from_records(Provinsi.objects.values('id', 'nama', 'institusi__sekolah__tingkat_sekolah__teks').annotate(Count('institusi__sekolah')).order_by('nama')).rename(
    columns={
        'institusi__sekolah__count': 'jumlah_sekolah',
        'institusi__sekolah__tingkat_sekolah__teks': 'tingkat_sekolah'
    }
)

data_kokab = pd.DataFrame.from_records(KotaKab.objects.values('id', 'provinsi_id', 'nama', 'institusi__sekolah__tingkat_sekolah__teks').annotate(Count('institusi__sekolah')).order_by('nama')).rename(
    columns={
        'institusi__sekolah__count': 'jumlah_sekolah',
        'institusi__sekolah__tingkat_sekolah__teks': 'tingkat_sekolah'
    }
)
data_kec = pd.DataFrame.from_records(Kecamatan.objects.values('id', 'kokab_id', 'nama', 'institusi__sekolah__tingkat_sekolah__teks').annotate(Count('institusi__sekolah')).order_by('nama')).rename(
    columns={
        'institusi__sekolah__count': 'jumlah_sekolah',
        'institusi__sekolah__tingkat_sekolah__teks': 'tingkat_sekolah'
    }
)
data_kel = pd.DataFrame.from_records(Kelurahan.objects.values('id', 'kecamatan_id', 'nama', 'institusi__sekolah__tingkat_sekolah__teks').annotate(Count('institusi__sekolah')).order_by('nama')).rename(
    columns={
        'institusi__sekolah__count': 'jumlah_sekolah',
        'institusi__sekolah__tingkat_sekolah__teks': 'tingkat_sekolah'
    }
)

with open('./dashboard/geodata/IDN_adm_1_province.json') as f:
    geodata = json.load(f)

df_choropleth = data_provinsi.groupby(['nama']).sum().reset_index()


def get_sekolah_nasional():
    df_jumlah_sekolah = data_provinsi.groupby(['tingkat_sekolah']).sum().reset_index()

    custom_dict = {'SD': 0, 'SMP': 1, 'SMA': 2}
    df_jumlah_sekolah.sort_values(by=['tingkat_sekolah'], key=lambda x: x.map(custom_dict), inplace=True)
    return df_jumlah_sekolah


def get_axis_data(df_sekolah_per_wilayah):
    data = df_sekolah_per_wilayah.fillna('tmp').groupby(['nama', 'tingkat_sekolah']).sum().reset_index().replace('tmp', np.nan)

    x = data['nama'].unique()
    y_sd = data.fillna('SD').groupby(['nama', 'tingkat_sekolah']).sum().reset_index()
    y_smp = data.fillna('SMP').groupby(['nama', 'tingkat_sekolah']).sum().reset_index()
    y_sma = data.fillna('SMA').groupby(['nama', 'tingkat_sekolah']).sum().reset_index()

    y_sd = y_sd['jumlah_sekolah'].loc[y_sd['tingkat_sekolah'] == 'SD'].tolist()
    y_smp = y_smp['jumlah_sekolah'].loc[y_smp['tingkat_sekolah'] == 'SMP'].tolist()
    y_sma = y_sma['jumlah_sekolah'].loc[y_sma['tingkat_sekolah'] == 'SMA'].tolist()

    return x, y_sd, y_smp, y_sma


def get_choropleth_data(tingkat_sekolah):
    data_choropleth = data_provinsi.fillna(tingkat_sekolah)
    data_choropleth = data_choropleth.loc[data_choropleth['tingkat_sekolah'] == tingkat_sekolah].groupby(['nama']).sum().reset_index()
    return data_choropleth

# ------------------------------------------------------------------------------
# App layout


app.layout = html.Div([
    dcc.Tabs([
        dbc.Tab(label='Grafik Batang', children=[
            dbc.Container([
                dcc.Loading([
                    dbc.Row([
                        html.Div([
                            html.Label(['Tampilkan data per:',
                                        dcc.Dropdown(id='select_filter',
                                                        options=[
                                                            {'label': 'Nasional', 'value': 'Nasional'},
                                                            {'label': 'Provinsi', 'value': 'Provinsi'},
                                                            {'label': 'Kota / Kabupaten', 'value': 'Kota / Kabupaten'},
                                                            {'label': 'Kecamatan', 'value': 'Kecamatan'},
                                                            {'label': 'Kelurahan', 'value': 'Kelurahan'}],
                                                        multi=False,
                                                        clearable=False,
                                                        value='Nasional',
                                                        placeholder='Pilih wilayah',
                                                        style={'font-weight': 'normal'})]),
                        ], style={'width': '165px'}),

                        html.Div([
                            html.Label(id='select_provinsi',
                                    children=['Pilih Provinsi:',
                                                dcc.Dropdown(id='dropdown_provinsi',
                                                            multi=False,
                                                            clearable=False,
                                                            placeholder='Pilih Provinsi',
                                                            value=None,
                                                            disabled=True,
                                                            style={'font-weight': 'normal'})]),
                        ], style={'width': '300px'}),

                        html.Div([
                            html.Label(id='select_kokab',
                                    children=['Pilih Kota / Kabupaten:',
                                                dcc.Dropdown(id='dropdown_kokab',
                                                            multi=False,
                                                            clearable=False,
                                                            placeholder='Pilih Kota / Kabupaten',
                                                            value=None,
                                                            disabled=True,
                                                            style={'font-weight': 'normal'})]),
                        ], style={'width': '300px'}),

                        html.Div([
                            html.Label(id='select_kecamatan',
                                    children=['Pilih Kecamatan:',
                                                dcc.Dropdown(id='dropdown_kec',
                                                            multi=False,
                                                            clearable=False,
                                                            placeholder='Pilih Kecamatan:',
                                                            value=None,
                                                            disabled=True,
                                                            style={'font-weight': 'normal'})]),
                        ], style={'width': '300px'}),
                    ],
                        style={'display': 'flex', 'justify-content': 'space-evenly', 'padding': '20px'})
                ], type='default', color='#EAC763'),
                
                html.Br(),
*******html.Div(id='output_container', children=[]),******************** # what I want to remove

            ], style={'background': 'white',
                    'border-radius': '5px',
                    'border': '1px solid #BEC2C4',
                    'box-shadow': '3px 3px 5px #EAC763',
                    'width': '1200px',
                    'height': '100px',
                    'margin-top': '20px'}
            ),

            html.Br(),

            dbc.Container([
                dcc.Loading([
                    dbc.Col([
                        html.Div([
**************dcc.Graph(id='grafik_jlh_sekolah', figure={},****************
                                    style={'backgroundColor': '#1a2d46', 'color': '#ffffff'}),
                        ],
                            style={'padding': '10px'}),
                    ],
                        style={'background': 'white',
                            'border-radius': '5px',
                            'border': '1px solid #BEC2C4',
                            'box-shadow': '3px 3px 5px #EAC763',
                            'width': '1200px',
                            'height': '500px'}
                    )
                ], type='graph', color='#EAC763')
            ])
        ]),

        dbc.Tab(label='Peta Choropleth', children=[
            dbc.Container([
                dbc.Row([
                    dbc.Col([
                        dcc.RadioItems(id='radio_button_choropleth',
                                       options=[{'label': 'Semua Tingkat', 'value': 'Semua Tingkat'},
                                                {'label': 'SD', 'value': 'SD'},
                                                {'label': 'SMP', 'value': 'SMP'},
                                                {'label': 'SMA', 'value': 'SMA'}],
                                       value='Semua Tingkat',
                                       labelStyle={'display': 'block', 'padding': '5px'},
                        )],
                        style={'display': 'flex', 'align-items': 'center', 'margin-left': '50px'}
                    ),

                    dbc.Col([
***********dcc.Graph(id='choropleth_sekolah',****************     # what I want to add
                                  figure=dict(data=[go.Choropleth(geojson=geodata,
                                                                  locations=df_choropleth.nama,
                                                                  z=df_choropleth.jumlah_sekolah,
                                                                  featureidkey='properties.NAME_1',
                                                                  marker_line_color='black',
                                                                  colorscale='YlGnBu',
                                                                  colorbar_title='<b>Jumlah Sekolah<b>')],
                                              layout=go.Layout(title='<b>Peta Persebaran Jumlah Sekolah</b>',
                                                               font=dict(color='black',
                                                                         family='Nunito, sans-serif'),
                                                               geo_scope='asia',
                                                               geo_projection_scale=3,
                                                               geo_center_lat=0,
                                                               geo_center_lon=118,
                                                               margin={"r": 5, "t": 100, "l": 5, "b": 50}))
                        ),
                    ], style={'flex-grow': '1'}),
                ],
                    style={'background': 'white',
                        'border-radius': '5px',
                        'border': '1px solid #BEC2C4',
                        'box-shadow': '3px 3px 5px #EAC763',
                        'width': '1200px',
                        'height': '450px',
                        'margin-top': '20px',
                        'display': 'flex',
                        'justify-content': 'space-between'}
                )
            ])
        ]),
    ])], style={'font-family': 'Nunito, sans-serif', 'font-weight': 'bold'}
)

# ------------------------------------------------------------------------------
# Connect the Plotly graphs with Dash Components


@app.callback(
    [Output(component_id='dropdown_provinsi', component_property='options'),
     Output(component_id='dropdown_provinsi', component_property='value'),
     Output(component_id='dropdown_provinsi', component_property='disabled')],
    [Input(component_id='select_filter', component_property='value')]
)
def update_dropdown_provinsi(selected_filter):
    disabled = True
    pilihan_provinsi = []
    default_value = None

    if (selected_filter != 'Nasional') and (selected_filter != 'Provinsi'):
        pilihan_provinsi = []
        daftar_provinsi = data_provinsi.drop_duplicates(subset='id', keep='first').reset_index()
        default_value = '31'
        disabled = False

        for provinsi in daftar_provinsi.itertuples():
            pilihan_provinsi.append({'label': provinsi.nama, 'value': provinsi.id})

    return pilihan_provinsi, default_value, disabled


@app.callback(
    [Output(component_id='dropdown_kokab', component_property='options'),
     Output(component_id='dropdown_kokab', component_property='value'),
     Output(component_id='dropdown_kokab', component_property='disabled')],
    [Input(component_id='select_filter', component_property='value'),
     Input(component_id='dropdown_provinsi', component_property='value')]
)
def update_dropdown_kokab(selected_filter, selected_provinsi):
    disabled = True
    pilihan_kokab = []
    default_value = None

    if (selected_filter == 'Kecamatan') or (selected_filter == 'Kelurahan'):
        pilihan_kokab = []
        daftar_kokab = data_kokab.loc[data_kokab['provinsi_id'] == selected_provinsi].drop_duplicates(subset='id', keep='first').reset_index()
        default_value = daftar_kokab['id'][0]
        disabled = False

        for kokab in daftar_kokab.itertuples():
            pilihan_kokab.append({'label': kokab.nama, 'value': kokab.id})

    return pilihan_kokab, default_value, disabled


@app.callback(
    [Output(component_id='dropdown_kec', component_property='options'),
     Output(component_id='dropdown_kec', component_property='value'),
     Output(component_id='dropdown_kec', component_property='disabled')],
    [Input(component_id='select_filter', component_property='value'),
     Input(component_id='dropdown_kokab', component_property='value')]
)
def update_dropdown_kec(selected_filter, selected_kokab):
    disabled = True
    pilihan_kecamatan = []
    default_value = None

    if (selected_filter == 'Kelurahan'):
        pilihan_kecamatan = []
        daftar_kecamatan = data_kec.loc[data_kec['kokab_id'] == selected_kokab].drop_duplicates(subset='id', keep='first').reset_index()
        default_value = daftar_kecamatan['id'][0]
        disabled = False

        for kecamatan in daftar_kecamatan.itertuples():
            pilihan_kecamatan.append({'label': kecamatan.nama, 'value': kecamatan.id})

    return pilihan_kecamatan, default_value, disabled

**************
@app.callback(
    [Output(component_id='output_container', component_property='children'), # what I want to remove
     Output(component_id='grafik_jlh_sekolah', component_property='figure')],
    [Input(component_id='select_filter', component_property='value'),
     Input(component_id='dropdown_provinsi', component_property='value'),
     Input(component_id='dropdown_kokab', component_property='value'),
     Input(component_id='dropdown_kec', component_property='value')]
)**************
def update_graph(selected_filter, selected_provinsi, selected_kokab, selected_kec):
    children = 'Filter yang dipilih: {}'.format(selected_filter)
    figure = go.Figure()
    figure.update_layout(
        paper_bgcolor='white',
        plot_bgcolor='rgba(0,0,0,0)',
        font=dict(color='black',
                  family='Nunito, sans-serif'),
        xaxis={'showgrid': False, 'title': '<b>' + selected_filter + '</b>', 'automargin': True},
        yaxis={'showgrid': False, 'tickformat': ',d', 'automargin': True},
        barmode='group',
        title={
            'text': '<b>JUMLAH SEKOLAH DI TINGKAT NASIONAL</b>',
            'y': 0.9,
            'x': 0.5,
            'xanchor': 'center',
            'yanchor': 'top'},
        uniformtext_minsize=8,
        uniformtext_mode='hide'
    )

    # Plotly Go
    if selected_filter == 'Nasional':
        data = get_sekolah_nasional()

        figure.add_trace(
            go.Bar(
                x=data['tingkat_sekolah'],
                y=data['jumlah_sekolah'],
                marker_color='#EAC763',
                text=data['jumlah_sekolah'],
                textposition='auto',
                name='Grafik Jumlah Sekolah',
            )
        )

    elif selected_filter == 'Provinsi':
        x, y_sd, y_smp, y_sma = get_axis_data(data_provinsi)

        figure.add_trace(
            go.Bar(
                x=x,
                y=y_sd,
                marker_color='#942B25',
                text=y_sd,
                textposition='auto',
                name='SD',
            )
        )

        figure.add_trace(
            go.Bar(
                x=x,
                y=y_smp,
                marker_color='#081E43',
                text=y_smp,
                textposition='auto',
                name='SMP',
            )
        )

        figure.add_trace(
            go.Bar(
                x=x,
                y=y_sma,
                marker_color='#566D8D',
                text=y_sma,
                textposition='auto',
                name='SMA',
            )
        )

        figure.update_layout(title_text='<b>JUMLAH SEKOLAH PER PROVINSI</b>', xaxis={'tickangle': 45},)

    elif selected_filter == 'Kota / Kabupaten':
        nama_provinsi = data_provinsi.loc[data_provinsi['id'] == selected_provinsi]['nama'].unique()[0]
        x, y_sd, y_smp, y_sma = get_axis_data(data_kokab.loc[data_kokab['provinsi_id'] == selected_provinsi])

        if set(y_sd) == {0} and set(y_smp) == {0} and set(y_sma) == {0}:
            figure.update_layout(
                xaxis={'visible': False},
                yaxis={'visible': False},
                annotations=[dict(
                    text='Tidak ada sekolah<br>yang mengikuti NGTS<br>di wilayah ini',
                    xref='paper',
                    yref='paper',
                    showarrow=False,
                    font={'size': 28, 'color': '#786630'}
                )]
            )
        else:
            figure.add_trace(
                go.Bar(
                    x=x,
                    y=y_sd,
                    marker_color='#942B25',
                    text=y_sd,
                    textposition='auto',
                    name='SD',
                )
            )

            figure.add_trace(
                go.Bar(
                    x=x,
                    y=y_smp,
                    marker_color='#081E43',
                    text=y_smp,
                    textposition='auto',
                    name='SMP',
                )
            )

            figure.add_trace(
                go.Bar(
                    x=x,
                    y=y_sma,
                    marker_color='#566D8D',
                    text=y_sma,
                    textposition='auto',
                    name='SMA',
                )
            )

        figure.update_layout(title_text='<b>JUMLAH SEKOLAH PER KOTA / KABUPATEN<br>DI PROVINSI </b><b>' + nama_provinsi.upper() + '</b>')

    elif selected_filter == 'Kecamatan':
        nama_kokab = data_kokab.loc[data_kokab['id'] == selected_kokab]['nama'].unique()[0]
        x, y_sd, y_smp, y_sma = get_axis_data(data_kec.loc[data_kec['kokab_id'] == selected_kokab])

        if set(y_sd) == {0} and set(y_smp) == {0} and set(y_sma) == {0}:
            figure.update_layout(
                xaxis={'visible': False},
                yaxis={'visible': False},
                annotations=[dict(
                    text='Tidak ada sekolah<br>yang mengikuti NGTS<br>di wilayah ini',
                    xref='paper',
                    yref='paper',
                    showarrow=False,
                    font={'size': 28, 'color': '#786630'}
                )]
            )
        else:
            figure.add_trace(
                go.Bar(
                    x=x,
                    y=y_sd,
                    marker_color='#942B25',
                    text=y_sd,
                    textposition='auto',
                    name='SD',
                )
            )

            figure.add_trace(
                go.Bar(
                    x=x,
                    y=y_smp,
                    marker_color='#081E43',
                    text=y_smp,
                    textposition='auto',
                    name='SMP',
                )
            )

            figure.add_trace(
                go.Bar(
                    x=x,
                    y=y_sma,
                    marker_color='#566D8D',
                    text=y_sma,
                    textposition='auto',
                    name='SMA',
                )
            )

        figure.update_layout(title_text='<b>JUMLAH SEKOLAH PER KECAMATAN<br>DI </b><b>' + nama_kokab.upper() + '</b>')

    else:
        nama_kec = data_kec.loc[data_kec['id'] == selected_kec]['nama'].unique()[0]
        x, y_sd, y_smp, y_sma = get_axis_data(data_kel.loc[data_kel['kecamatan_id'] == selected_kec])

        if set(y_sd) == {0} and set(y_smp) == {0} and set(y_sma) == {0}:
            figure.update_layout(
                xaxis={'visible': False},
                yaxis={'visible': False},
                annotations=[dict(
                    text='Tidak ada sekolah<br>yang mengikuti NGTS<br>di wilayah ini',
                    xref='paper',
                    yref='paper',
                    showarrow=False,
                    font={'size': 28, 'color': '#786630'}
                )]
            )
        else:
            figure.add_trace(
                go.Bar(
                    x=x,
                    y=y_sd,
                    marker_color='#942B25',
                    text=y_sd,
                    textposition='auto',
                    name='SD',
                )
            )

            figure.add_trace(
                go.Bar(
                    x=x,
                    y=y_smp,
                    marker_color='#081E43',
                    text=y_smp,
                    textposition='auto',
                    name='SMP',
                )
            )

            figure.add_trace(
                go.Bar(
                    x=x,
                    y=y_sma,
                    marker_color='#566D8D',
                    text=y_sma,
                    textposition='auto',
                    name='SMA',
                )
            )

        figure.update_layout(title_text='<b>JUMLAH SEKOLAH PER KELURAHAN<br>DI KECAMATAN </b><b>' + nama_kec.upper() + '</b>')

    return children, figure

**************
@app.callback(
    [Output(component_id='choropleth_sekolah', component_property='figure')],   # what I want to add
    [Input(component_id='radio_button_choropleth', component_property='value')]
)**************
def update_choropleth(selected_button):
    # print(selected_button)

    figure = go.Figure()
    figure.update_layout(
        title='<b>Peta Persebaran Jumlah Sekolah</b>',
        font=dict(color='black',
                  family='Nunito, sans-serif'),
        geo_scope='asia',
        geo_projection_scale=3,
        geo_center_lat=0,
        geo_center_lon=118,
        margin={"r": 5, "t": 100, "l": 5, "b": 50}
    )

    if selected_button == 'Semua Tingkat':
        figure.add_trace(
            go.Choropleth(
                geojson=geodata,
                locations=df_choropleth.nama,
                z=df_choropleth.jumlah_sekolah,
                featureidkey='properties.NAME_1',
                marker_line_color='black',
                colorscale='YlGnBu',
                colorbar_title='<b>Jumlah Sekolah<b>'
            )
        )

    elif selected_button == 'SD':
        data_choropleth = get_choropleth_data('SD')
        # print(data_choropleth)

        figure.add_trace(
            go.Choropleth(
                geojson=geodata,
                locations=data_choropleth.nama,
                z=data_choropleth.jumlah_sekolah,
                featureidkey='properties.NAME_1',
                marker_line_color='black',
                colorscale='YlGnBu',
                colorbar_title='<b>Jumlah Sekolah<b>'
            )
        )

    elif selected_button == 'SMP':
        data_choropleth = get_choropleth_data('SMP')
        print(data_choropleth)

        figure.add_trace(
            go.Choropleth(
                geojson=geodata,
                locations=data_choropleth.nama,
                z=data_choropleth.jumlah_sekolah,
                featureidkey='properties.NAME_1',
                marker_line_color='black',
                colorscale='YlGnBu',
                colorbar_title='<b>Jumlah Sekolah<b>'
            )
        )

    else:
        data_choropleth = get_choropleth_data('SMA')
        # print(data_choropleth)

        figure.add_trace(
            go.Choropleth(
                geojson=geodata,
                locations=data_choropleth.nama,
                z=data_choropleth.jumlah_sekolah,
                featureidkey='properties.NAME_1',
                marker_line_color='black',
                colorscale='YlGnBu',
                colorbar_title='<b>Jumlah Sekolah<b>'
            )
        )

    return figure

Heroku problem solved!

The Plotly Dash doesn’t show up because I use AWS S3 to serve my staticfiles.

It turns out that the Plotly staticfiles only appear when there’s a request to load Plotly Dash, so the staticfiles isn’t saved permanently in my static folder.

What I do is copy manually the static file to my AWS S3 bucket.

For, the keyerror, it hasn’t been solved.

I could not run your code but I can make two guesses:

  1. There is some artifact that refers to the removed Output and, since Dash cannot find the Output, it is throwing a KeyError. If you have eliminated all references to the no longer existing Output then:

  2. Make sure that a single Output is not an element of a list. While multiple Outputs have to be included in a list, a single Output list will break and often throw the KeyError.

1 Like

No. 2 solution worked for my case.
I almost discard the feature if this problem were not solved.

Thank you so much!! :grin: