Search code examples
pythonplotly

Plotly: auto resize height


I am creating a bar graph using plotly express inside dash application. The graph is getting displayed but I am having an issue with height.Currently I am using default height and width.

Now for eg:

  1. dataframe having field column contain 3 entires, the graph looks ok.

  2. dataframe having field column contain 10 entires, the bar width is reduced auto and height remains the same and graph looks congested and hard to read.

figure = (
    px.bar(
        data_frame=dataframe,
        x="size",
        y="field",
        title="Memory Usage",
        text="size",
        # width=400,
        # height=400,
        orientation="h",
        labels={"size": "size in byte(s)"},
        template=template,
    ).update_traces(width=0.4)
    .update_layout(autosize=True)
)
        
dcc.Graph(id="memory_bar", figure=figure, className="dbc")

Is it possible depending on number of entires, the height can be auto-resized? Also I am using orient as horrizontal. I tried autosize=true but got no effect on height it remains same.


Solution

  • It is possible to define a dynamic width and height based on the dataframe:

    • The number of categories can be found with dataframe['field'].nunique() (assuming you are using pandas). It will impact the height of the figure (since the bar chart is horizontal)
    • The number of entries can be found with dataframe.shape[0] and will impact the width of the figure. You could be more precise if you use dataframe.groupby("field").count()["size"].max() instead. It returns the maximum entry per category.

    Then, we can define two methods for computing height and width of the figure:

    def num_fields_based_height(num_fields: int) -> int:
        padding = 150 # arbitrary value depending on legends
        row_size = 100 # arbitrary value
        return padding + row_size * num_fields
    
    def num_entries_based_width(num_entries: int) -> int:
        padding = 150 # arbitrary value depending on legends
        entry_size = 100 # arbitrary value
        return padding + entry_size * num_entries
    

    Then call this methods when declaring the figure:

    figure = (
        px.bar(
            data_frame=dataframe,
            x="size",
            y="field",
            title="Memory Usage",
            text="size",
            width=num_entries_based_width(dataframe.shape[0]),
            height=num_fields_based_height(dataframe['field'].nunique()),
            orientation="h",
            labels={"size": "size in byte(s)"},
        )
    )
    

    Now you need to find the right parameters (padding, entry_size, row_size) for your scenario.