Free Study Material
A table of numbers is precise, but a trend is often easier to actually see than to read off row by row. This chapter covers turning DataFrame data into charts, using Python's most widely used plotting library.
Matplotlib is Python's core plotting library, brought in with:
import matplotlib.pyplot as plt
A line chart connects data points in sequence with a line — the standard choice for showing a trend over an ordered sequence, like values changing across months.
plt.plot(x_values, y_values)
plt.show()
import matplotlib.pyplot as plt
months = ["Jan", "Feb", "Mar", "Apr"]
sales = [200, 240, 210, 300]
plt.plot(months, sales)
plt.xlabel("Month")
plt.ylabel("Sales")
plt.title("Monthly Sales")
plt.show()
plt.plot(months, sales) draws a line connecting each month's sales figure in sequence. xlabel(), ylabel(), and title() label the chart so it's readable on its own. plt.show() displays the finished chart — a line rising from Jan to Feb, dipping slightly at Mar, then rising again to its highest point at Apr, visually showing the same trend the raw numbers describe.
Note:plt.show()is what actually displays the chart — building it withplot()/xlabel()/etc. alone prepares it, but nothing appears untilshow()is called.
A line chart's whole purpose is showing change over an ordered sequence — which is exactly why its x-axis should always be something naturally ordered, like months or years, rather than unordered categories, which the next topic covers with a more suitable chart type.
import matplotlib.pyplot as plt brings in Python's core plotting library. plt.plot(x, y) draws a line chart connecting data points in sequence — the right chart type for showing a trend over an ordered sequence like time. plt.show() displays the finished chart.
System Update: We are initializing the Graphing Engine (Matplotlib).
Important: In the labs below, always use plt_show() instead of plt.show() to render the image.
import sys
# 1. Install Matplotlib if missing
if "matplotlib" not in sys.modules:
print("Toolkit: Installing Graphing Engine...")
import pyodide_js
await pyodide_js.loadPackage("micropip")
import micropip
await micropip.install(['matplotlib', 'pandas', 'numpy'])
print("Toolkit: Ready.")
# 2. The Magic Function to Render Graphs
import matplotlib.pyplot as plt
import io, base64
def plt_show():
"""Saves the plot to a buffer and prints it as an HTML image"""
buf = io.BytesIO()
plt.savefig(buf, format='png', bbox_inches='tight')
buf.seek(0)
img_str = base64.b64encode(buf.read()).decode('utf-8')
print(f"<br><img src='data:image/png;base64,{img_str}' style='max-width:100%; border-radius:10px; box-shadow:0 4px 6px rgba(0,0,0,0.1);'/><br>")
plt.clf() # Clear the canvas for the next plot
print(" Toolkit: Graphics System Loaded. You can now plot!")
A Line Chart is the "Hello World" of data visualization. It is best used for showing Trends over Time (e.g., Temperature changes, Stock prices, Viewer growth).
We use the library Matplotlib (specifically the `pyplot` module).
plt.plot(x, y)
import matplotlib.pyplot as plt
# Data
days = [1, 2, 3, 4, 5]
temp = [30, 32, 34, 33, 31]
# 1. Create the Plot
# x=days, y=temp
plt.plot(days, temp)
# 2. Render it using our custom tool
plt_show()
A graph without labels is useless. You must tell the viewer what the X and Y axes represent.
import matplotlib.pyplot as plt
days = [1, 2, 3, 4, 5]
temp = [30, 32, 34, 33, 31]
# Plot with Style
# color='red': Line color
# marker='o': Adds dots at data points
# linestyle='--': Makes the line dashed
plt.plot(days, temp, color='red', marker='o', linestyle='--')
# Add Labels
plt.title("Daily Temperature Report")
plt.xlabel("Day of Week")
plt.ylabel("Temperature (C)")
plt.grid(True)
# Render
plt_show()
The last topic's line chart suits an ordered sequence like months. This topic covers the right chart for a genuinely different job: comparing separate, unordered categories against each other.
A bar chart represents each category as a separate bar, with height (or length) showing its value — built for comparing categories side by side, not for showing a trend.
plt.bar(categories, values)
import matplotlib.pyplot as plt
subjects = ["Physics", "Chemistry", "Maths"]
marks = [85, 78, 92]
plt.bar(subjects, marks)
plt.xlabel("Subject")
plt.ylabel("Marks")
plt.title("Marks by Subject")
plt.show()
plt.bar(subjects, marks) draws one bar per subject, each bar's height matching its mark — Maths's bar is visibly the tallest at 92, Chemistry's the shortest at 78. Unlike the line chart, there's no meaningful "order" connecting Physics to Chemistry to Maths — reordering the bars wouldn't change what the chart honestly represents.
Note: A bar chart and a line chart can plot the exact same numbers, but choosing the right one matters: connecting unordered categories with a line (as if Physics "leads to" Chemistry) would misleadingly suggest a trend that doesn't actually exist.
The choice between a line chart and a bar chart isn't stylistic — it's about whether the x-axis categories have a genuine order. Months naturally progress; subjects don't. Using a bar chart for genuinely unordered categories is exactly what avoids implying a trend where none exists.
plt.bar(categories, values) draws a bar chart, one bar per category — the right choice for comparing unordered categories side by side, unlike a line chart, which implies (and should only be used for) a genuine ordered sequence.
System Update: We are initializing the Graphing Engine (Matplotlib).
Important: In the labs below, always use plt_show() instead of plt.show() to render the image.
import sys
# 1. Install Matplotlib if missing
if "matplotlib" not in sys.modules:
print("Toolkit: Installing Graphing Engine...")
import pyodide_js
await pyodide_js.loadPackage("micropip")
import micropip
await micropip.install(['matplotlib', 'pandas', 'numpy'])
print("Toolkit: Ready.")
# 2. The Magic Function to Render Graphs
import matplotlib.pyplot as plt
import io, base64
def plt_show():
"""Saves the plot to a buffer and prints it as an HTML image"""
buf = io.BytesIO()
plt.savefig(buf, format='png', bbox_inches='tight')
buf.seek(0)
img_str = base64.b64encode(buf.read()).decode('utf-8')
print(f"<br><img src='data:image/png;base64,{img_str}' style='max-width:100%; border-radius:10px; box-shadow:0 4px 6px rgba(0,0,0,0.1);'/><br>")
plt.clf() # Clear the canvas for the next plot
print("Toolkit: Graphics System Loaded. You can now plot!")
A Bar Chart uses rectangular bars to represent data. The height of the bar corresponds to the value.
Syntax:
plt.bar(categories, values)
import matplotlib.pyplot as plt
# Data
langs = ['Python', 'Java', 'C++']
students = [50, 30, 20]
# Create Bar Chart
# color='teal' makes all bars teal color
plt.bar(langs, students, color='teal')
# Labels
plt.title("Most Popular Languages")
plt.xlabel("Language")
plt.ylabel("Number of Students")
plt_show()
import matplotlib.pyplot as plt
# Data
langs = ['Python', 'Java', 'C++']
students = [50, 30, 20]
# Create Bar Chart
# color='teal' makes all bars teal color
plt.bar(langs, students, color='teal')
# Labels
plt.title("Most Popular Languages")
plt.xlabel("Language")
plt.ylabel("Number of Students")
plt_show()
If you have long names for your categories (e.g., "Introduction to Computer Science"), they won't fit well on the bottom X-axis.
In this case, we use a Horizontal Bar Chart.
Syntax: Simply add an 'h'.
plt.barh(categories, values)
import matplotlib.pyplot as plt
subjects = ['Maths', 'Physics', 'Computer Science', 'English']
marks = [85, 70, 95, 80]
# List of colors for each bar
my_colors = ['red', 'blue', 'green', 'orange']
# Note: For horizontal bars, we use barh()
plt.barh(subjects, marks, color=my_colors)
plt.title("Term 1 Report Card")
plt.xlabel("Marks Obtained") # Note: X-axis is now Marks
plt.ylabel("Subjects") # Note: Y-axis is now Subjects
plt_show()
A bar chart compares categories you already named. This topic covers a chart that instead shows how a set of numeric values is distributed — how many fall into each range.
A histogram groups numeric data into equal-width ranges called bins, and draws one bar per bin, with height showing how many values fall inside it.
plt.hist(values, bins=n)
import matplotlib.pyplot as plt
marks = [45, 52, 67, 71, 74, 78, 81, 85, 88, 91, 95]
plt.hist(marks, bins=5)
plt.xlabel("Marks")
plt.ylabel("Number of Students")
plt.title("Distribution of Marks")
plt.show()
plt.hist(marks, bins=5) splits the full range of marks (45 to 95) into five equal-width ranges, and draws one bar per range, its height showing how many students' marks fall inside it — revealing the overall shape of the data (are most students clustered around the middle, or spread evenly?), which a plain list of numbers doesn't show at a glance.
Note: A histogram looks like a bar chart, but represents something genuinely different — a bar chart's bars are separate, named categories; a histogram's bars are numeric ranges of one single variable, and are always drawn touching, since the ranges are continuous.
A histogram answers a question a simple average can't: two classes could have the exact same average mark, one with every student clustered tightly around it, the other with marks spread from very low to very high — a histogram makes that difference immediately visible, where a single average number hides it completely.
plt.hist(values, bins=n) groups numeric data into equal-width ranges and shows how many values fall in each — revealing a dataset's overall shape and spread, something a single average or a category-based bar chart can't show.
System Update: We are initializing the Graphing Engine (Matplotlib).
Important: In the labs below, always use plt_show() instead of plt.show() to render the image.
import sys
# 1. Install Matplotlib if missing
if "matplotlib" not in sys.modules:
print("Toolkit: Installing Graphing Engine...")
import pyodide_js
await pyodide_js.loadPackage("micropip")
import micropip
await micropip.install(['matplotlib', 'pandas', 'numpy'])
print("Toolkit: Ready.")
# 2. The Magic Function to Render Graphs
import matplotlib.pyplot as plt
import io, base64
def plt_show():
"""Saves the plot to a buffer and prints it as an HTML image"""
buf = io.BytesIO()
plt.savefig(buf, format='png', bbox_inches='tight')
buf.seek(0)
img_str = base64.b64encode(buf.read()).decode('utf-8')
print(f"<br><img src='data:image/png;base64,{img_str}' style='max-width:100%; border-radius:10px; box-shadow:0 4px 6px rgba(0,0,0,0.1);'/><br>")
plt.clf() # Clear the canvas for the next plot
print("Toolkit: Graphics System Loaded. You can now plot!")
A Histogram answers the question: "How many people fall into this range?"
It takes a list of numbers (like Ages) and groups them into buckets (called Bins).
plt.hist(data, bins=5)
import matplotlib.pyplot as plt
# Data: Ages of people
ages = [22, 55, 62, 45, 21, 22, 34, 42, 42, 4, 99, 102, 110, 120, 121]
# Create Histogram
# bins: How many buckets to create
plt.hist(ages, bins=5, color='purple', edgecolor='black')
plt.title("Age Distribution")
plt.xlabel("Age Groups")
plt.ylabel("Number of People (Frequency)")
plt_show()
The most important setting in a Histogram is bins.
import matplotlib.pyplot as plt
ages = [10, 15, 20, 25, 30, 45, 50, 55, 90, 95]
# Custom Cut-off points (Bins)
custom_bins = [0, 18, 40, 80, 120]
plt.hist(ages, bins=custom_bins, color='orange', edgecolor='black')
plt.title("Age Distribution (Custom Groups)")
plt.xlabel("Age Ranges")
plt.ylabel("Count")
plt_show()
Every chart so far compared values against each other. This topic covers a chart with a different job: showing how one whole splits into its parts.
A pie chart represents a whole as a circle, sliced into wedges — each wedge's size proportional to what share of the total it represents.
plt.pie(values, labels=category_names)
import matplotlib.pyplot as plt
streams = ["Science", "Commerce", "Arts"]
students = [120, 90, 60]
plt.pie(students, labels=streams)
plt.title("Students by Stream")
plt.show()
plt.pie(students, labels=streams) draws one wedge per stream, each wedge's size proportional to its share of the total 270 students — Science's wedge (120 of 270) is visibly the largest, closest to half the circle; Arts's (60 of 270) the smallest.
Note: A pie chart only genuinely makes sense when the values represent parts of one meaningful whole that together add up to something complete — comparing unrelated totals (like this year's Science students against last year's total school enrolment) in a pie chart would be misleading, since they aren't parts of the same whole.
A pie chart trades precision for an intuitive, at-a-glance sense of proportion — reading an exact value off a wedge is harder than reading one off a bar chart's height, which is exactly why a pie chart works best with a small number of categories, and exact figures are often labelled directly on or beside each wedge.
plt.pie(values, labels=names) draws a pie chart — a circle split into wedges proportional to each category's share of one meaningful whole. It suits a small number of categories that genuinely sum to a complete total, favouring intuitive proportion over exact readability.
System Update: We are initializing the Graphing Engine (Matplotlib).
Important: In the labs below, always use plt_show() instead of plt.show() to render the image.
import sys
# 1. Install Matplotlib if missing
if "matplotlib" not in sys.modules:
print("Toolkit: Installing Graphing Engine...")
import pyodide_js
await pyodide_js.loadPackage("micropip")
import micropip
await micropip.install(['matplotlib', 'pandas', 'numpy'])
print("Toolkit: Ready.")
# 2. The Magic Function to Render Graphs
import matplotlib.pyplot as plt
import io, base64
def plt_show():
"""Saves the plot to a buffer and prints it as an HTML image"""
buf = io.BytesIO()
plt.savefig(buf, format='png', bbox_inches='tight')
buf.seek(0)
img_str = base64.b64encode(buf.read()).decode('utf-8')
print(f"<br><img src='data:image/png;base64,{img_str}' style='max-width:100%; border-radius:10px; box-shadow:0 4px 6px rgba(0,0,0,0.1);'/><br>")
plt.clf() # Clear the canvas for the next plot
print("Toolkit: Graphics System Loaded. You can now plot!")
A Pie Chart is a circular graph divided into slices. The arc length of each slice is proportional to the quantity it represents.
Syntax:
plt.pie(values, labels=labels)
import matplotlib.pyplot as plt
# Data
expenses = [500, 300, 200]
items = ['Food', 'Books', 'Movies']
# Create Pie Chart
plt.pie(expenses, labels=items)
plt.title("Monthly Expenses")
plt_show()
To make a Pie Chart professional, we often need to "pull out" a specific slice to highlight it, or show the exact percentage numbers.
| Parameter | Function |
|---|---|
| explode | A list of decimals (e.g., [0, 0.2, 0]). Pulls a slice out from the center. |
| autopct | Format string (e.g., '%1.1f%%') to display percentages automatically. |
import matplotlib.pyplot as plt
# Data
modes = ['Bus', 'Car', 'Walk', 'Cycle']
counts = [40, 20, 10, 30]
# Explode Configuration:
# The list matches the order of data. 0 = Normal, 0.1 = Pulled out slightly.
# Here, 'Car' is the 2nd item, so we explode the 2nd value.
my_explode = [0, 0.2, 0, 0]
# Create Pie Chart with bells and whistles
plt.pie(counts, labels=modes, explode=my_explode, autopct='%1.1f%%', shadow=True)
plt.title("How Students Travel to School")
plt_show()
This closing topic of the unit covers three finishing touches: labelling multiple series on one chart, saving a chart to a file instead of only displaying it, and building up a chart across several plot calls.
plt.legend() after giving each plot() call a label=.plt.plot() more than once before plt.show() draws every one of them on the same chart, layered together.import matplotlib.pyplot as plt
months = ["Jan", "Feb", "Mar"]
science_scores = [78, 82, 88]
commerce_scores = [70, 75, 74]
plt.plot(months, science_scores, label="Science")
plt.plot(months, commerce_scores, label="Commerce")
plt.legend()
plt.title("Average Scores by Stream")
plt.savefig("scores_chart.png")
plt.show()
The two plt.plot() calls draw two separate lines on the same chart, each with its own label=. plt.legend() then adds a key showing which line is Science and which is Commerce — without it, two unlabeled lines would be impossible to tell apart. plt.savefig("scores_chart.png") writes the finished chart to an image file before plt.show() displays it.
Note:savefig()must be called beforeshow()— on some setups,show()can clear the chart from memory afterward, leaving nothing left forsavefig()to save if called second.
Layering multiple plot() calls onto one chart, each labelled and distinguished by a legend, is exactly how a single chart compares more than one series at once — Science versus Commerce's trend over the same months, read together rather than as two separate, harder-to-compare charts.
Giving each plot() call a label= and then calling plt.legend() distinguishes multiple lines on one chart. plt.savefig("file.png"), called before show(), saves the chart to an image file. Multiple plot() calls before one show() layer their lines onto the same chart together.
System Update: Initializing Pandas and Matplotlib for the final Unit 1 review.
import sys
if "matplotlib" not in sys.modules:
import pyodide_js
await pyodide_js.loadPackage("micropip")
import micropip
await micropip.install(['matplotlib', 'pandas', 'numpy'])
import matplotlib.pyplot as plt
import pandas as pd
import io, base64
def plt_show():
buf = io.BytesIO()
plt.savefig(buf, format='png', bbox_inches='tight')
buf.seek(0)
img_str = base64.b64encode(buf.read()).decode('utf-8')
print(f"<br><img src='data:image/png;base64,{img_str}' style='max-width:100%; border-radius:10px; box-shadow:0 4px 6px rgba(0,0,0,0.1);'/><br>")
plt.clf()
print(" Toolkit: Ready for Final Unit 1 Review.")
Two small but important concepts remaining:
NaN.df.iterrows(). It gives you the Index and the Row Data for every step of the loop.import pandas as pd
# 1. Series Math (Alignment)
term1 = pd.Series([90, 80, 70], index=['Amit', 'Sumit', 'Ravi'])
term2 = pd.Series([95, 85], index=['Amit', 'Sumit']) # Ravi is missing
print("--- Term 1 + Term 2 ---")
# Ravi will be NaN because he doesn't exist in Term 2
total = term1 + term2
print(total)
# 2. Iteration (df.iterrows)
df = pd.DataFrame({'Name': ['Amit', 'Sumit'], 'Marks': [90, 85]})
print("\n--- Generating Report Cards (Loop) ---")
for index, row in df.iterrows():
print(f"Student: {row['Name']} | Score: {row['Marks']}")
When plotting multiple lines, you need a Legend key to tell them apart.
import matplotlib.pyplot as plt
days = [1, 2, 3, 4]
class_a = [30, 35, 40, 38]
class_b = [25, 30, 32, 30]
# Plotting two lines with 'label'
plt.plot(days, class_a, color='blue', label='Class A')
plt.plot(days, class_b, color='red', label='Class B')
# Add Labels & Legend
plt.title("Class Performance Comparison")
plt.xlabel("Test Number")
plt.ylabel("Average Score")
# This enables the box that says "Blue=Class A, Red=Class B"
plt.legend()
# In a real desktop app, you would use: plt.savefig('my_chart.png')
plt_show()