Int type X-Axis with Dropdown Filter

I have a bar chart visual with years on the x-axis and dollars on the y-axis, and a dropdown for fundraising years that filters the bar chart. Filtering works, except for the fact that if I filter off a year in the middle of the range, the year remains in the bar chart x-axis (second screenshot).

How would the code need to be adjusted to have the filtered off year removed from the x-axis? I narrowed it down to the fact that the year is of type int. If I convert everything to str, it works correctly. My assumption is that this is the result of how Dash filters for int values, and the lack of contains support. Is that accurate or would it be possible to get this to work with int types?

My versions and code are below. Here are screenshots of what is occurring with the visual.

Thanks for any assistance.

Unfiltered Visual


Middle Year Filtered Visual (x-axis value NOT removed)

Two Year Filter (it correctly only shows the 2 years on the x-axis

Dash Version: 2.14.2
DCC version: 2.12.1
HTML version: 2.0.15
Dash Table version: 5.2.8
Plotly version: 5.18.0

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

fundraising_dataframe = pd.read_csv(
    os.path.join(os.path.dirname(__file__), "../../data/DonorData.csv")
)


def render(app: Dash) -> html.Div:
    @app.callback(
        Output(ids.BAR_CHART, "children"),
        [
            Input(ids.FUNDRAISING_TYPE_DROPDOWN, "value"),
            Input(ids.FUNDRAISING_YEAR_DROPDOWN, "value"),
        ],
    )
    def update_bar_chart(
        fundraising_type: list[str], fundraising_year: list[int]
    ) -> html.Div:
        fundraising_dataframe_grouped = (
            fundraising_dataframe.groupby(["FundraisingYear", "FundraisingType"])
            .agg(TotalPledge=("Pledge", "sum"))
            .reset_index()
        )

        filtered_data = fundraising_dataframe_grouped.query(
            "FundraisingType in @fundraising_type and FundraisingYear in @fundraising_year"
        )

        if filtered_data.shape[0] == 0:
            return html.Div("No data selected")

        fig = px.bar(
            filtered_data,
            x="FundraisingYear",
            y="TotalPledge",
            color="FundraisingType",
            text="FundraisingType",
            barmode="group",  #'group' puts the bars next to each other rather than in one bar
            color_discrete_sequence=px.colors.sequential.Bluyl,  # You can choose a different color scale from Plotly's library
            category_orders={
                "FundraisingType": filtered_data.groupby("FundraisingType")[
                    "TotalPledge"
                ]
                .sum()
                .sort_values(ascending=False)
                .index
            },
        )

        return html.Div(dcc.Graph(figure=fig), id=ids.BAR_CHART)

    return html.Div(id=ids.BAR_CHART)

Hi @songmak welcome to the forums an thanks for such a well redacted first post.

You’re right, what you see there is due to the use of a time X-axis. Plotly reserves the space on the axis for the missing years. By converting to string, you are using a categorical axis. If you convert to int, you are using a numeric axis.

Actually, if you converted to int, the behaviour should be the same as for the time axis.

So in my opinion, converting to string is the easiest way to achieve what you are after.

Great! Thanks for confirming and the recommendation.

1 Like