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()
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]
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()
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()
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()
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()
sharey=True.Grouped or stacked?
| Chart | Best for |
|---|---|
| Grouped (side by side) | Comparing the series with each other within each group |
| Stacked | Showing the total of each group and how it is made up |
| Separate subplots | Many 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:
- Create a stacked bar chart in Matplotlib
- Plot a bar chart in Matplotlib
- Show values on bar charts
- Add error bars to a bar chart
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.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn