Replacing an empty graph with a message

If a user query results in no data, instead of showing the following empty set of axes as pasted below, I’d like to show an error message.

Currently the callback is something like app.callback(Output('tofu-chart', 'figure'), [Input('page-state', 'children')].

Is the only way to do this to make the output of my callback be a Div into which I insert a figure myself?

1 Like

If you want to keep the dcc.Graph around, you could do this with layout.annotations:

return {
    "layout": {
        "xaxis": {
            "visible": false
        },
        "yaxis": {
            "visible": false
        },
        "annotations": [
            {
                "text": "No matching data found",
                "xref": "paper",
                "yref": "paper",
                "showarrow": false,
                "font": {
                    "size": 28
                }
            }
        ]
    }
}

Makes this graph:

5 Likes

HI Alex. How can add this annotatios in python?

Example:

if data:
fig.add_trace(go.Scatter(x=fechaDoas, y=d1, marker_color=‘white’),
row=7, col=1)
else:
showanotation in this subplot

Thank you in advance

Check out https://plot.ly/python/text-and-annotations/#simple-annotation

To get the annotation into that specific subplot you’ll need to either use xref and yref to match the x/y axis ids you have at row=7, col=1 (if you want the annotation positioned in data coordinates) or xref='paper', yref='paper' and find the x/y locations (as fraction of the plot area) matching that location in the plot. I actually don’t know if we have any facilities in the Python library to help find those references or locations based on row and col - @nicolaskruchten?

add_annotation() supports row and col… does that meet your needs @alexcjohnson ?

Ah nice, I wasn’t able to find that in the docs but that’s great! Does that just set xref/yref to the subplot at that location (for data-referenced annotations), or would it also do something useful for positioning paper-referenced annotations within that grid cell?

row/col is used to target xref/yref automatically (for figures created with make_subplots only! including px). It’s not as good at targeting paper coordinates just yet IIRC.

Wow! thank u very much

I use this simple scrip on every graph I made, and I get a simple message.

    fig_none = go.Figure()
    fig_none.add_trace(go.Scatter(
    x=[0, 1, 2, 3, 4, 5, 6, 7, 8, 10],
    y=[0, 4, 5, 1, 2, 3, 2, 4, 2, 1],
    mode="lines+markers+text",
    text=["","","","", "SIN DATOS", "","","", "", ''],
    textfont_size=40,
    ))
    fig_none.update_layout(
        paper_bgcolor=background,
        plot_bgcolor=background      
    )
    fig_none.update_layout(
        xaxis = dict(
            showgrid=False,
            gridcolor=background,
            zerolinecolor=background),
        yaxis = dict(
            showgrid=False,
            gridcolor=background,
            zerolinecolor=background))
    try:
        read_cube_orig = pd.read_csv(make_cube,
                            sep=',',
                            header=None,
                            usecols=[0,1,2,3],
                            names=['X', 'Y', 'Z','DATA']
                                )
        read_cube = read_cube_orig #.round(0)
    except FileNotFoundError:
        return fig_none

You can try to adapt this script to your graph. What I do is:

  • I try to read the data, but if I get the ‘‘FileNotFoundError’’ (or any error you have), I plot the fig_none graph.

Thanks for the great tip @alexcjohnson. Here is a simple example:

def plot_data(v, m):
    if venue is not None and market is not None:
        df = pd.DataFrame({
            "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
            "Amount": [4, 1, 2, 2, 4, 5],
            "City": ["1", "2", "3", "Montreal", "Montreal", "Montreal"]
        })
        fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
    else:
        fig = go.Figure()
        fig.update_layout(
            xaxis =  { "visible": False },
            yaxis = { "visible": False },
            annotations = [
                {   
                    "text": "Please select v and m",
                    "xref": "paper",
                    "yref": "paper",
                    "showarrow": False,
                    "font": {
                        "size": 28
                    }
                }
            ]
        )

    return fig
1 Like

Hi Alex
I am new to plotly dash and I don’t really understand where to add this piece of code.
Could you please give an example.

Below is how I am plotting my figure:

fig = px.scatter(df_plot[‘status_count’]).update_traces(mode=‘lines+markers’)
fig.add_bar(x=df_plot.index, y=df_plot[‘status_count’], name=“Active Sellers”, marker_color=‘rgb(255,204,0)’)

fig.update_layout(
    {
        'yaxis': {'title': 'No of Active Sellers'},
        'xaxis': dict(title='Months',
                      tickmode='array',
                      tickvals=df_plot.index,
                      ticktext=df_plot.index
                      ),
        'margin': dict(l=10, r=10, t=60, b=10)
    },
    showlegend=False,
    height=250
    # plot_bgcolor='rgb(204,255,255)'
)

@cankav shows the pattern well: check whether you have the prerequisites to make your chart, if so show it; if not show the placeholder. If all you care about is “are there rows in the data set” it could be something like:

if len(df):
    fig = px.scatter(df_plot[‘status_count’]).update_traces(mode=‘lines+markers’)
    (etc, the rest of your code)
else:
    fig = go.Figure()
    fig.update_layout( ... blank plot with annotation)

return fig
1 Like

thanks @alexcjohnson, @cankav

Another options would be to use a Skeleton component,

3 Likes