Chart Types

Data Science · Lesson 22 of 32 7 min read Updated

Different questions need different charts. "How did sales change over the year?" is a line chart. "Which city sold the most?" is a bar chart. "How are marks spread out?" is a histogram. Choosing the wrong form hides the answer even when the data is right.

In this lesson you will match common questions to the five charts data scientists use most, and draw each one with matplotlib using the practice datasets.

Which chart answers which question?

QuestionChartmatplotlib
How does a value change over time?Line chartax.plot()
How do categories compare?Bar chart (horizontal for long names)ax.bar(), ax.barh()
How is one numeric variable spread out?Histogramax.hist()
Are two numeric variables related?Scatter plotax.scatter()
How do spreads compare across groups?Box plotax.boxplot()

Pie charts are popular in office reports, but people judge angles poorly. With more than two or three slices, a sorted bar chart is almost always clearer.

Bar charts: comparing categories

A bar chart compares a quantity across categories. Sort the bars so the order carries meaning, and use horizontal bars (barh) when the labels are long.

PythonRun it yourself
import pandas as pd
import matplotlib.pyplot as plt

sales = pd.read_csv("sales.csv").drop_duplicates()
sales["revenue"] = sales["quantity"] * sales["unit_price"] * (1 - sales["discount"] / 100)
by_cat = (sales.groupby("category")["revenue"].sum() / 100000).sort_values()

fig, ax = plt.subplots(figsize=(7, 4))
ax.barh(by_cat.index, by_cat.values, color="#c2410c")
ax.set_title("Revenue by category, 2025")
ax.set_xlabel("₹ lakh")
plt.show()

print(by_cat.round(2))
Output
category
Books             1.12
Sports            1.34
Groceries         1.78
Home & Kitchen    4.50
Electronics       5.03
Fashion           5.30
Name: revenue, dtype: float64

Six horizontal bars appear in order of size, with Fashion's the longest at the top and Books' the shortest at the bottom. Because barh draws the first value at the bottom, sorting from smallest to largest puts the biggest category on top, where readers look first. A bar's length is the message, so a bar chart's value axis must start at zero; matplotlib does that by default.

Histograms: how values are spread

A histogram splits a numeric range into bins (intervals) and draws a bar for how many values fall in each. It shows the shape of the data: where most values are, how wide the spread is, and whether one side has a longer tail.

PythonRun it yourself
import pandas as pd
import matplotlib.pyplot as plt

students = pd.read_csv("students.csv", na_values=["AB"]).drop_duplicates()

fig, ax = plt.subplots(figsize=(7, 4))
ax.hist(students["maths"].dropna(), bins=range(10, 101, 5), color="#2563eb", edgecolor="white")
ax.axvline(33, color="black", linestyle="--", label="Pass mark (33)")
ax.set_title("Maths marks, Class 10")
ax.set_xlabel("Marks")
ax.set_ylabel("Number of students")
ax.legend()
plt.show()

print((students["maths"] < 33).sum(), "students below the pass mark")
Output
38 students below the pass mark

The histogram is a hill centred around 55 to 60 marks, falling away on both sides, with a small group below the dashed pass-mark line and a thin tail reaching 100. bins=range(10, 101, 5) makes bins 5 marks wide, which matches how people think about marks; too few bins hide the shape and too many make it jagged. axvline() draws a vertical reference line. Histograms need dropna() because missing values cannot be placed in a bin.

A scatter plot draws one dot per row, with one variable on each axis. A cloud that slopes upward suggests that the variables rise together.

PythonRun it yourself
import pandas as pd
import matplotlib.pyplot as plt

students = pd.read_csv("students.csv", na_values=["AB"]).drop_duplicates()
students = students[students["attendance"] <= 100]

fig, ax = plt.subplots(figsize=(7, 4))
ax.scatter(students["attendance"], students["maths"], s=14, alpha=0.5)
ax.set_title("Attendance and maths marks")
ax.set_xlabel("Attendance (%)")
ax.set_ylabel("Maths marks")
plt.show()

print(students[["attendance", "maths"]].corr().round(2))
Output
            attendance  maths
attendance        1.00   0.39
maths             0.39   1.00

The dots form a wide cloud that drifts upward from left to right: students with higher attendance tend to score higher, but with a lot of variation at every attendance level. s sets the dot size and alpha=0.5 makes dots half transparent, so places where many dots overlap look darker. The printed correlation puts a number on the relationship; you will learn exactly what it means in Correlation.

Box plots: comparing spreads across groups

A box plot summarises a distribution in five numbers: the box runs from the 25th to the 75th percentile with a line at the median, the whiskers reach the furthest values within 1.5 × IQR, and dots beyond them are possible outliers. Placing boxes side by side compares groups quickly.

PythonRun it yourself
import pandas as pd
import matplotlib.pyplot as plt

emp = pd.read_csv("employees.csv").drop_duplicates()
emp["department"] = emp["department"].str.strip().str.title().replace({"Engg": "Engineering", "Hr": "HR"})

order = emp.groupby("department")["salary"].median().sort_values().index
data = [emp.loc[emp["department"] == d, "salary"].dropna() / 100000 for d in order]

fig, ax = plt.subplots(figsize=(8, 4))
ax.boxplot(data, tick_labels=order)
ax.set_title("Salary by department")
ax.set_ylabel("₹ lakh per year")
plt.show()

print(emp.groupby("department")["salary"].median().sort_values().div(100000).round(2))
Output
department
Support          5.34
Finance          7.48
Sales            7.74
HR               8.07
Engineering     10.11
Data Science    11.20
Name: salary, dtype: float64

Six boxes rise from left to right because they are ordered by median salary: Support on the left with the lowest and narrowest box, Data Science on the right with the highest. Engineering and Data Science have the tallest boxes, the widest spread of pay, while Sales and Finance show a few dots above their whiskers: unusually high earners in those departments. In matplotlib 3.10 the box names are passed with tick_labels; older code used labels, which still works but is deprecated.

Line charts with several series, and when not to use them

Line charts imply that the x-axis is continuous and ordered, usually time. Do not draw lines between categories that have no natural order, such as cities; use bars instead.

PythonRun it yourself
import pandas as pd
import matplotlib.pyplot as plt

sales = pd.read_csv("sales.csv", parse_dates=["order_date"]).drop_duplicates()
sales["month"] = sales["order_date"].dt.month
counts = sales.pivot_table(index="month", columns="category", values="order_id", aggfunc="count")

ax = counts[["Electronics", "Books", "Sports"]].plot(marker="o", figsize=(8, 4))
ax.set_title("Orders per month for three categories")
ax.set_xlabel("Month")
ax.set_ylabel("Orders")
ax.set_xticks(range(1, 13))
plt.show()

The three lines tell three seasonal stories: Books are highest in February and March (exam season), Sports orders rise in April to June (summer holidays and cricket season), and Electronics shoots up in October and November with festive shopping. Three series on one chart is readable; with ten, the lines become spaghetti, and separate small charts work better, as shown in Subplots & Styling.

Common mistakes

  • Pie charts with many slices. Use a sorted bar chart.
  • Bar charts that do not start at zero. A cut axis makes small differences look huge. (Line charts may zoom in, because they show change, not size.)
  • Lines between unordered categories. Use bars for cities, products or departments.
  • Overplotting. Thousands of solid dots hide each other; use alpha, smaller s, or a histogram.
  • Forgetting dropna() before hist() or boxplot(). Missing values can cause errors or empty plots.

Key points

  • Line for change over time, bar for comparing categories, histogram for a distribution, scatter for a relationship, box plot for comparing spreads.
  • Sort bars by value and use barh() for long labels; bar axes start at zero.
  • Choose histogram bins that match the data, such as 5-mark bins for exam marks.
  • Use alpha and small markers in scatter plots to show where points overlap.
  • In matplotlib 3.10, name box plot groups with tick_labels.

Exercise

Using weather.csv, draw a histogram of Mumbai's daily rainfall for the days when it rained (more than 0 mm), with bins of 5 mm from 0 to 80. Add a title and axis labels. Then print how many rainy days Mumbai had and the median rainfall on those days.

Show solution
Python
import pandas as pd
import matplotlib.pyplot as plt

weather = pd.read_csv("weather.csv")
rain = weather.loc[(weather["city"] == "Mumbai") & (weather["rainfall_mm"] > 0), "rainfall_mm"]

fig, ax = plt.subplots(figsize=(7, 4))
ax.hist(rain, bins=range(0, 81, 5), color="#0891b2", edgecolor="white")
ax.set_title("Rainfall on rainy days, Mumbai 2025")
ax.set_xlabel("Rainfall (mm)")
ax.set_ylabel("Days")
plt.show()

print(len(rain), "rainy days, median", rain.median(), "mm")
Output
97 rainy days, median 12.1 mm

The histogram is tallest at the left and falls away to the right: most rainy days bring a modest amount of rain, and a few bring very heavy downpours. This long right tail is called right skew, and it is why the median is a better summary than the mean for rainfall.

Quick Quiz

1. Which chart best shows how a variable is distributed?

2. Why should a bar chart's value axis start at zero?

3. What does alpha=0.5 do in a scatter plot?

4. You want to compare salary spreads across six departments. Which chart fits best?

Learn Data Science with a mentor

Free lessons get you started. Our Data Science & Machine Learning training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call