In the print dialog, choose "Save as PDF" as the destination.
Machine Learning, Week 2
Data Visualization with Matplotlib and Seaborn
Look at the data before you model it: the charts every notebook of the course uses, and when each one fits.
Objectives
- ▸Draw scatter, bar, histogram, line and box plots with Matplotlib, with titles, labels, ticks and legends
- ▸Compute histogram bins and the parts of a boxplot by hand
- ▸Plot straight from a DataFrame with
df.plot.scatteranddf.plot.hist - ▸Compare groups with Seaborn:
boxplot,violinplot,regplot,lmplot - ▸Compute a correlation r and read a correlation heatmap
- ▸Choose the chart that fits the question, and use it in your proposal
Week 2 of the plan
Where This Sits in the Course
- ▸Notebook: Matplotlib_Seaborn_basics, on three small datasets
- ▸Real-world scenario: the plan leaves it open this week, so we use the notebook's own: clinic patients, a month of polls, 178 wines
- ▸Project milestone this week: Project/Paper Proposal
Plan for the Two Hours
| Part | What we do | Time |
|---|---|---|
| 1 | Matplotlib on the clinic data, a histogram by hand | 30 min |
| 2 | The poll data: line plot, a boxplot by hand | 20 min |
| 3 | Pandas and Seaborn on the wine data | 20 min |
| 4 | Correlation, the heatmap, choosing a chart | 15 min |
| 5 | Practice with answers, then takeaways | 35 min |
Open the Notebook in Colab
https://colab.research.google.com/github/
tirthajyoti/Machine-Learning-with-Python/blob/master/
Pandas%20and%20Numpy/Matplotlib_Seaborn_basics.ipynbPart 1
Matplotlib on the Clinic Data
One figure, built call by call
The Clinic Data
Twelve patients: age in years, weight in kg, height in cm
people = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6',
'P7', 'P8', 'P9', 'P10', 'P11', 'P12']
age = [21, 12, 32, 45, 37, 18,
28, 52, 5, 40, 48, 15]
weight = [55, 35, 77, 68, 70, 60,
72, 69, 18, 65, 82, 48]
height = [160, 135, 170, 165, 173, 168,
175, 159, 105, 171, 155, 158]- ▸Plain Python lists, one value per patient, in the same order
- ▸Matplotlib accepts lists, NumPy arrays and DataFrame columns alike
- ▸Question: is there a relationship between these features?
A First Scatter Plot
- ▸One dot per patient: age on x, height on y
import matplotlib.pyplot as plt
plt.scatter(age, height)
plt.show()
Bells and Whistles
Each extra call adds one element to the same figure
| Call | Adds |
|---|---|
plt.figure(figsize=(8, 6)) | figure size in inches |
plt.title, plt.xlabel, plt.ylabel | the texts around the plot |
plt.ylim(100, 200) | the visible y range |
plt.xticks(list) | where x tick marks go |
| Call | Adds |
|---|---|
plt.scatter(c=, s=, edgecolors=) | dot colour, size, outline |
plt.text(x, y, s) | text at a data point |
plt.vlines, plt.hlines | vertical, horizontal lines |
plt.legend(list, loc=2) | a legend, upper left |
Worked Example: Which Ticks?
plt.xticks([i * 5 for i in range(12)],
fontsize=15)[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]range(12) gives i = 0 to 11, times 5: twelve ticks up to 55.
Bar Chart
One number across named items; every bar starts at zero
plt.figure(figsize=(12, 4))
plt.bar(x=people, height=weight,
width=0.6, color='orange',
edgecolor='k', alpha=0.6)
plt.xticks(fontsize=14, rotation=30)
plt.show()- ▸
width=0.6: each bar fills 60% of its slot - ▸
alpha=0.6: partly transparent - ▸
rotation=30: tilted labels

Step 1 of 3
Worked Example: Histogram Bins
plt.hist(weight, color='red', edgecolor='k', alpha=0.75, bins=5)Step 2 of 3
Step 2: Count the Values in Each Bin
A bin holds its left edge, not its right one; the last bin also holds 82
| Bin | Weights inside | Count |
|---|---|---|
| 18 to 30.8 | 18 | 1 |
| 30.8 to 43.6 | 35 | 1 |
| 43.6 to 56.4 | 55, 48 | 2 |
| 56.4 to 69.2 | 68, 60, 69, 65 | 4 |
| 69.2 to 82 | 77, 70, 72, 82 | 4 |
Step 3 of 3
Step 3: Check Against the Plot
- ▸Counts
1, 1, 2, 4, 4add up to 12, one per patient - ▸
plt.histreturns the same counts and edges - ▸The two short bars on the left are the two children

Part 2
The Poll Data
A line through time, and a box around a spread
A Month of Polls, Drawn as Lines
np.random.seed(0) # added
days = np.arange(1, 31)
candidate_A = 50 + days * 0.07 \
+ 2 * np.random.randn(30)
candidate_B = 50 - days * 0.1 \
+ 3 * np.random.randn(30)
plt.style.use('fivethirtyeight')
plt.plot(days, candidate_A, 'o-', c='blue')
plt.plot(days, candidate_B, '^-', c='green')- ▸A: +0.07 a day, B: -0.1 a day, plus random noise
- ▸
plt.style.usestays on for every later plot

The Parts of a Boxplot
- ▸Median: the middle of the sorted values, the line in the box
- ▸Q1 and Q3: the quartiles; the box holds the middle half
- ▸IQR = Q3 - Q1, the length of the box
- ▸Fences at 1.5 IQR beyond the box decide what is unusual
- ▸Whiskers reach the farthest values inside the fences; outliers beyond them are circles
Step 1 of 5
Worked Example: Box of the 12 Heights
Sort, then find the median
sorted: 105 135 155 158 159 160 165 168 170 171 173 175
position: 0 1 2 3 4 5 6 7 8 9 10 11Step 2 of 5
Step 2: The Quartiles Q1 and Q3
Step 3 of 5
Step 3: IQR and the Fences
Step 4 of 5
Step 4: Whiskers and Outliers
Fences: 137.75 and 189.75
| Part | Value | Why |
|---|---|---|
| Lower whisker | 155 | smallest height at or above 137.75 |
| Upper whisker | 175 | largest height at or below 189.75 |
| Outliers | 105, 135 | below the lower fence: P9 and P2, the children |
Step 5 of 5
Step 5: The Mean, and the Check
plt.boxplot(x=[height], showmeans=True)
Try It: Build the Boxplot Step by Step
The Notebook's Boxplot of the Polls
plt.style.use('ggplot')
plt.boxplot(x=[candidate_A, candidate_B],
showmeans=True)
plt.xticks([1, 2], ['Candidate A', 'Candidate B'])| A | B | |
|---|---|---|
| Median | 51.947 | 47.389 |
| Q1 to Q3 | 50.87 to 53.53 | 45.35 to 48.89 |
| Outlier | 46.364 | 54.452 |
| Mean | 51.971 | 47.581 |

Part 3
Pandas and Seaborn on the Wine Data
Name the columns, let the library do the rest
Load the Wine Data
df = pd.read_csv("https://raw.githubusercontent.com/tirthajyoti/"
"Stats_data_science_ValleyML/master/Notebooks/Data/wine.data.csv")
df.head()- ▸
df.shapeis(178, 14): 178 wines, 14 columns - ▸
Classtakes the values 1, 2, 3 (59, 71 and 48 wines) - ▸13 measurements, such as
Alcohol,Flavanoids,Color intensity,Proline
Pandas Plots Straight from a DataFrame
df.plot.scatter('Alcohol', 'Color intensity')
plt.show()- ▸Name the columns; no lists to pass
- ▸Pandas calls Matplotlib for you, so
plt.xlabeland friends still work - ▸Each dot is one wine

Worked Example: 20 Bins of Alcohol
df['Alcohol'].plot.hist(bins=20, figsize=(5, 5),
edgecolor='k')
Seaborn: One Box per Class
import seaborn as sns
sns.boxplot(x='Class', y='Alcohol', data=df)
Violin Plot
sns.violinplot(x='Class', y='Alcohol', data=df)- Violin plot
- A boxplot plus the shape of the distribution: the width at each height shows how many wines have that value.

regplot: A Scatter Plot with a Fitted Line
sns.regplot(x='Alcohol', y='Color intensity',
data=df)- ▸The line that fits the dots best: a linear regression, next week's topic
- ▸The shaded band is the confidence interval: how unsure the line is
- ▸Fitted here: slope 1.560, intercept -15.226

Worked Example: Read the Line at Alcohol 13
lmplot: One Line per Group
sns.lmplot(x='Alcohol', y='Color intensity',
hue='Class', data=df)- ▸
hue='Class'colours the dots by class and fits one line per class
| Class | Slope |
|---|---|
| 1 | 1.094 |
| 2 | 0.464 |
| 3 | 1.527 |

Part 4
Correlation and the Heatmap
Every pair of columns in one picture
The Correlation Coefficient r
- ▸r near 1: high values of x go with high values of y
- ▸r near -1: high x goes with low y
- ▸r near 0: no straight-line relation
Step 1 of 2
Worked Example: r for Four Patients
P1, P4, P6, P10: heights 160, 165, 168, 171 and weights 55, 68, 60, 65
| Patient | Deviations | Product | Squares |
|---|---|---|---|
| P1 | -6, -7 | 42 | 36, 49 |
| P4 | -1, 6 | -6 | 1, 36 |
| P6 | 2, -2 | -4 | 4, 4 |
| P10 | 5, 3 | 15 | 25, 9 |
| Sum | 47 | 66, 98 |
Step 2 of 2
Step 2: Combine into r
The Correlation Matrix and Its Heatmap
corr_mat = np.corrcoef(df, rowvar=False)
corr_mat.shape # (14, 14)
corr_df = pd.DataFrame(corr_mat,
columns=df.columns, index=df.columns)
sns.heatmap(corr_df, linewidth=1,
cmap='plasma')- ▸
rowvar=False: the variables are the columns - ▸14 x 14 = 196 values of r
- ▸Diagonal is 1; the matrix is symmetric
- ▸Yellow: r near 1; dark blue: most negative

Worked Example: Read the Heatmap
| Question | Answer | r |
|---|---|---|
Most related to Class | Flavanoids | -0.847 |
| Next two | OD280/OD315, Total phenols | -0.788, -0.719 |
| Most related pair | Total phenols and Flavanoids | 0.865 |
| Least related pair | Ash and OD280/OD315 | 0.004 |
Choosing a Chart
| Question | Chart |
|---|---|
| Do two numbers move together? | scatter, regplot |
| How does a number change over time? | line |
| How do named items compare? | bar |
| Question | Chart |
|---|---|
| What shape does one column have? | histogram |
| How do groups differ in spread? | box, violin |
| Which of many columns are related? | heatmap |
Try It: The Chart Chooser
Common Mistakes
- ▸A line plot through rows that have no order, such as the 12 patients
- ▸Judging a histogram with one bin count only
- ▸Forgetting that
plt.style.usestays on for later plots - ▸Deleting boxplot outliers without checking them: they are only values beyond 1.5 IQR
- ▸Reading r = 0 as "no relation": r only sees straight-line relations
- ▸Treating a correlation as a cause
Project Milestone: Project/Paper Proposal
- 1State the idea, or the paper you will reproduce, in two or three sentences
- 2Name the dataset: source, rows, columns, and the target column
- 3Draw a histogram of the target, or a bar chart of its classes
- 4Draw a boxplot or scatter of the target against the column you expect to matter most
- 5Draw the correlation heatmap and note the strongest relations
- 6Put the plots in the proposal, with one sentence under each
Practice
Practice: Your Turn
About 30 minutes
About 7 minutes
Practice 1: A Histogram by Hand
| Bin | Values | Count |
|---|---|---|
| 12 to 20 | 12, 15 | 2 |
| 20 to 28 | 21, 22, 26 | 3 |
| 28 to 36 | 30, 31, 33 | 3 |
| 36 to 44 | 38, 44 | 2 |
About 8 minutes
Practice 2: A Boxplot by Hand
| Part | Position | Value |
|---|---|---|
| Q1 | 0.25 x 9 = 2.25 | 55 + 0.25 x 2 = 55.5 |
| Median | 0.5 x 9 = 4.5 | 58 + 0.5 x 2 = 59 |
| Q3 | 0.75 x 9 = 6.75 | 61 + 0.75 x 2 = 62.5 |
About 5 minutes
Practice 3: r by Hand
About 10 minutes
Practice 4: In Colab, on the Wine Data
- 1
sns.boxplot(x='Class', y='Flavanoids', data=df): which class has the highest median? Which boxes show outliers? - 2
df['Proline'].plot.hist(bins=10): how many wines in the tallest bin, between which edges? (np.histogramgives exact numbers) - 3
sns.regplot(x='Total phenols', y='Flavanoids', data=df): slope sign? r withnp.corrcoef? - 4Heatmap of
['Class', 'Alcohol', 'Flavanoids', 'Proline']only: which pair has the largest |r|?
Practice 4: Answer
| Task | Answer |
|---|---|
| 1 | Medians 2.98, 2.03, 0.685: class 1. Outliers: class 2 (5.08), class 3 (1.57) |
| 2 | 41 wines between 558.4 and 698.6 |
| 3 | Positive: slope 1.380, r = 0.865 |
| 4 | Class and Flavanoids, r = -0.847, the same as in the full heatmap |
Key Takeaways
- 1Matplotlib builds a figure call by call: data, then title, labels, ticks, text, lines, legend
- 2A histogram cuts the range into equal bins; the bin count changes the picture
- 3A boxplot shows median, quartiles, whiskers to 1.5 IQR, and outliers beyond
- 4Pandas and Seaborn plot DataFrame columns by name;
x=orhue=splits by group - 5r measures straight-line relation; a heatmap shows every pair at once
- 6Pick the chart from the question: time, compare, shape, spread, relation
Open this lesson
Mahmoud Abas|Data Visualization with Matplotlib and Seaborn