Search code examples
pythonplotly

How to remove the large top and bottom paddings due to top-to-bottom lines?


How to remove the large top and bottom paddings due to top-to-bottom lines?

import numpy as np
import pandas as pd
import plotly.graph_objects as go

count = 100

df = pd.DataFrame(
    {
        "A": np.random.randint(10, 20, size=(count)),
        "B": np.random.randint(10, 20, size=(count)),
        "C": np.random.randint(10, 20, size=(count)),
    },
    index=[f"bar.{i}" for i in range(count)],
)

fig = go.Figure(
    data=[
        go.Bar(
            name=df.columns[0],
            orientation="h",
            y=df.index,
            x=df.iloc[:, 0],
            text=df.iloc[:, 0],
        ),
        go.Bar(
            name=df.columns[1],
            orientation="h",
            y=df.index,
            x=df.iloc[:, 1],
            text=df.iloc[:, 1],
        ),
        go.Scatter(
            name=df.columns[2],
            y=df.index,
            x=df.iloc[:, 2],
            text=df.iloc[:, 2],
        ),
    ],
    layout=dict(
        width=512,
        height=1024,
        margin=dict(l=10, r=10, t=10, b=10),
    ),
)

fig.update_layout(
    xaxis_title=None,
    yaxis_title=None,
    legend_title=None,
    yaxis=dict(
        autorange="reversed",
    ),
)

fig.show()

enter image description here

If I don't draw the line or reduce the data point count from 100 to 10, I can get rid of the large paddings:

enter image description here

enter image description here

If I draw the line left-to-right, there are no large paddings on both sides also:

import numpy as np
import pandas as pd
import plotly.graph_objects as go

count = 100

df = pd.DataFrame(
    {
        "A": np.random.randint(10, 20, size=(count)),
        "B": np.random.randint(10, 20, size=(count)),
        "C": np.random.randint(10, 20, size=(count)),
    },
    index=[f"bar.{i}" for i in range(count)],
)

fig = go.Figure(
    data=[
        go.Bar(
            name=df.columns[0],
            orientation="v",
            x=df.index,
            y=df.iloc[:, 0],
            text=df.iloc[:, 0],
        ),
        go.Bar(
            name=df.columns[1],
            orientation="v",
            x=df.index,
            y=df.iloc[:, 1],
            text=df.iloc[:, 1],
        ),
        go.Scatter(
            name=df.columns[2],
            x=df.index,
            y=df.iloc[:, 2],
            text=df.iloc[:, 2],
        ),
    ],
    layout=dict(
        width=1024,
        height=512,
        margin=dict(l=10, r=10, t=10, b=10),
    ),
)

fig.update_layout(
    xaxis_title=None,
    yaxis_title=None,
    legend_title=None,
    yaxis=dict(
        # autorange="reversed",
    ),
)

fig.show()

enter image description here


Solution

  • I don't know why this happens, and I think it might be a bug. Fortunately you can specify the yaxis range "manually" to fix the issue :

    fig.update_layout(
        xaxis_title=None,
        legend_title=None,
        yaxis=dict(
            title=None,
            range=[len(df), 0]  # (because 1 bar per row, reversed)
        )
    )
    

    output

    Note the yaxis dtick (which sets the step in-between ticks on this axis) equals 2, you might want to change that, and/or add an offset (ie. -1 or +1) to the yaxis min/max.