Skillversitas

Bar Charts

A bar chart compares magnitudes across categories, and it is the right tool when the categories are discrete - products, months, regions, answers to a survey. Two rules govern good bar charts: the axis should start at zero (a truncated axis turns small differences into dramatic ones), and bars should be sorted or ordered by a meaningful logic (value, time, or hierarchy). Matplotlib's bar and barh cover vertical and horizontal forms with full control over width, position, and stacking.

Basic Bar Chart

import matplotlib.pyplot as plt

categories = ["Search", "Direct", "Referral", "Social", "Email"]
values = [4200, 3100, 1800, 950, 640]

fig, ax = plt.subplots()
bars = ax.bar(categories, values, color="tab:blue", width=0.6)
ax.set_ylabel("visits")
ax.set_ylim(0, max(values) * 1.15)   # room for value labels

for bar, v in zip(bars, values):
    ax.text(bar.get_x() + bar.get_width() / 2, v + 80,
            f"{v:,}", ha="center", va="bottom", fontsize=9)
plt.show()

bar returns the Rectangle artists, which makes value labels a two-line loop: read each bar's position from the artist and place text above it. set_ylim starting at zero is the honest default for magnitude comparison.

Horizontal Bars

import matplotlib.pyplot as plt

regions = ["APAC", "EMEA", "Americas", "LATAM", "ANZ"]
revenue = [2.1, 3.4, 5.8, 0.9, 0.4]   # in $M

fig, ax = plt.subplots()
ax.barh(regions, revenue, color="tab:green")
ax.set_xlabel("revenue ($M)")
ax.invert_yaxis()      # largest on top, matching the label order
plt.show()

Horizontal bars are the better form when category labels are long or numerous - the label column never overlaps the bars. invert_yaxis puts the first (usually largest) category on top, matching how people read rankings.

Grouped (Side-by-Side) Bars

import numpy as np
import matplotlib.pyplot as plt

months = ["Jan", "Feb", "Mar", "Apr"]
this_year = [120, 150, 135, 170]
last_year = [100, 120, 140, 130]

x = np.arange(len(months))
width = 0.38

fig, ax = plt.subplots()
ax.bar(x - width / 2, last_year, width, label="2025", color="tab:gray")
ax.bar(x + width / 2, this_year, width, label="2026", color="tab:blue")
ax.set_xticks(x, months)
ax.legend()
ax.set_ylabel("sales")
plt.show()

Grouped bars need numeric x positions so two bars per category can sit side by side; set_xticks then relabels the numeric positions with the category names. Keep groups to two or three series - beyond that, a line chart or small multiples communicate better.

Stacked Bars

import matplotlib.pyplot as plt

quarters = ["Q1", "Q2", "Q3", "Q4"]
hardware = [40, 55, 60, 75]
services = [25, 30, 45, 50]

fig, ax = plt.subplots()
ax.bar(quarters, hardware, label="hardware", color="tab:blue")
ax.bar(quarters, services, bottom=hardware, label="services", color="tab:orange")
ax.legend()
ax.set_ylabel("revenue")
plt.show()

The bottom argument stacks segments: each series sits on the cumulative sum of the ones before it. Stacked bars show total-plus-composition, but comparing individual segments across categories becomes hard - reserve them for "the whole matters" charts.

Summary

Build bar charts with bar/barh, always zero-based for magnitude comparison, sorted by a real logic, with value labels from the returned artists. Horizontal form for long labels, numeric x positions for grouped bars, and bottom for composition - and stop at three series before the chart stops being readable.