Question

How to plot a line on the second axis over a HORIZONTAL (not VERTICAL) bar chart with Matplotlib?

I know how to plot a line on the second axis over a VERTICAL bar chart.

Now I want the bars HORIZONTAL and the line top-to-bottom, just like the whole chart rotates 90°.

If I simply replace bar with barh, the line is still left-to-right...

Can I do this with Matplotlib?

Here is a sample for VERTICAL bar chart:

import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame(
    {
        "A": [2, 4, 8],
        "B": [3, 5, 7],
        "C": [300, 100, 200],
    },
    index=["a", "b", "c"],
)
ax0 = df.plot(y=df.columns[:2], kind="bar", figsize=(10.24, 5.12))
ax1 = df["C"].plot(
    kind="line",
    secondary_y=True,
    color="g",
    marker=".",
)
plt.tight_layout()
plt.show()

Let me stress: I do see those questions related to VERTICAL bar charts. Now I'm asking about HORIZONTAL bar charts.

So this is not a duplicate question.

 2  62  2
1 Jan 1970

Solution

 3

Pandas plotting doesn't readily support a secondary x axis. Instead, you can directly plot via matplotlib.

(Note that df.plot(...) plots via pandas. Pandas plotting is a pandas specific interface towards matplotlib, and only supports a subset of matplotlib's functionality.)

import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame(
    {
        "A": [2, 4, 8],
        "B": [3, 5, 7],
        "C": [300, 100, 200],
    },
    index=["a", "b", "c"],
)
ax0 = df.plot(y=df.columns[:2], kind="barh", figsize=(10.24, 5.12))
ax1 = ax0.twiny()
ax1.plot(df["C"],
         df.index,
         color="g",
         marker=".",
         )
plt.tight_layout()
plt.show()

lineplot over pandas barh plot

PS: To exchange the top and bottom axes, you can use:

ax0 = df.plot(y=df.columns[:2], kind="barh", figsize=(10.24, 5.12))
ax1 = ax0.twiny()
ax1.plot(df["C"],
         df.index,
         color="g",
         marker=".",
         )
# change the direction of the y-axis
ax0.invert_yaxis()
# set the x-axis for ax0 at the top
ax0.tick_params(top=True, bottom=False, labeltop=True, labelbottom=False) # for the ticks and tick labels
ax0.xaxis.set_label_position('top') # for the axis label
# set the x-axis for ax1 at the bottom
ax1.tick_params(top=False, bottom=True, labeltop=False, labelbottom=True)
ax1.xaxis.set_label_position('bottom')

exchanging top and bottom axes

2024-07-21
JohanC