A manager once scrolled past a perfectly correct table I had sent and asked, in the next breath, which region was doing best. The answer was right there in the numbers, and she still could not see it. That is the gap a chart closes. A table asks the reader to do the comparing; a chart does the comparing for them and hands over the conclusion.
In Part 15 you loaded a file, filtered it, and grouped revenue by region into a small clean summary. This part keeps the exact same data and turns that summary into a picture. You will draw a bar chart, a line, and a scatter with Matplotlib, the plotting library nearly every Python analyst reaches for first, and you will see how pandas can draw many of them for you in a single line.
Key takeaways
Matplotlib draws the chart; pandas is a shortcut that calls Matplotlib for you. Learn both, because the shortcut is quick and the full library gives you control when the shortcut runs out.
Use the explicit style: create a figure and axes with fig, ax = plt.subplots(), then call methods on ax. It reads clearly and scales to charts with more than one panel.
Three charts cover most of the work: a bar for comparing categories, a line for change over time, and a scatter for the relationship between two numbers. Label every one and save it with savefig.
Two libraries, one job
Two names come up the moment you plot in Python, and it helps to know how they relate before you type anything. Matplotlib is the drawing engine, a library that turns numbers into shapes, axes and text on a canvas. pandas, the table library from Part 15, does not draw anything itself; its plot method is a thin wrapper that hands your DataFrame to Matplotlib and asks it to draw. So when you call a chart from pandas, Matplotlib is still doing the work underneath. That single fact removes most of the early confusion: you are always using Matplotlib, sometimes directly and sometimes through pandas.
The practical rule I follow is simple. Reach for the pandas shortcut when you want a quick look at data you have already shaped, because one short line gets a chart on screen. Reach for Matplotlib directly when you need to control the result, a specific colour, a second line on the same axes, a title and axis labels worded exactly your way, or two charts side by side. You will use both every week, and neither is more correct than the other. This part shows the direct route first, so the shortcut makes sense once you see what it is standing in for.
There is one more library you will hear about, Seaborn, which sits on top of Matplotlib and makes attractive statistical charts with less code. It is worth learning later, but not now. Get comfortable with the engine and its pandas shortcut first, because everything Seaborn produces is a Matplotlib figure you can then adjust with the same methods you are about to learn. Adding a third tool before the first two are steady just spreads your attention thin.
The parts of a Matplotlib figure
Almost every beginner mistake in Matplotlib comes from not knowing which object owns what, so learn the two that matter. The Figure is the whole canvas, the outer window that holds everything. The Axes, confusingly named because it is not a single axis, is one plot area sitting inside the figure, the rectangle where your bars or lines actually live, together with its x axis, y axis, title and labels. A figure can hold one Axes or a grid of them. When you type fig, ax = plt.subplots(), you are asking for a figure and one Axes in a single line, and then you draw on ax.
Hold that split in your head and the method names stop being arbitrary. Anything about the whole canvas, such as saving to a file, is a figure method, so it is fig.savefig. Anything about the plot itself, the bars, the title, the axis labels, is an Axes method, so it is ax.bar, ax.set_title, ax.set_xlabel. The diagram below labels each part on a real chart. Keep it in mind and you will know, without guessing, whether a command belongs to fig or to ax.
Make your first bar chart
A bar chart compares a number across categories, and it is the honest default for a question like which region sold the most. We start from the grouped summary you built in Part 15, total revenue per region, and draw it directly with Matplotlib so every step is visible. You import the pyplot module as plt by convention, create a figure and one Axes, call ax.bar with the category names and their values, then add a title and labels before showing the result. Here are the numbers we are drawing.
| region | total_revenue | orders |
|---|---|---|
| West | 5400 | 2 |
| North | 3400 | 2 |
| South | 2500 | 2 |
The grouped revenue per region carried over from Part 15. These three numbers are the ones every chart below is built from.
Result: a window with three red bars, West tallest at 5400, then North, then South, with a title and both axes labelled. In a notebook the chart appears under the cell; plt.show() forces it to display in a plain script.
Common failure: nothing appears when you run this as a .py file and forget plt.show(). A notebook shows the figure automatically, but a script needs that final call to open the window. If the chart still does not show over a remote connection, save it to a file with savefig instead, which the last section covers.
The picture below is exactly what that code draws, redrawn here so you can check your own output against it. Notice the y axis starts at zero, which for a bar chart is not optional. You met this trap in Part 13: a bar whose axis starts above zero exaggerates small gaps into big ones. Matplotlib starts bar charts at zero by default, and you should leave it there.
Let pandas draw it for you
Once your data is already in a DataFrame or a grouped Series, you rarely need to pull the values out by hand as we just did. pandas plots straight from the table with a plot method, and it labels the axes from your column and index names automatically, which saves several lines. The kind argument picks the chart: bar for a bar chart, line for a line, scatter for a scatter. Because pandas is calling Matplotlib underneath, you can capture the Axes it returns and keep tuning the result with the same ax methods from the last section.
Result: the same bar chart as before, in three lines of plotting instead of six. pandas reads the region names from the group index and puts them on the x axis for you.
Common failure: expecting kind=’bar’ to sort the bars for you. It draws them in the order they sit in the Series, which for a groupby is alphabetical by region. If you want the tallest bar first, sort the data before plotting with sort_values(ascending=False), then call plot.
Worked example
Say a manager wants the regions ranked, tallest first, with revenue on the y axis. You already have every piece. Sort the grouped Series, then plot it: by_region.sort_values(ascending=False).plot(kind=’bar’).
That one line reorders West, North, South from highest to lowest and draws the ranked chart. The lesson is that shaping the data, not styling the chart, is what usually gets you the picture you want. Sort, filter or group first; plot last.
Show change over time with a line
When the x axis is time, a line chart beats bars, because the line makes the trend, the rise or fall from one day to the next, jump out. Our sample spans three days, so let us total revenue per day and draw it as a line. The pattern mirrors the bar chart: create the figure and Axes, call ax.plot with the dates and the daily totals, then label. A line implies the points connect in a meaningful order, so only use one when the x axis has a natural sequence like dates or months, never for unordered categories such as region names.
Result: a red line rising from 4000 on 2026-06-01 to 5000 on 2026-06-02, then falling to 2300 on 2026-06-03, with a dot marking each day. marker=’o’ draws the points so the reader sees the three real measurements, not just the line between them.
Common failure: dates read from a CSV arrive as plain text, so Matplotlib spaces them evenly rather than by real calendar distance. For three consecutive days it looks fine; across uneven gaps it misleads. Convert the column with pd.to_datetime(sales[‘date’]) first, and the axis then honours the true spacing between dates.
Compare two numbers with a scatter
A scatter plots one number against another, one dot per row, and answers the question of whether two measurements move together. In our data, do higher unit counts come with higher revenue? You met the danger of reading too much into that pattern in Part 12, where a rising cloud of points tempts you to claim one thing causes the other. The scatter shows the shape; it does not prove the cause. Here we plot units on the x axis and revenue on the y, each order a single dot.
Result: five dots rising from lower left to upper right, the order with 20 units sitting highest on revenue. We drop the row with a missing units value first, because a scatter cannot place a point with no x coordinate.
Common failure: feeding a scatter a column that still holds missing values. Matplotlib silently skips those points, so your chart shows fewer dots than you have rows and you may not notice. Drop or fill the gaps first, as in Part 15, so the count of dots matches the count of orders you expect.
Label it, then save it
A chart with no title and bare axes forces the reader to guess, and a guessing reader stops trusting you. Three methods fix that, and you have already seen them: ax.set_title gives the chart a plain sentence saying what it shows, ax.set_xlabel and ax.set_ylabel name the axes with their real units, and ax.legend labels each series when a chart holds more than one line or bar group. Treat these as part of drawing the chart, not an optional polish, because an unlabelled chart is a puzzle and a labelled one is an answer.
When the chart is ready to share, you save it to an image file rather than screenshotting the screen. fig.savefig writes a PNG or PDF, and two arguments matter: dpi controls the resolution, with 150 a good balance for a slide or document, and bbox_inches set to tight trims the surrounding whitespace so labels are not clipped. Save the file, drop it into your report or deck, and you have taken the analysis from a picture on your screen to something a colleague can open. The reference below lines up each method with the job it does.
Result: a file named revenue.png appears in your working folder, sharp enough for a slide and cropped tight to the chart. No window opens, because savefig writes to disk instead of the screen.
Common failure: calling plt.show() before fig.savefig. On some setups show clears the figure, so the saved file comes out blank. Save first, then show, and you always get the image you drew.
| You want to | Method | Belongs to |
|---|---|---|
| Draw bars | ax.bar | Axes |
| Draw a line | ax.plot | Axes |
| Draw dots | ax.scatter | Axes |
| Title the chart | ax.set_title | Axes |
| Name the axes | ax.set_xlabel, ax.set_ylabel | Axes |
| Save to a file | fig.savefig | Figure |
The core methods for this part. Everything about the plot lives on ax; only saving the whole canvas lives on fig.
The workflow from data to saved chart
Every chart in this part followed the same short path, and it is worth seeing the whole loop at once. You shape the data with the pandas moves from Part 15, decide which question you are answering and therefore which chart fits, draw it on an Axes, label it so it stands alone, and save it to a file. The step people skip is the second one, choosing the chart to match the question, and skipping it is how you end up with a line chart of unordered categories or a pie chart nobody can read. Decide the question first; the chart type falls out of it.
My take
Beginners burn hours on styling, hunting for the perfect colour or a fancier chart type, when the win is almost always in the data and the labels. A plain red bar chart with an honest zero axis and a clear title persuades a manager better than a rainbow chart that hides its question. I keep a private rule: I do not touch a single style option until the chart already answers its question in one glance. Nine times in ten, it never needs the styling at all.
Get these three charts fluent first
Matplotlib can draw dozens of chart types and expose hundreds of options, and you can safely ignore nearly all of them for now. A bar for comparing categories, a line for change over time, and a scatter for the link between two numbers will carry the majority of your first year, and each one uses the same three steps: make a figure and Axes, call one drawing method, label and save. Get those reflexes steady and every fancier chart, the stacked bar, the histogram, the small grid of panels, is a short addition to a pattern you already own.
You can now take a grouped result from pandas and turn it into a chart a colleague can read without you standing next to them. Part 17 steps back from the tools to the thinking behind them: how to define the metrics and KPIs a chart should show in the first place, so the number you plot is the number that actually matters. Keep the Data Analyst guide open as your map, and revisit Part 13 if choosing between chart types still feels uncertain.
This week, open a Colab notebook, recreate the sales.csv from Part 15, and draw all three charts yourself: a bar of revenue per region, a line of revenue per day, and a scatter of units against revenue. Then save one with savefig and drop it into a document. Drawing them once by hand fixes the pattern far better than reading it does.
References
- Quick start guide, Matplotlib Documentation
- pandas.DataFrame.plot Reference, pandas Documentation
- matplotlib.pyplot.savefig Reference, Matplotlib Documentation


DrJha