How to Create Multiple Bar Charts in Matplotlib (Grouped, Side by Side)

To create a multiple bar chart in Matplotlib (also called a grouped, double or side-by-side bar chart), draw each series with ax.bar() at positions shifted by the bar width, for example x - width/2 and x + width/2, then put the group labels in the middle with ax.set_xticks(x, labels). With pandas, df.plot(kind="bar") draws a grouped bar for every column. This guide covers both, plus any number of series, horizontal bars, and several separate bar charts side by side.

Tested with Python 3.12.5, Matplotlib 3.11.2, NumPy 2.5.3 and pandas 3.0.6; the charts are real Matplotlib windows. Reference: Matplotlib grouped bar chart example and DataFrame.plot.bar.

Double bar graph (two bars side by side)

import matplotlib.pyplot as plt
import numpy as np

quarters = ["Q1", "Q2", "Q3", "Q4"]
sales_2024 = [120, 135, 150, 170]
sales_2025 = [128, 149, 162, 195]

x = np.arange(len(quarters))        # 0, 1, 2, 3: one group per quarter
width = 0.38                        # width of each bar

fig, ax = plt.subplots(figsize=(7, 4.5))
bars1 = ax.bar(x - width / 2, sales_2024, width, label="2024")   # shift left
bars2 = ax.bar(x + width / 2, sales_2025, width, label="2025")   # shift right
ax.bar_label(bars1, padding=2)
ax.bar_label(bars2, padding=2)

ax.set_xticks(x, quarters)          # labels in the middle of each group
ax.set_ylabel("Sales (thousand USD)")
ax.set_title("Double bar graph: sales by quarter")
ax.legend()
plt.tight_layout()
plt.show()
Matplotlib double bar graph with 2024 and 2025 sales side by side for each quarter and value labels on the bars
Two series side by side, with values from bar_label().

The trick is the x positions: np.arange() gives one position per group, and each series is moved half a bar width to the left or right so the bars touch instead of overlapping.

Any number of bars per group

For n series, make each bar 0.8 / n wide and move series i by (i - (n - 1) / 2) * width. This prints the positions it produces:

import numpy as np

groups = 4                     # quarters
series = ["2023", "2024", "2025"]
width = 0.8 / len(series)      # the bars of one group fill 80% of the space between groups

x = np.arange(groups)
for i, name in enumerate(series):
    offset = (i - (len(series) - 1) / 2) * width
    print(f"{name}: offset {offset:+.3f} -> bar centres {np.round(x + offset, 3)}")

Output:

2023: offset -0.267 -> bar centres [-0.267  0.733  1.733  2.733]
2024: offset +0.000 -> bar centres [0. 1. 2. 3.]
2025: offset +0.267 -> bar centres [0.267 1.267 2.267 3.267]
Command Prompt output of the offsets and bar centre positions for three grouped bar series calculated with NumPy
The offsets centre every group on its tick.
import matplotlib.pyplot as plt
import numpy as np

products = ["Laptops", "Phones", "Tablets", "Watches", "Audio"]
regions = {"North": [42, 55, 20, 18, 25], "South": [38, 61, 24, 15, 30],
           "East": [50, 47, 19, 22, 28], "West": [45, 52, 27, 20, 21]}

x = np.arange(len(products))
width = 0.8 / len(regions)

fig, ax = plt.subplots(figsize=(9, 4.5))
for i, (region, values) in enumerate(regions.items()):
    offset = (i - (len(regions) - 1) / 2) * width
    ax.bar(x + offset, values, width, label=region)

ax.set_xticks(x, products)
ax.set_ylabel("Units sold (thousands)")
ax.legend(title="Region", ncols=4, loc="upper right")
plt.tight_layout()
plt.show()
Matplotlib grouped bar chart with four regions side by side for five products drawn in a loop with a legend
Four series per group drawn in a loop.

Bar plot of multiple columns with pandas

If your data is in a DataFrame, each column becomes a series and each row a group. No offset calculation is needed:

import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame({"2023": [310, 280, 190], "2024": [335, 300, 210], "2025": [360, 290, 240]},
                  index=["Electronics", "Clothing", "Groceries"])

ax = df.plot(kind="bar", figsize=(7, 4.5), rot=0, width=0.8)   # one bar per column, grouped by row
ax.set_ylabel("Revenue (thousand USD)")
ax.set_title("pandas: bar plot of multiple columns")
for container in ax.containers:
    ax.bar_label(container, fontsize=8)
plt.tight_layout()
plt.show()
pandas grouped bar plot of revenue for 2023, 2024 and 2025 for three categories with value labels
df.plot(kind="bar") on a DataFrame with three columns.

Use kind="barh" for horizontal bars and stacked=True for stacked bars. To choose columns, pass y=["col1", "col2"].

Horizontal grouped bar chart

import matplotlib.pyplot as plt
import numpy as np

skills = ["Python", "SQL", "Excel", "Tableau"]
junior = [60, 55, 80, 30]
senior = [90, 85, 70, 65]

y = np.arange(len(skills))
height = 0.38
fig, ax = plt.subplots(figsize=(7, 4))
ax.barh(y - height / 2, junior, height, label="Junior")
ax.barh(y + height / 2, senior, height, label="Senior")
ax.set_yticks(y, skills)
ax.invert_yaxis()
ax.set_xlabel("Average score")
ax.legend()
plt.tight_layout()
plt.show()
Matplotlib horizontal grouped bar chart comparing junior and senior scores for four skills with barh
barh() with the offsets on the y-axis.

Several separate bar charts side by side

Sometimes “multiple bar charts” means several charts, not grouped bars. Put one bar chart in each subplot and share the y-axis so they are easy to compare:

import matplotlib.pyplot as plt

data = {"Chicago": [5, 7, 12, 18, 23, 27], "Miami": [24, 25, 26, 28, 30, 31],
        "Seattle": [7, 8, 10, 13, 16, 19]}
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]

fig, axes = plt.subplots(1, 3, figsize=(11, 3.6), sharey=True)
for ax, (city, temps), color in zip(axes, data.items(), ["tab:blue", "tab:orange", "tab:green"]):
    ax.bar(months, temps, color=color)       # one separate bar chart per subplot
    ax.set_title(city)
axes[0].set_ylabel("Temperature (°C)")
plt.tight_layout()
plt.show()
Three Matplotlib bar charts side by side in subplots showing monthly temperatures for Chicago, Miami and Seattle with a shared y-axis
One bar chart per subplot, sharey=True.

Grouped or stacked?

ChartBest for
Grouped (side by side)Comparing the series with each other within each group
StackedShowing the total of each group and how it is made up
Separate subplotsMany groups or series with different ranges

See how to create a stacked bar chart in Matplotlib for the stacked version.

More Matplotlib bar chart tutorials:

Frequently asked questions

How do I plot multiple bars side by side in Matplotlib?

Create positions with x = np.arange(n), draw each series with ax.bar(x + offset, values, width) using different offsets, and label the groups with ax.set_xticks(x, labels).

How do I make a double bar graph in Python?

Draw two bar() calls at x - width/2 and x + width/2 with the same width, and add a legend.

How do I plot multiple columns as a bar chart in pandas?

df.plot(kind="bar") draws one bar per column for each row. Use y=[...] to pick columns.

How do I calculate the bar positions for n series?

Use width = 0.8 / n and offset = (i - (n - 1) / 2) * width for series i.

How do I add values on top of grouped bars?

Call ax.bar_label(bars) for each series, or loop over ax.containers after a pandas plot.

How do I show several bar charts side by side?

Use fig, axes = plt.subplots(1, 3, sharey=True) and draw one bar chart on each axes.