Bar charts
Sort them, turn them sideways, and never cut the baseline
ax.barax.barhbottom=ax.bar_labelax.containersnp.argsortWatch it happen
Play it through, or step back and forth yourself.
ax.bar(items, sold)vertical barswidth=0.8the default — leaves a gapcolor="#66aaf9"one colour, unless colour means somethingb.get_height()read a bar backBars are for comparing amounts across categories — five tea flavours, four regions, twelve months. The eye compares lengths well, which is exactly what a bar chart asks it to do.
The idea
Bars compare amounts across categories — five flavours, four regions, twelve months. The eye compares lengths well, which is exactly the task a bar chart sets it.
fig, ax = plt.subplots()
bars = ax.bar(items, sold)
ax.set_ylabel("cups sold")ax.bar hands back a BarContainer — a list-like of Rectangle artists you can read and restyle, and the thing ax.bar_label wants. Each call adds one entry to ax.containers.
Sort them
Unless the categories carry their own order — months, sizes, a 1–5 rating — sort by value. The chart exists to show the ranking; leaving it in menu order makes the reader do the sorting themselves.
order = np.argsort(sold)[::-1] # biggest first
ax.bar([items[i] for i in order], [sold[i] for i in order])And remember to reorder both — labels and values. Sorting one and not the other is a silent, plausible-looking wrong chart, and nothing will warn you.
Turn it sideways
When the labels are words, use ax.barh. Horizontal bars give each label a full line, so nothing needs rotating to 45° and squinting at.
order = np.argsort(sold) # ASCENDING for barh
ax.barh([items[i] for i in order], [sold[i] for i in order])Note the flip: the y axis counts upwards from the bottom, so ascending order puts the biggest bar on top where the eye starts. Get this backwards and your chart reads upside-down.
Two series
Grouped — side by side, for comparing the pairs. You place them yourself:
x = np.arange(len(days))
ax.bar(x - 0.2, delhi, width=0.4, label="Delhi")
ax.bar(x + 0.2, mumbai, width=0.4, label="Mumbai")
ax.set_xticks(x, days) # put the words backStacked — bottom=, for when the total is the point:
ax.bar(days, delhi, label="Delhi")
ax.bar(days, mumbai, bottom=delhi, label="Mumbai")Stacking shows the total honestly and the bottom segment honestly. Everything above starts at a different height, so comparing those segments across bars is genuinely hard — that's the trade, and it's worth it only when the total is what you're arguing about. Past three segments, stop.
The baseline is not a style choice
A bar encodes its value as a length. Cut the axis and you change the length without changing the number:
ax.set_ylim(280, 320) # 312 vs 288 now looks like 3xThis is the most common misleading chart there is, and it takes one line to make by accident. Bars start at zero. If the differences are too small to see at zero, that's the finding — say so, or plot the difference itself, or use a line chart, which encodes position rather than length and may be zoomed freely.
Label the bars, delete the furniture
bars = ax.barh(items, sold)
ax.bar_label(bars, padding=3)
ax.set_xticks([])
for side in ("top", "right", "bottom"):
ax.spines[side].set_visible(False)Once every bar carries its number, the axis and the gridlines are duplicated effort. Fewer things on the page, more of them actually read.
Not a pie chart
ax.pie() exists. It asks the eye to compare angles and areas, which it does badly, and it can only show parts of one whole. A sorted barh answers the same question and can be read exactly. Two or three slices with very different sizes is about the only case a pie survives.
See it run
The lesson's code, ready to run and to fiddle with.
Putting the kettle on…
Starting up…
Worked example
not gradedAlready written and ready to go — press Run to see what it does, then change a number, a column name, anything, and run it again.
tryswapping argsort(sold) for argsort(sold)[::-1] and seeing the chart read upside-down.
Your turn
3 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.
Draw a bar chart of items against sold, then read the bars back: return [round(b.get_height()) for b in bars].
Sort the menu by sales, biggest first, and return the item names in that order as a list.
Stack mumbai on top of delhi over days using bottom=, then return len(ax.containers) — one per bar() call.
