Python Matplotlib: Line, Bar and Pie Charts Step by Step - Python with AI tutorial chapter 40
Python

Python Matplotlib: Line, Bar and Pie Charts Step by Step

Python with AI Tutorial · Chapter 40 of 48

Python Matplotlib is the standard library for charts. With a few lines you can draw line, bar and pie charts from lists or pandas DataFrames, label them, style them and save them as PNG files for reports and slides. This chapter builds each chart type step by step using the sales data from the pandas chapters.

Install Matplotlib and draw a line chart

Install with pip and import matplotlib.pyplot as plt. A line chart needs an x list and a y list; everything else is optional labelling.

pip install matplotlib
Output:
Successfully installed matplotlib-3.9.2 ...
import matplotlib.pyplot as plt

months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
revenue = [10469, 11273, 9850, 12980, 14120, 13560]

plt.plot(months, revenue, marker="o")
plt.title("Monthly Revenue 2026")
plt.xlabel("Month")
plt.ylabel("Revenue (USD)")
plt.grid(True)
plt.savefig("revenue_line.png", dpi=150, bbox_inches="tight")
plt.show()
Output:
A window opens showing a line rising from 10,469 in Jan to a peak of 14,120 in May,
with a dot on each month; the same chart is saved as revenue_line.png.

Call savefig() before show(). In a script, show() blocks until you close the window and then clears the figure, so a savefig() placed after it writes a blank image.

The Figure and Axes objects

The plt. functions are shortcuts. For anything beyond a quick look, create a figure and an axes with plt.subplots() and call methods on the axes. This object-oriented style is what you will see in most documentation.

regions = ["East", "North", "South", "West"]
totals = [3186, 5481, 5987, 7088]

fig, ax = plt.subplots(figsize=(7, 4))
bars = ax.bar(regions, totals, color="#2b6cb0")
ax.bar_label(bars, fmt="{:,.0f}")
ax.set_title("Revenue by Region")
ax.set_ylabel("Revenue (USD)")
fig.savefig("region_bar.png", dpi=150, bbox_inches="tight")
plt.show()
Output:
Four blue bars labelled 3,186  5,481  5,987  7,088 above them, West the tallest.

bar_label() prints the value on each bar, and the fmt string adds thousands separators. figsize is in inches; combined with dpi=150 this gives a 1050 by 600 pixel image.

Chart types and when to use them

Pick the chart from the question you are answering, not from what looks impressive.

Method Chart Best for
ax.plot() Line Trends over time (monthly revenue)
ax.bar() / ax.barh() Vertical / horizontal bar Comparing categories (revenue by region)
ax.pie() Pie Share of a whole, five slices or fewer
ax.scatter() Scatter Relationship between two numbers (units vs price)
ax.hist() Histogram Distribution of one number (order values)
ax.boxplot() Box plot Spread and outliers per group
ax.stackplot() / fill_between() Area Cumulative or stacked totals over time
df.plot(kind=...) Any of the above Quick charts straight from pandas

Grouped bar chart

To compare two months per region, draw two bar series shifted left and right of each tick. NumPy supplies the positions.

import numpy as np

jan = [1998, 5481, 2990, 0]
feb = [1188, 0, 2997, 7088]
x = np.arange(len(regions))
width = 0.38

fig, ax = plt.subplots(figsize=(7, 4))
ax.bar(x - width / 2, jan, width, label="2026-01")
ax.bar(x + width / 2, feb, width, label="2026-02")
ax.set_xticks(x, regions)
ax.set_ylabel("Revenue (USD)")
ax.set_title("Revenue by Region and Month")
ax.legend()
plt.show()
Output:
Pairs of bars per region in two colours with a legend; North has only a January bar
and West only a February bar.

The width of 0.38 leaves a small gap between neighbouring pairs. Shifting each series by half the width keeps every pair centred on its tick, so the region names line up with the bars they describe.

Pie chart

Pie charts work for a handful of slices that add up to a whole. autopct prints the percentage on each slice.

products = ["Dashboard", "Tracker", "Calendar"]
share = [13986, 5083, 2673]

fig, ax = plt.subplots(figsize=(5, 5))
ax.pie(share, labels=products, autopct="%1.1f%%", startangle=90, counterclock=False)
ax.set_title("Revenue Share by Product")
plt.show()
Output:
Three slices labelled Dashboard 64.3%, Tracker 23.4%, Calendar 12.3%, starting at the top
and running clockwise.

If you have more than five categories, a horizontal bar chart sorted by value is almost always easier to read than a pie.

Try it with AI

Paste your aggregated data and specify every visual detail you want.

I have this pandas Series from sales.groupby("Region")["Revenue"].sum():

Region
East     3186
North    5481
South    5987
West     7088

Write Matplotlib code (object-oriented style with fig, ax = plt.subplots) for a horizontal bar chart sorted largest at the top, bars in #2b6cb0 with the top bar highlighted in #dd6b20, value labels formatted like 7,088, no top or right spines, title "Revenue by Region, H1 2026", and save it as region_bars.png at 200 dpi with tight bounding box.

Plot straight from pandas

Every DataFrame and Series has a .plot() method that calls Matplotlib for you and returns the axes, so you can keep customising.

import pandas as pd

sales = pd.DataFrame({
    "Region":  ["North", "South", "East", "North", "West", "South", "East", "West"],
    "Product": ["Dashboard", "Tracker", "Dashboard", "Calendar", "Tracker", "Dashboard", "Calendar", "Dashboard"],
    "Units":   [4, 10, 2, 15, 7, 3, 12, 5],
    "Revenue": [3996, 2990, 1998, 1485, 2093, 2997, 1188, 4995],
})

ax = sales.groupby("Product")[["Units", "Revenue"]].sum().plot(
    kind="bar", subplots=True, layout=(1, 2), figsize=(9, 4), legend=False, rot=0,
    title=["Units by Product", "Revenue by Product"])
plt.tight_layout()
plt.show()
Output:
Two bar charts side by side: Units (Calendar 27, Dashboard 14, Tracker 17) and
Revenue (Calendar 2673, Dashboard 13986, Tracker 5083).

Everything pandas draws is still Matplotlib underneath, so plt.savefig() and the axes methods from the earlier sections apply unchanged to the returned axes.

Format the axes

Default tick labels such as 14000 look unfinished. A FuncFormatter rewrites each tick, and hiding the top and right spines gives a cleaner look.

from matplotlib.ticker import FuncFormatter

fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(months, revenue, marker="o", color="tab:green", linewidth=2)
ax.yaxis.set_major_formatter(FuncFormatter(lambda v, pos: f"${v / 1000:.0f}k"))
ax.spines[["top", "right"]].set_visible(False)
ax.set_title("Monthly Revenue 2026", loc="left", fontsize=14)
ax.annotate("Best month", xy=("May", 14120), xytext=("Mar", 14000),
            arrowprops=dict(arrowstyle="->"))
plt.show()
Output:
The y axis reads $10k, $11k ... $14k, the title sits at the left, and an arrow labelled
"Best month" points at the May value.

Several charts in one figure

plt.subplots(rows, cols) returns a grid of axes. Fill each one, add a shared title and save a single dashboard image.

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))

ax1.plot(months, revenue, marker="o", color="tab:green")
ax1.set_title("Monthly Revenue")
ax1.grid(axis="y", alpha=0.3)

ax2.bar(regions, totals, color="tab:orange")
ax2.set_title("Revenue by Region")

fig.suptitle("Sales Dashboard 2026", fontsize=15)
fig.tight_layout()
fig.savefig("dashboard.png", dpi=150)
print("Saved dashboard.png")
Output:
Saved dashboard.png
Tip: in Jupyter and VS Code notebooks charts appear inline without plt.show(). In a plain script run from the terminal you need plt.show() to see a window, or savefig() to get a file. Call plt.close(fig) inside loops that create many figures to free memory.
Try it with AI

Describe a layout problem and ask for the fix with an explanation.

My Matplotlib bar chart has 12 product names on the x axis and the labels overlap. I am using fig, ax = plt.subplots(figsize=(8, 4)) and ax.bar(names, values). Show me three fixes: rotating labels 45 degrees with correct alignment, switching to ax.barh with the longest bar at the top, and wrapping long names onto two lines with textwrap. Also make the y axis show values as 1.2k instead of 1200.

Common mistakes

  • Calling savefig() after show() and getting an empty image.
  • Mixing the plt.title() shortcuts with axes objects and wondering why labels land on the wrong subplot; stick to ax.set_title() once you use subplots().
  • Plotting text categories in the wrong order. Sort the data first; Matplotlib draws in the order given.
  • Using a pie chart for ten categories. Switch to a sorted bar chart.
  • Forgetting tight_layout() or bbox_inches="tight", which crops long axis labels in the saved file.

Exercise

Using the sales DataFrame above, draw a horizontal bar chart of total Units per Product, sorted so the largest bar is at the top, with the value printed at the end of each bar and the title “Units Sold by Product”. Save it as units_by_product.png.

Show answer
units = sales.groupby("Product")["Units"].sum().sort_values()   # ascending puts largest on top in barh

fig, ax = plt.subplots(figsize=(7, 3.5))
bars = ax.barh(units.index, units.values, color="#2b6cb0")
ax.bar_label(bars, padding=3)
ax.set_title("Units Sold by Product")
ax.set_xlabel("Units")
fig.tight_layout()
fig.savefig("units_by_product.png", dpi=150)
print(units)
Output:
Product
Dashboard    14
Tracker      17
Calendar     27
Name: Units, dtype: int64

barh draws the first item at the bottom, so sorting ascending places Calendar (27) at the top of the chart.

Related chapters

FAQ

What is Matplotlib used for?

Matplotlib draws static charts in Python: line, bar, pie, scatter, histogram and many more. It works with plain lists, NumPy arrays and pandas DataFrames and can save charts as PNG, SVG or PDF for reports, slides and websites.

How do I save a Matplotlib chart as an image?

Call fig.savefig(“chart.png”, dpi=150, bbox_inches=”tight”) or plt.savefig() before plt.show(). The file extension sets the format; use .svg or .pdf for vector output.

What is the difference between plt.plot and ax.plot?

plt.plot() draws on the current figure implicitly, which is fine for one quick chart. ax.plot() draws on a specific Axes object returned by plt.subplots(), giving you full control when you have several charts or detailed styling.

Working with spreadsheets too? Ready-made Excel, Google Sheets and Power BI templates are at NextGenTemplates.com.

Chapter 40 of 48 · Python with AI: all 48 chapters

PK
Meet PK, the founder of NeotechNavigators.com! With over 15 years of experience in Data Visualization, Excel Automation, and dashboard creation. PK is a Microsoft Certified Professional who has a passion for all things in Excel. PK loves to explore new and innovative ways to use Excel and is always eager to share his knowledge with others. With an eye for detail and a commitment to excellence, PK has become a go-to expert in the world of Excel. Whether you're looking to create stunning visualizations or streamline your workflow with automation, PK has the skills and expertise to help you succeed. Join the many satisfied clients who have benefited from PK's services and see how he can take your data analysis skills to the next level!
https://neotechnavigators.com