0% found this document useful (0 votes)
4 views19 pages

Graphing in Python

This comprehensive guide on graphing in Python covers essential tools like Matplotlib, Seaborn, and Plotly, focusing on effective data visualization for scientific communication. It provides a systematic approach from basic concepts to advanced techniques, including publication-quality figure production and integration with scientific workflows. The guide is designed for readers with a basic understanding of Python and aims to equip them with the skills to create high-quality visualizations suitable for peer-reviewed journals.

Uploaded by

faisal314159
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views19 pages

Graphing in Python

This comprehensive guide on graphing in Python covers essential tools like Matplotlib, Seaborn, and Plotly, focusing on effective data visualization for scientific communication. It provides a systematic approach from basic concepts to advanced techniques, including publication-quality figure production and integration with scientific workflows. The guide is designed for readers with a basic understanding of Python and aims to equip them with the skills to create high-quality visualizations suitable for peer-reviewed journals.

Uploaded by

faisal314159
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Mastering Graphing in Python Contents

Mastering Graphing in Python:


A Comprehensive Guide from Fundamentals to
Publication-Quality Scientific Visualisation

Research Methodology Series


Covering Matplotlib, Seaborn, Plotly, and Best Practices for Scientific Communication

Abstract
Effective data visualisation is a cornerstone of scientific communication. This guide provides a systematic,
research-oriented treatment of data graphing in Python, progressing from the architecture of Matplotlib
through advanced statistical plots, interactive dashboards, and publication-ready figure production. We
cover figure anatomy, colour theory, perceptual accessibility, multi-panel layout, three-dimensional vi-
sualisation, time-series analysis, and integration with scientific workflows. Code examples throughout
are self-contained and immediately reproducible. Design principles are grounded in the visualisation
literature, with particular attention to principles relevant for peer-reviewed publication. After complet-
ing this guide the reader will be equipped to produce figures that meet the typographic and perceptual
standards of leading scientific journals.

Contents 7 Heatmaps and 2-D Density Estima-


tion 7
7.1 Correlation Heatmaps . . . . . . . 7
7.2 2-D Histograms and Hexbin . . . . 7
1 Introduction 2
1.1 Prerequisites . . . . . . . . . . . . 2 8 Regression and Curve Fitting Plots 8
1.2 Installation . . . . . . . . . . . . . 2 8.1 Simple Linear Regression with Con-
fidence Bands . . . . . . . . . . . . 8
2 The Python Visualisation Ecosystem 2 8.2 Polynomial Regression . . . . . . . 8
2.0.1 Choosing a Library . . . . . 3 8.3 Regression Diagnostics . . . . . . . 8

3 Matplotlib Core Concepts 3 9 Time-Series Visualisation 8


3.1 The Object Hierarchy . . . . . . . 3 9.1 Dual-Axis Time-Series . . . . . . . 8
3.2 The Two Interfaces: pyplot vs. 9.2 Rolling Statistics . . . . . . . . . . 9
Object-Oriented . . . . . . . . . . . 3 9.3 Event Markers . . . . . . . . . . . 9
3.3 Figure and Axes Creation . . . . . 3
3.4 Line Styles, Markers, and Colours . 4 10 Three-Dimensional Visualisation 9
10.1 Surface Plots . . . . . . . . . . . . 9
4 Subplot Layouts and Multi-Panel Fig- 10.2 Contour and Filled Contour . . . . 9
ures 4 10.3 3-D Scatter Plots . . . . . . . . . . 10
4.1 GridSpec for Unequal Panels . . . 4
4.2 Nested GridSpecs . . . . . . . . . . 4 11 Advanced Multi-Panel Research Fig-
4.3 Aligning Panels and Shared Axes . 4 ures 10
11.1 Empirical CDF . . . . . . . . . . . 10
5 Core Plot Types 5 11.2 Confusion Matrix . . . . . . . . . . 10
5.1 Line Plots . . . . . . . . . . . . . . 5
5.2 Scatter Plots . . . . . . . . . . . . 5 12 Colour Theory and Colourmap Selec-
5.3 Bar and Column Charts . . . . . . 5 tion 10
5.4 Histograms and KDE . . . . . . . 5 12.1 Colourmap Categories . . . . . . . 10
12.2 Qualitative Colours for Categorical
6 Statistical Visualisation 6 Data . . . . . . . . . . . . . . . . . 11
6.1 Box Plots . . . . . . . . . . . . . . 6 12.3 Custom Colourmaps . . . . . . . . 11
6.2 Violin Plots . . . . . . . . . . . . . 6
6.3 Error Bars . . . . . . . . . . . . . . 6 13 Axes, Ticks, and Scales 12
6.4 Seaborn for Statistical Graphics . . 6 13.1 Tick Formatters . . . . . . . . . . . 12

1
Mastering Graphing in Python

13.2 Axis Limits and Broken Axes . . . 12 scientific computing language, and its visualisa-
13.3 Annotations and Arrows . . . . . . 12 tion ecosystem is correspondingly rich.
13.4 Inset Axes . . . . . . . . . . . . . . 12
This guide is structured as a learning progres-
14 Interactive Visualisation with Plotly 12 sion. Section 2 surveys the landscape of Python
14.1 Basic Plotly Express . . . . . . . . 13 visualisation libraries and guides library selection.
14.2 Plotly Graph Objects . . . . . . . 13 Section 3 covers the Matplotlib object model in
14.3 Subplots in Plotly . . . . . . . . . 13 depth, because all other libraries build on or in-
terface with it. Subsequent sections treat specific
15 Publication-Quality Output 13 chart families, statistical graphics, and advanced
15.1 Resolution and File Format . . . . 13 topics. The final sections address colour theory
15.2 Figure Dimensions . . . . . . . . . 14 (section 12), accessibility (??), and the production
15.3 Font Sizes and Style . . . . . . . . 14 of print-ready figures (section 15).
15.4 Removing Chart Junk . . . . . . . 14
15.5 Exporting at Publication Quality . 14
1.1 Prerequisites
16 Working with LaTeX Labels 15 Readers are assumed to have working knowledge of
16.1 Enabling LaTeX Rendering . . . . 15 Python 3.9+, NumPy array operations, and basic
Pandas DataFrames. Mathematical prerequisites
17 Reproducible Figure Workflows 15
are limited to undergraduate statistics (e.g.,means,
17.1 Random Seeds . . . . . . . . . . . 15
variances, regression). All code in this guide tar-
17.2 Configuration Files . . . . . . . . . 15
gets the following versions:
17.3 Figure Factory Pattern . . . . . . . 16
• matplotlib ≥ 3.8
18 Integration with Pandas and NumPy 16 • numpy ≥ 1.26
18.1 Plotting Directly from DataFrames 16 • pandas ≥ 2.1
18.2 GroupBy and FacetGrid . . . . . . 16 • seaborn ≥ 0.13
• plotly ≥ 5.18
19 Performance: Large Datasets 16
• scipy ≥ 1.12
19.1 Rasterisation . . . . . . . . . . . . 16
19.2 Datashader for Very Large Data . 17
19.3 Binned Visualisations . . . . . . . 17 1.2 Installation

20 Common Pitfalls and Debugging 17 A clean virtual environment is strongly recom-


20.1 The Ten Most Common Errors . . 17 mended:
20.2 Debugging Layout Issues . . . . . . 17 1 python -m venv venv
2 source venv / bin / activate # Linux /
21 Quick Reference 18 macOS
3 # venv \ Scripts \ activate # Windows
22 Conclusion 18 4
5 pip install matplotlib numpy pandas \
6 scipy seaborn plotly kaleido

Listing 1. Environment setup


1 Introduction

The kaleido package is required to export static


Scientific figures serve two inseparable functions: images from Plotly figures.
they reveal structure in data that is invisible in
tabular form, and they communicate that struc-
2 The Python Visualisation Ecosystem
ture to readers efficiently and honestly. Poor visu-
alisation choices inappropriate colour maps, mis-
leading axis scales, excessive chart junk actively
obstruct scientific understanding and erode trust Python offers a layered visualisation stack. Ta-
in results [1, 2]. Python has become the de facto ble 1 summarises the major libraries.

2
Mastering Graphing in Python

Table 1. Comparison of major Python visualisation 3. Artists every visible element (Line2D,
libraries. PathCollection, Text, Patch, . . . ) is an Artist
attached to an Axes or directly to the Figure.
Library Strengths Best For
Matplotlib Full control, pub- Static figures, Figure 1 illustrates the main components.
lication output, journals
vast ecosystem
Figure 1. Anatomy of a Matplotlib figure showing
Seaborn Statistical de- EDA, statistical
the Figure object, the Axes region, title, axis labels,
faults, tidy-data plots
and legend. Understanding these named components
API
enables precise programmatic control.
Plotly Interactive, web Dashboards, ex-
export, 3-D sup- ploration
port
3.2 The Two Interfaces: pyplot vs. Object-
Bokeh Streaming, web Real-time apps
integration Oriented
Altair Grammar of Rapid prototyp- Matplotlib exposes two distinct interfaces:
graphics, declara- ing
tive 1 import matplotlib . pyplot as plt
HoloViews Large datasets, Big data visualisa- 2 import numpy as np
3
datashader back- tion
end 4 x = np . linspace (0 , 2* np .pi , 200)
5 plt . figure ( figsize =(5 , 3) )
6 plt . plot (x , np . sin (x) , label = ’ sin ( x ) ’)
7 plt . xlabel ( ’x ( rad ) ’)
2.0.1 Choosing a Library. For journal publi- 8 plt . ylabel ( ’y ’)
cations requiring vector graphics, Matplotlib re- 9 plt . title ( ’ State - machine interface ’)
10 plt . legend ()
mains the primary choice. Seaborn builds on
11 plt . tight_layout ()
Matplotlib and provides sensible defaults for sta- 12 plt . savefig ( ’ output . pdf ’)
tistical graphics with minimal code. Plotly is 13 plt . show ()
preferred when interactive exploration or HTML
Listing 2. pyplot (state-machine) interface
delivery is required. These three cover the vast
majority of research visualisation needs, and this
1 import matplotlib . pyplot as plt
guide focuses on them.
2 import numpy as np
3

3 Matplotlib Core Concepts 4 fig , ax = plt . subplots ( figsize =(5 , 3) )


5 x = np . linspace (0 , 2* np .pi , 200)
6 ax . plot (x , np . sin (x) , label = ’ sin ( x ) ’)
7 ax . set_xlabel ( ’x ( rad ) ’)
Understanding Matplotlib’s object hierarchy is 8 ax . set_ylabel ( ’y ’)
9 ax . set_title ( ’ Object - oriented interface ’
the most important investment a Python data an- )
alyst can make. Every element of a figure the 10 ax . legend ()
canvas, the coordinate system, the data traces, 11 fig . tight_layout ()
the tick marks is a Python object that can be 12 fig . savefig ( ’ output . pdf ’ , dpi =300)
13 plt . show ()
inspected and modified programmatically.
Listing 3. Object-oriented (OO) interface preferred
3.1 The Object Hierarchy for research code

Matplotlib organises figures as a tree:


Note
1. Figure ([Link]) the top- For research code, always use the OO inter-
level container. Holds all subplots, colour bars, face. It makes the target of each operation
annotations, and controls the physical dimen- unambiguous, is thread-safe, and integrates
sions and resolution of the output. cleanly with functions that accept an ax argu-
2. Axes ([Link]) the region where ment.
data are plotted. One Figure may contain many
Axes. The Axes object owns the coordinate
system, axis labels, ticks, legends, and title. 3.3 Figure and Axes Creation

3
Mastering Graphing in Python 3.4 Line Styles, Markers, and Colours

Table 2. Commonly used Matplotlib colour


1 # Single axes specifications.
2 fig , ax = plt . subplots ( figsize =(6 , 4) )
3
Format Example
4 # 2 x3 grid of axes
5 fig , axes = plt . subplots ( Named colour ’steelblue’, ’firebrick’
6 nrows =2 , ncols =3 , Hex string ’#2980B9’
7 figsize =(10 , 6) , RGB tuple (0.16, 0.50, 0.73)
8 sharex = ’ col ’ , # share x within RGBA tuple (0.16, 0.50, 0.73, 0.8)
columns
Colourmap val. [Link](0.6)
9 sharey = ’ row ’ , # share y within
rows
CSS4 colour ’RoyalBlue’
10 )
11 # Access as axes [ row , col ]
12 4 Subplot Layouts and Multi-Panel Fig-
13 # Unequal grid via GridSpec ures
14 from matplotlib . gridspec import GridSpec
15 fig = plt . figure ( figsize =(8 , 5) )
16 gs = GridSpec (2 , 3, figure = fig ,
17 hspace =0.4 , wspace =0.35) Multi-panel figures are the standard in peer-
18 ax_top = fig . add_subplot ( gs [0 , :]) #
span all cols
reviewed papers. A well-designed multi-panel lay-
19 ax_bl = fig . add_subplot ( gs [1 , 0]) out communicates comparisons and relationships
20 ax_bm = fig . add_subplot ( gs [1 , 1]) that would require the reader to flip between sep-
21 ax_br = fig . add_subplot ( gs [1 , 2]) arate figures.
Listing 4. Creating figures and axes
4.1 GridSpec for Unequal Panels
1 from matplotlib . gridspec import GridSpec
2 import matplotlib . pyplot as plt
3
4 fig = plt . figure ( figsize =(8 , 4) )
3.4 Line Styles, Markers, and Colours 5 gs = GridSpec (1 , 3,
6 width_ratios =[2 , 1, 1] ,
Figure 2 illustrates the main visual attributes 7 wspace =0.35)
8 ax_main = fig . add_subplot ( gs [0])
available for line plots.
9 ax_right = fig . add_subplot ( gs [1])
10 ax_far = fig . add_subplot ( gs [2])

Listing 6. Unequal column widths with GridSpec


Figure 2. Visual encoding options in Matplotlib.
(a) Line styles: ’-’, ’–’, ’-.’, ’:’. (b) Marker types:
circle, square, triangle, diamond, inverted-triangle,
4.2 Nested GridSpecs
plus. (c) Continuous colour variation using the
viridis colourmap. 1 outer_gs = GridSpec (1 , 2, figure = fig )
2 inner_gs = outer_gs [1]. subgridspec (
3 2, 2, hspace =0.3)
4 ax_left = fig . add_subplot ( outer_gs
[0])
1 ax . plot (x , y , 5 ax_top_right = fig . add_subplot ( inner_gs
2 linestyle = ’ -- ’ , # or ls =’--’ [0 , :])
3 linewidth =2.0 , # or lw =2.0 6 ax_bot_left = fig . add_subplot ( inner_gs
4 color = ’ #2980 B9 ’ , # hex , name , or [1 , 0])
tuple 7 ax_bot_right = fig . add_subplot ( inner_gs
5 marker = ’o ’ , [1 , 1])
6 markersize =5 , # or ms =5
7 markerfacecolor = ’ white ’ , Listing 7. Nested grids for complex layouts
8 markeredgecolor = ’ #2980 B9 ’ ,
9 markeredgewidth =1.2 ,
10 alpha =0.8 , 4.3 Aligning Panels and Shared Axes
11 label = ’ Series A ’)
1 fig , axes = plt . subplots (
Listing 5. Controlling visual attributes 2 3, 1,
3 sharex = True , # linked x - axis
4 figsize =(6 , 7) ,

4
Mastering Graphing in Python

5 gridspec_kw ={ ’ hspace ’: 0.08}


6 )
Listing 10. Scatter plot with size and colour
7 # Remove x tick labels on upper panels
8 for ax in axes [: -1]: encoding
9 ax . tick_params ( labelbottom = False )

Listing 8. Shared axes for aligned multi-panel figures 5.3 Bar and Column Charts
1 import numpy as np
Figure 3 demonstrates a mixed-width grid layout 2
combining a full-width top panel with three equal 3 categories = [ ’A ’, ’B ’ , ’C ’ , ’D ’]
lower panels. 4 means_g1 = [3.2 , 4.1 , 2.8 , 5.0]
5 means_g2 = [2.5 , 3.6 , 3.4 , 4.2]
6 errors_g1 = [0.3 , 0.4 , 0.2 , 0.5]
Figure 3. Mixed GridSpec layout: (a) full-width 7 errors_g2 = [0.25 , 0.35 , 0.3 , 0.45]
8
damped sinusoid with area fill; (b) histogram; (c)
9 x = np . arange ( len ( categories ))
scatter coloured by radial distance; (d) categorical bar
10 width = 0.35
chart. This is a typical pattern for research papers 11
that present a primary result alongside three 12 fig , ax = plt . subplots ( figsize =(5 , 3.5) )
supporting panels. 13 bars1 = ax . bar (x - width /2 , means_g1 ,
14 width , yerr = errors_g1 ,
15 capsize =4 , color = ’ #2980 B9
5 Core Plot Types ’,
16 label = ’ Group 1 ’ , alpha
=0.85)
17 bars2 = ax . bar (x + width /2 , means_g2 ,
5.1 Line Plots 18 width , yerr = errors_g2 ,
19 capsize =4 , color = ’# E74C3C
1 fig , ax = plt . subplots ( figsize =(6 , 3.5) ) ’,
2 20 label = ’ Group 2 ’ , alpha
3 # Mean line =0.85)
4 ax . plot ( time , mean_signal , color = ’ #2 21 ax . set_xticks (x)
C3E50 ’ , 22 ax . set_xticklabels ( categories )
5 lw =2 , label = ’ Mean ’) 23 ax . legend ()
6 24 ax . set_ylabel ( ’ Mean score ’)
7 # Confidence interval as filled band
8 ax . fill_between ( time , Listing 11. Grouped bar chart with error bars
9 mean_signal - 1.96* std_err ,
10 mean_signal + 1.96* std_err ,
11 color = ’ #2 C3E50 ’ , alpha =0.2 ,
5.4 Histograms and KDE
12 label = ’ 95% CI ’)
13 1 from scipy . stats import gaussian_kde
14 ax . set_xlabel ( ’ Time ( s ) ’) 2
15 ax . set_ylabel ( ’ Signal amplitude ’) 3 fig , ax = plt . subplots ( figsize =(5 , 3.5) )
16 ax . legend ( framealpha =0.9) 4
5 # Histogram ( normalised )
Listing 9. Line plot with uncertainty band 6 ax . hist ( data , bins =30 , density = True ,
7 color = ’ #2980 B9 ’ , alpha =0.45 ,
8 edgecolor = ’ white ’ , linewidth
5.2 Scatter Plots =0.4)
9
1 sc = ax . scatter ( 10 # KDE overlay
2 x_data , y_data , 11 xs = np . linspace ( data . min () , data . max ()
3 c = z_values , # colour by 3 rd , 300)
variable 12 kde = gaussian_kde ( data )
4 s = size_values , # area by 4 th 13 ax . plot (xs , kde ( xs ) , color = ’ #2980 B9 ’ ,
variable 14 lw =2.2 , label = ’ KDE ’)
5 cmap = ’ viridis ’ , 15
6 vmin = z_min , vmax = z_max , 16 # Optional : rug plot
7 alpha =0.7 , 17 ax . plot ( data , np . full_like ( data , -0.005)
8 edgecolors = ’ white ’ , ,
9 linewidths =0.4) 18 ’| ’ , color = ’ #2 C3E50 ’ , alpha =0.4 ,
10 plt . colorbar (sc , ax = ax , label = ’Z 19 ms =8)
variable ’) 20

5
Mastering Graphing in Python

21 ax . set_xlabel ( ’ Value ’) 21 for i , ( grp , c) in enumerate (


22 ax . set_ylabel ( ’ Density ’) 22 zip ( groups , colors )):
23 ax . legend () 23 jitter = np . random . normal (i +1 , 0.07 ,
24 len ( grp ))
Listing 12. Histogram with kernel density estimate 25 ax . scatter ( jitter , grp ,
overlay 26 color =c , s =10 ,
27 alpha =0.45 , zorder =4)

Listing 13. Box plot with jitter overlay


6 Statistical Visualisation

6.2 Violin Plots


Statistical plots communicate distributional prop-
erties, uncertainty, and group comparisons. Fig- Violin plots display the probability density of data
ure 4 presents three essential chart types for sta- at each value, mirrored to form a symmetric shape.
tistical research papers. They are superior to box plots when the distribu-
tion is multimodal or heavily skewed.
1 parts = ax . violinplot (
Figure 4. Statistical visualisation patterns. (a) Box
2 data_list ,
plot with superimposed strip (jitter) plot: reveals
3 showmedians = True ,
both distributional shape and individual observations. 4 showextrema = True ,
(b) Error-bar plot with mean ± SD, appropriate for 5 bw_method =0.3) # bandwidth
small samples under normality. (c) Violin plot 6
showing full probability density for four groups with 7 for body in parts [ ’ bodies ’]:
distinct shape (gamma distributed). 8 body . set_facecolor ( ’ #2980 B9 ’)
9 body . set_alpha (0.7)
10 parts [ ’ cmedians ’ ]. set_color ( ’ white ’)
6.1 Box Plots
Listing 14. Violin plot
A standard box plot encodes the median (Q2 ), in-
terquartile range (Q1 –Q3 ), whiskers extending to
Q1 − 1.5 IQR and Q3 + 1.5 IQR, and outliers as 6.3 Error Bars
individual points. The addition of a strip (jitter) 1 ax . errorbar (
plot on top of the box plot sometimes called a 2 x , y_mean ,
beeswarm or strip-box is increasingly required by 3 yerr =[ y_lower_err , y_upper_err ],
4 fmt = ’o - ’ ,
journals because it shows the full data alongside 5 color = ’ #2980 B9 ’ ,
the summary statistics. 6 capsize =5 ,
1 import numpy as np 7 capthick =1.3 ,
2 import matplotlib . pyplot as plt 8 elinewidth =1.2 ,
3
9 markersize =6 ,
4 groups = [ np . random . normal (mu , 1.5 , 40) 10 linewidth =1.6)
5 for mu in [0 , 1, 2.5 , 4]]
6
Listing 15. Error bar plot with asymmetric errors
7 fig , ax = plt . subplots ( figsize =(5 , 3.5) )
8 bp = ax . boxplot ( groups ,
9 patch_artist = True , 6.4 Seaborn for Statistical Graphics
10 medianprops = dict ( color = ’
white ’ , Seaborn provides a higher-level interface for statis-
11 linewidth tical plots with tidy data (each row an observation,
=1.8) each column a variable).
,
12 widths =0.5) 1 import seaborn as sns
13 2 import pandas as pd
14 colors = [ ’ #2 C3E50 ’ , ’# E74C3C ’ , 3
15 ’ #2980 B9 ’ , ’ #27 AE60 ’] 4 # Assume df has columns : ’ group ’, ’ score
16 for patch , c in zip ( bp [ ’ boxes ’], colors ) ’, ’ condition ’
: 5 sns . violinplot ( data =df ,
17 patch . set_facecolor (c) 6 x= ’ group ’ , y= ’ score ’ ,
18 patch . set_alpha (0.75) 7 hue = ’ condition ’ ,
19 8 palette = ’ Set2 ’ ,
20 # Jitter overlay 9 inner = ’ box ’,

6
Mastering Graphing in Python

10 ax = ax ) 21 for j in range (n ):
11 22 v = corr . values [i , j]
12 sns . stripplot ( data =df , 23 ax . text (j , i , f ’{ v :.2 f} ’ ,
13 x= ’ group ’, y= ’ score ’ , 24 ha = ’ center ’ ,
14 hue = ’ condition ’ , 25 va = ’ center ’ ,
15 dodge = True , 26 fontsize =7 ,
16 alpha =0.35 , size =3 , 27 color = ’w ’ if abs (v) >0.6
17 palette = ’ dark :#333 ’ , 28 else ’k ’)
18 ax = ax ) 29 ax . set_xticks ( range (n))
30 ax . set_yticks ( range (n))
Listing 16. Seaborn categorical statistics 31 ax . set_xticklabels (
32 corr . columns , rotation =40 ,
1 g = sns . pairplot ( 33 ha = ’ right ’)
2 df [[ ’ feature_a ’ , ’ feature_b ’, 34 ax . set_yticklabels ( corr . columns )
3 ’ feature_c ’ , ’ label ’]] ,
4 hue = ’ label ’,
Listing 18. Annotated correlation heatmap
5 diag_kind = ’ kde ’ ,
6 plot_kws = dict ( alpha =0.5 , s =15) ,
7 diag_kws = dict ( fill = True , alpha =0.4) )
8 g. fig . suptitle ( ’ Pair Plot ’ , y =1.02)
9 g. fig . savefig ( ’ pairplot . pdf ’ , 7.2 2-D Histograms and Hexbin
10 dpi =300 ,
11 bbox_inches = ’ tight ’) 1 # Method 1: imshow with histogram2d
2 h , xe , ye = np . histogram2d (x , y , bins
Listing 17. Seaborn pair plot for exploratory =30)
analysis 3 ax . imshow (h.T , origin = ’ lower ’ ,
4 cmap = ’ YlOrRd ’ ,
5 extent =[ xe [0] , xe [ -1] ,
6 ye [0] , ye [ -1]] ,
7 Heatmaps and 2-D Density Estima- 7 aspect = ’ auto ’)
tion 8
9 # Method 2: hexbin ( better for large N )
10 hb = ax . hexbin (x , y , gridsize =25 ,
11 cmap = ’ inferno ’ ,
12 mincnt =1)
13 plt . colorbar (hb , ax = ax , label = ’ Count ’)
Figure 5. Two-dimensional visualisations. (a)
Correlation matrix heatmap rendered with the Listing 19. 2-D histogram and hexbin plots
diverging RdBu_r colourmap; cell values annotated.
(b) Two-dimensional histogram of a bivariate normal
sample showing estimated joint density.
1 from scipy . stats import gaussian_kde
2
3 xy = np . vstack ([x , y ])
7.1 Correlation Heatmaps 4 kde = gaussian_kde ( xy )
5 xi , yi = np . mgrid [x. min () :x. max () :80 j ,
1 import numpy as np
6 y. min () :y. max () :80 j ]
2 import pandas as pd
7 zi = kde ( np . vstack ([ xi . ravel () ,
3 import matplotlib . pyplot as plt
8 yi . ravel () ]) )
4
9 zi = zi . reshape ( xi . shape )
5 corr = df . corr ()
10
6
11 ax . contourf (xi , yi , zi ,
7 fig , ax = plt . subplots (
12 levels =12 , cmap = ’ Blues ’)
8 figsize =(5 , 4) )
13 ax . contour (xi , yi , zi ,
9 im = ax . imshow (
14 levels =6 ,
10 corr . values ,
15 colors = ’ white ’ ,
11 cmap = ’ RdBu_r ’ ,
16 linewidths =0.5 ,
12 vmin = -1 , vmax =1 ,
17 alpha =0.7)
13 aspect = ’ auto ’)
14 plt . colorbar (im , ax = ax ,
Listing 20. 2-D KDE contour plot
15 fraction =0.046 ,
16 label = ’ Pearson r ’)
17
18 # Annotate cells
19 n = len ( corr )
20 for i in range (n): 8 Regression and Curve Fitting Plots

7
Mastering Graphing in Python

8.3 Regression Diagnostics


A residual plot is produced by plotting ei = yi −
ŷi against the fitted values ŷi or the predictor xi .
Figure 6. Regression visualisation. (a) OLS
regression line with 95% confidence interval band; Patterns in residuals (e.g.,fan shapes, curvature)
scatter points are the simulated observations. (b) indicate violations of OLS assumptions and must
Residual plot used to assess the constant-variance be reported.
assumption; the absence of systematic patterns
1 yhat = slope *x + intercept
supports the OLS assumptions. 2 resids = y - yhat
3
4 fig , axes = plt . subplots (1 , 2,
8.1 Simple Linear Regression with Confi- 5 figsize =(7 , 3)
)
dence Bands 6 # Residuals vs . fitted
1 from scipy . stats import linregress 7 axes [0]. scatter ( yhat , resids , s =18 ,
2 import numpy as np 8 alpha =0.65)
3
9 axes [0]. axhline (0 , ls = ’ -- ’, lw =1.2 ,
4 slope , intercept , r , p , se = \ 10 color = ’ gray ’)
5 linregress (x , y) 11 axes [0]. set_xlabel ( ’ Fitted values ’)
6 n = len (x) 12 axes [0]. set_ylabel ( ’ Residuals ’)
13
7 xfit = np . linspace (x. min () , x. max () ,
300) 14 # Q - Q plot
8 yfit = slope * xfit + intercept 15 from scipy . stats import probplot
9
16 probplot ( resids , plot = axes [1])
10 # SE of fitted values 17 axes [1]. set_title ( ’ Normal Q - Q ’)
11 s_res = np . sqrt ( np . sum (
12 ( y - ( slope *x+ intercept )) **2
Listing 23. Residual diagnostic plot
13 ) / (n -2) )
14 x_mean = x . mean ()
15 se_fit = s_res * np . sqrt ( 9 Time-Series Visualisation
16 1/ n + ( xfit - x_mean ) **2 /
17 np . sum (( x - x_mean ) **2) )
18
19 ax . scatter (x , y , s =22 , alpha =0.6)
20 ax . plot ( xfit , yfit , lw =2 ,
21 label =f ’ $r ^2={ r **2:.3 f } $ ’) Figure 7. Dual-axis time-series figure combining a
22 ax . fill_between ( precipitation bar chart (right y-axis, blue) with a
23 xfit , Savitzky-Golay smoothed temperature trace (left
24 yfit - 1.96* se_fit , y-axis, red). The raw temperature signal is shown in
25 yfit + 1.96* se_fit , faint red to indicate measurement noise.
26 alpha =0.2 ,
27 label = ’ 95% CI ’)
28 ax . legend () 9.1 Dual-Axis Time-Series
Listing 21. OLS with 95% confidence band 1 import pandas as pd
2 import matplotlib . pyplot as plt
3 from scipy . signal import savgol_filter
4
8.2 Polynomial Regression 5 fig , ax1 = plt . subplots ( figsize =(8 , 3.5)
)
1 from numpy . polynomial import polynomial 6 ax2 = ax1 . twinx ()
as P 7
2 8 # Bar series on right axis
3 deg = 3 9 ax2 . bar ( df . index , df [ ’ precip ’],
4 coeffs = P . polyfit (x , y , deg ) 10 width =1 , color = ’ #2980 B9 ’ ,
5 yfit = P . polyval ( xfit , coeffs ) 11 alpha =0.35 , label = ’ Precip ( mm ) ’)
6 ax . plot ( xfit , yfit , ’ -- ’ , 12
7 lw =2 , 13 # Smooth line on left axis
8 label =f ’ Polynomial ( deg ={ deg }) ’) 14 smooth = savgol_filter (
15 df [ ’ temperature ’], 21 , 3)
Listing 22. Polynomial regression overlay 16 ax1 . plot ( df . index , df [ ’ temperature ’],
17 color = ’# E74C3C ’ , lw =0.5 ,
18 alpha =0.4)

8
Mastering Graphing in Python 9.2 Rolling Statistics

19 ax1 . plot ( df . index , smooth , 10 Three-Dimensional Visualisation


20 color = ’# E74C3C ’ , lw =2.0 ,
21 label = ’ Temp ( smoothed ) ’)
22
23 ax1 . set_ylabel ( ’ Temperature ( C ) ’ ,
24 color = ’# E74C3C ’)
25 ax2 . set_ylabel ( ’ Precipitation ( mm ) ’ , Figure 8. Three-dimensional visualisation of the 2-D

26 color = ’ #2980 B9 ’) sinc function z = sinc( x2 + y 2 ). (a) Surface plot
27
with viridis colormap. (b) Contour projection on
28 # Combined legend
the xy-plane, which is more publication-appropriate
29 h1 , l1 = ax1 . get_legend_handles_labels ()
30 h2 , l2 = ax2 . get_legend_handles_labels ()
for print because it avoids perspective distortion.
31 ax1 . legend ( h1 +h2 , l1 +l2 ,
32 loc = ’ upper left ’)

Listing 24. Twin-axis time-series plot 10.1 Surface Plots


1 from mpl_toolkits . mplot3d import Axes3D
2 import numpy as np
9.2 Rolling Statistics 3 import matplotlib . pyplot as plt
4
1 window = 30 # days 5 fig = plt . figure ( figsize =(6 , 4) )
2 roll_mean = ( df [ ’ value ’] 6 ax = fig . add_subplot (111 , projection = ’3
3 . rolling ( window , center = d ’)
True ) 7
4 . mean () ) 8 x = np . linspace ( -4 , 4, 80)
5 roll_std = ( df [ ’ value ’] 9 y = np . linspace ( -4 , 4, 80)
6 . rolling ( window , center = 10 X , Y = np . meshgrid (x , y)
True ) 11 Z = np . sinc ( np . sqrt (X **2 + Y **2) )
7 . std () ) 12
8 13 surf = ax . plot_surface (
9 ax . plot ( df . index , roll_mean , 14 X, Y, Z,
10 lw =2 , label =f ’{ window }- day mean ’ 15 cmap = ’ viridis ’ ,
) 16 edgecolor = ’ none ’ ,
11 ax . fill_between ( 17 alpha =0.92 ,
12 df . index , 18 rstride =2 , cstride =2)
13 roll_mean - 2* roll_std , 19
14 roll_mean + 2* roll_std , 20 fig . colorbar ( surf , ax =ax ,
15 alpha =0.2 , 21 shrink =0.55 , label = ’z ’)
16 label = ’ 95% band ’) 22 ax . set_xlabel ( ’X ’); ax . set_ylabel ( ’Y ’)
23 ax . set_zlabel ( ’Z ’)
Listing 25. Rolling mean and confidence band 24 ax . view_init ( elev =30 , azim = -60)

Listing 27. 3-D surface plot

9.3 Event Markers


1 events = pd . to_datetime (
2 [ ’ 2022 -03 -15 ’ , ’ 2022 -07 -01 ’,
3 ’ 2022 -11 -20 ’ ]) 10.2 Contour and Filled Contour
4 labels = [ ’ Intervention A ’ ,
5 ’ Policy change ’ , 1 cf = ax . contourf (X , Y , Z ,
6 ’ Phase 3 start ’] 2 levels =16 ,
7
3 cmap = ’ viridis ’)
8 for date , lbl in zip ( events , labels ): 4 cs = ax . contour (X , Y , Z ,
9 ax . axvline ( date , color = ’ gray ’ , 5 levels =8 ,
10 lw =1.2 , ls = ’ -- ’ , 6 colors = ’ white ’ ,
11 alpha =0.7) 7 linewidths =0.5 ,
12 ax . text ( date , ax . get_ylim () [1]*0.97 , 8 alpha =0.6)
13 lbl , rotation =45 , 9 ax . clabel (cs , inline = True ,
14 ha = ’ right ’ , va = ’ top ’ , 10 fontsize =7)
15 fontsize =7.5 , color = ’ gray ’) 11 plt . colorbar (cf , ax = ax )

Listing 26. Annotating events on a time-series Listing 28. Contour plot

9
Mastering Graphing in Python 10.3 3-D Scatter Plots

Warning
1 from sklearn . metrics import (
Three-dimensional surface plots are often mis- 2 confusion_matrix ,
leading in print because the perspective pro- ConfusionMatrixDisplay )
3
jection hides portions of the surface and values 4 cm = confusion_matrix ( y_true , y_pred )
depend on viewing angle. Prefer contour pro- 5 disp = ConfusionMatrixDisplay (
jections or heatmaps for publication unless the 6 confusion_matrix =cm ,
3-D structure itself is the scientific message. 7 display_labels = class_names )
8 disp . plot ( cmap = ’ Blues ’ , ax = ax ,
9 colorbar = True )
10 ax . set_title ( ’ Confusion matrix ’)
10.3 3-D Scatter Plots
1 sc = ax . scatter (xs , ys , zs , Listing 31. Confusion matrix heatmap
2 c= c_values ,
3 cmap = ’ plasma ’ ,
4 s =20 ,
5 alpha =0.7) 12 Colour Theory and Colourmap Selec-
6 fig . colorbar (sc , ax = ax , label = ’ Value ’) tion
Listing 29. 3-D scatter with colour encoding

Colour is a primary encoding channel in scientific


11 Advanced Multi-Panel Research Fig- visualisation. Poor colourmap choices introduce
ures perceptual distortions that invalidate quantitative
reading [3].

12.1 Colourmap Categories


Figure 9. Six-panel research figure demonstrating
diverse chart types in a unified style. (a) KDE Table 3. Colourmap categories and recommended
distributions for three experimental conditions. (b) choices.
Step histograms with normalised density for two
groups. (c) Stacked bar chart for quarterly product
Category Description Examples
breakdown. (d) Grouped scatter with per-group OLS
fits. (e) Empirical CDFs for three parameter settings. Sequential Monotone viridis,
(f) Confusion matrix visualisation with annotation. increase plasma,
cividis
Diverging Centred at RdBu_r,
11.1 Empirical CDF zero coolwarm,
bwr
1 import numpy as np Qualitative Categorical Set2, tab10,
2
Paired
3 def plot_ecdf ( ax , data , ** kwargs ):
Cyclic Angular/periodic
hsv,
4 x = np . sort ( data )
5 y = np . arange (1 , len (x) +1) / len (x )
twilight
6 ax . step (x , y , where = ’ post ’ , ** kwargs Perceptually Uniform Constant viridis,
) perceptual inferno
7 ax . set_ylim (0 , 1.05) gradient
8 ax . set_ylabel (
9 ’ Cumulative probability ’)
10
11 for label , grp in df . groupby ( ’ condition ’ Warning
):
12 plot_ecdf ( ax , grp [ ’ value ’],
Never use the jet colourmap for scientific
13 label = label , lw =1.8) data. It has abrupt perceptual transitions (par-
14 ax . legend () ticularly around cyan and yellow) that intro-
duce artefacts not present in the underlying
Listing 30. ECDF plot
data, mislead readers about gradient magni-
tudes, and is inaccessible to people with deuter-
anopia [3].
11.2 Confusion Matrix

10
Mastering Graphing in Python 12.2 Qualitative Colours for Categorical Data

12.2 Qualitative Colours for Categorical 25 \ begin { figure }[ H]


Data 26 \ centering
27 \ includegraphics [ width =\ linewidth ]{
For a small number of categories (≤ 8), use a qual- fig_colorblind }
itative palette. The Wong (2011) palette [4] is 28 \ caption { Palette comparison .
29 (a) A red / green / blue / cyan palette :
designed for colour-vision deficiency (CVD) acces- the red and green series are
sibility: 30 indistinguishable under deuteranopia
simulation .
1 WONG = { 31 (b) The Wong (2011) CVD - safe palette
2 ’ black ’: ’ #000000 ’ , : all four series remain
3 ’ orange ’: ’# E69F00 ’ , visually
4 ’ sky ’: ’ #56 B4E9 ’ , 32 distinct under the three major forms
5 ’ green ’: ’ #009 E73 ’ , of CVD .}
6 ’ yellow ’: ’# F0E442 ’ , 33 \ label { fig : colorblind }
7 ’ blue ’: ’ #0072 B2 ’ , 34 \ end { figure }
8 ’ vermil ’: ’# D55E00 ’ , 35
9 ’ pink ’: ’# CC79A7 ’ , 36 \ subsection { Guidelines for Accessible
10 } Figures }
11
37
12 colors = list ( WONG . values () ) 38 \ begin { enumerate }[ leftmargin =* , nosep ]
13 for i , ( label , grp ) in enumerate ( 39 \ item Use the \ textbf { Wong } or \ textbf
14 df . groupby ( ’ group ’)): { Okabe - Ito } palettes for
15 ax . plot ( grp [ ’x ’], grp [ ’y ’], categorical
16 color = colors [i % len ( colors ) 40 data .
], 41 \ item Use \ textbf { viridis }, \ textbf {
17 label = label , lw =1.8) plasma }, or \ textbf { cividis } for
42 sequential continuous data .
Listing 32. Wong CVD-safe palette
43 \ item \ textbf { Never } rely on colour as
the sole encoding channel ;
reinforce
12.3 Custom Colourmaps 44 with line style , marker shape , or
pattern .
1 from matplotlib . colors import ( 45 \ item Use sufficient \ textbf { luminance
2 LinearSegmentedColormap ) contrast } ($\ geq 3{:}1 $ for non -
3 text
4 cmap = LinearSegmentedColormap . from_list 46 graphical elements , per WCAG ~2.1
( criterion ~1.4.11) .
5 ’ custom_bwr ’ , 47 \ item Test figures with a CVD
6 [ ’ #2980 B9 ’ , ’ white ’, ’# E74C3C ’], simulator (\ eg \ texttt { daltonize }
7 N =256) Python
8 48 package , or \ texttt { Coblis } web tool
9 # Diverging with a central white ).
10 im = ax . imshow ( data , 49 \ end { enumerate }
11 cmap = cmap , 50
12 vmin =- vmax , vmax = vmax ) 51 \ begin { lstlisting }[ caption ={ Combining
13 \ end { lstlisting > colour and linestyle / marker for
14 accessibility }]
15 % 52 styles = [ ’ -o ’ , ’ --s ’ , ’ -.^ ’ , ’: D ’]
16 \ section { Accessibility and Colour - Vision 53 palette = [ ’ #0072 B2 ’ , ’# E69F00 ’ ,
Deficiency } 54 ’# CC79A7 ’ , ’ #009 E73 ’]
17 \ label { sec : accessibility } 55
18 % 56 for i , ( series , s , c) in enumerate (
19 57 zip ( data_list , styles , palette )) :
20 Approximately 8\% of males and 0.5\% of 58 ax . plot (x , series , s ,
females of European descent have 59 color =c ,
some 60 lw =1.8 , ms =5 ,
21 form of colour - vision deficiency ( CVD ) , 61 label =f ’ Condition { i +1} ’)
most commonly deuteranopia ( red -
green Listing 33. Defining custom linear colourmaps
22 confusion ) . Scientific figures
accessible to this population
require careful
23 palette design .
24 13 Axes, Ticks, and Scales

11
Mastering Graphing in Python

22 kwargs . update (
23 transform = ax_bot . transAxes )
24 ax_bot . plot (( -d , +d) ,
25 (1 -d , 1+ d) , ** kwargs )
Figure 10. Tick and axis formatting options. (a) 26 ax_bot . plot ((1 -d , 1+ d) ,
Logarithmic x-axis with LogFormatterSciNotation. 27 (1 -d , 1+ d) , ** kwargs )
(b) Both axes formatted as percentages using
PercentFormatter. (c) Custom categorical x-tick Listing 35. Broken y-axis for disparate scale ranges
labels (month names, rotated 45ř).

13.1 Tick Formatters 13.3 Annotations and Arrows


1 import matplotlib . ticker as ticker 1 ax . annotate (
2 2 ’ Peak response ’ ,
3 # Scientific notation 3 xy =( x_peak , y_peak ) , # tip
4 ax . xaxis . set_major_formatter ( 4 xytext =( x_peak +0.8 ,
5 ticker . ScalarFormatter ( 5 y_peak *0.7) , # text
6 useMathText = True )) pos
7 ax . ticklabel_format ( 6 fontsize =8 ,
8 style = ’ sci ’, axis = ’x ’ , 7 arrowprops = dict (
9 scilimits =( -2 , 4) ) 8 arrowstyle = ’ -> ’ ,
10 9 color = ’ black ’ ,
11 # Percentage (0 -1 normalised ) 10 lw =1.2 ,
12 ax . yaxis . set_major_formatter ( 11 connectionstyle =
13 ticker . PercentFormatter ( xmax =1) ) 12 ’ arc3 , rad =0.25 ’) ,
14 13 ha = ’ center ’)
15 # Custom lambda formatter
16 ax . xaxis . set_major_formatter ( Listing 36. Annotation with curved arrow
17 ticker . FuncFormatter (
18 lambda v , _:
19 f ’{ v /1 e6 :.1 f } M ’))
20 13.4 Inset Axes
21 # Log scale
22 ax . set_xscale ( ’ log ’) 1 from mpl_toolkits . axes_grid1 .
23 ax . xaxis . set_major_formatter ( inset_locator \
24 ticker . LogFormatterSciNotation () ) 2 import inset_axes
3

Listing 34. Custom tick formatters 4 ax_inset = inset_axes (


5 ax ,
6 width = ’ 35% ’ , height = ’ 35% ’ ,
7 loc = ’ upper right ’ ,
13.2 Axis Limits and Broken Axes 8 bbox_to_anchor = ax . bbox ,
1 fig , ( ax_top , ax_bot ) = plt . subplots ( 9 bbox_transform = ax . transAxes )
2 2 , 1 , sharex = True , 10

3 figsize =(5 , 4) , 11 ax_inset . plot ( x_zoom , y_zoom ,


4 gridspec_kw ={ ’ height_ratios ’ :[1 ,3]}) 12 color = ’# E74C3C ’ , lw =1.4)
5 fig . subplots_adjust ( hspace =0.06) 13 ax_inset . set_xlim (x1 , x2 )
6 14 ax_inset . set_ylim (y1 , y2 )
7 ax_top . plot (x , y) 15 ax_inset . tick_params (
8 ax_bot . plot (x , y) 16 labelsize =6)
9
10 ax_top . set_ylim (900 , 1000) # outliers Listing 37. Inset zoom panel
11 ax_bot . set_ylim (0 , 150) # main data
12
13 # Diagonal cut marks
14 d = 0.01 14 Interactive Visualisation with Plotly
15 kwargs = dict ( transform = ax_top . transAxes
,
16 color = ’k ’, clip_on = False ,
17 lw =1.0) Plotly generates interactive HTML figures that
18 ax_top . plot (( -d , +d) ,
19 (-d , +d) , ** kwargs )
can be embedded in web applications, Jupyter
20 ax_top . plot ((1 -d , 1+ d) , notebooks, and exported to static images for pub-
21 (-d , +d) , ** kwargs ) lication via kaleido.

12
Mastering Graphing in Python 14.1 Basic Plotly Express

14.1 Basic Plotly Express 3 import plotly . graph_objects as go


4
1 import plotly . express as px 5 fig = make_subplots (
2
6 rows =2 , cols =2 ,
3 fig = px . scatter ( 7 subplot_titles =[
4 df , 8 ’ Panel A ’, ’ Panel B ’ ,
5 x = ’ weight ’ , y= ’ mpg ’, 9 ’ Panel C ’, ’ Panel D ’],
6 color = ’ origin ’ , 10 shared_xaxes = False ,
7 size = ’ horsepower ’ , 11 vertical_spacing =0.12)
8 hover_data =[ ’ name ’], 12
9 trendline = ’ ols ’ , 13 fig . add_trace (
10 title = ’ Fuel efficiency dataset ’ , 14 go . Scatter (x=x , y=y1 ,
11 labels ={ ’ mpg ’: ’ Miles per gallon ’ , 15 name = ’ Series 1 ’) ,
12 ’ weight ’: ’ Weight ( lb ) ’}, 16 row =1 , col =1)
13 template = ’ plotly_white ’ , 17 fig . add_trace (
14 color_discrete_sequence = 18 go . Bar (x= cats , y= vals ,
15 px . colors . qualitative . Safe ) 19 name = ’ Categories ’) ,
16 fig . show () 20 row =1 , col =2)
17 fig . write_image ( ’ scatter . pdf ’ , 21 # ... add more traces
18 scale =2) # 2x 22
resolution 23 fig . update_layout (
24 height =600 , width =800 ,
Listing 38. Plotly Express scatter with trendline 25 title_text = ’ Multi - panel research
figure ’,
26 template = ’ plotly_white ’)
14.2 Plotly Graph Objects
Listing 40. Plotly multi-panel figure
1 import plotly . graph_objects as go
2
3 fig = go . Figure ()
4
5 fig . add_trace ( go . Scatter (
6 x =x , y = y_mean , 15 Publication-Quality Output
7 mode = ’ lines ’ ,
8 name = ’ Mean ’,
9 line = dict ( color = ’ #2980 B9 ’ , width =2) )
)
10 Journals impose strict requirements on figure res-
11 fig . add_trace ( go . Scatter ( olution, font size, colour space, and file format.
12 x = np . concatenate ([x , x [:: -1]]) , Adhering to these requirements from the outset
13 y = np . concatenate (
14 [ y_upper , y_lower [:: -1]]) , avoids costly revisions.
15 fill = ’ toself ’ ,
16 fillcolor = ’ rgba (41 ,128 ,185 ,0.2) ’ ,
17 line = dict ( color = ’ rgba (0 ,0 ,0 ,0) ’) ,
18 name = ’ 95% CI ’ , 15.1 Resolution and File Format
19 showlegend = True ))
20
21 fig . update_layout (
Table 4. Standard journal figure specifications.
22 template = ’ plotly_white ’ ,
23 xaxis_title = ’ Time ’ , Format Use Case DPI
24 yaxis_title = ’ Value ’,
PDF Vector output, La- ∞ (vector)
25 font = dict ( family = ’ serif ’ , size =12) ,
26 legend = dict ( TeX, all line art
27 x =0.02 , y =0.98 , SVG Web, vector, scal- ∞ (vector)
28 bordercolor = ’ lightgrey ’, able
29 borderwidth =1) ) EPS Legacy journal sub- ∞ (vector)
mission
Listing 39. Multi-trace Plotly figure TIFF Raster pho- 300–600
tographs, mi-
crographs
14.3 Subplots in Plotly PNG Raster, lossless, 300 minimum
supplementary
1 from plotly . subplots import (
JPEG Photographs only 300 minimum
2 make_subplots )

13
Mastering Graphing in Python 15.2 Figure Dimensions

Note 23 ’ axes . spines . right ’: False ,


24
Always submit figures as PDF or EPS for line 25 # Saving
art, charts, and plots. These are vector for- 26 ’ savefig . dpi ’: 300 ,
mats: they scale without pixelation and pro- 27 ’ savefig . bbox ’: ’ tight ’ ,
duce the sharpest output at any print resolu- 28 ’ savefig . pad_inches ’: 0.02 ,
29 ’ pdf . fonttype ’: 42 , # embed
tion. fonts
30 ’ ps . fonttype ’: 42 ,
31 })
15.2 Figure Dimensions
Listing 42. Setting a consistent publication style
Journals specify figures in physical units. Com-
mon column widths:
Tip
• Single column: 85 mm (≈ 3.35 in)
• 1.5 column: 114 mm (≈ 4.5 in) Set [Link] = 42 and [Link] = 42
• Double column: 174 mm (≈ 6.85 in) to embed fonts as TrueType in exported PDFs
and EPS files. Without this, text may appear
1 mm = 1/25.4 # 1 mm in inches
2
incorrectly on systems that lack the same fonts.
3 fig , ax = plt . subplots (
4 figsize =(85* mm , 65* mm )) # single
col . 15.4 Removing Chart Junk
5
6 # Always save with bbox_inches =’ tight ’ Tufte’s data-ink ratio principle [1] states that every
7 # to prevent label clipping ink mark should convey data or enable data inter-
8 fig . savefig ( ’ figure1 . pdf ’ , pretation. Remove elements that do not serve this
9 dpi =300 ,
function:
10 bbox_inches = ’ tight ’,
11 pad_inches =0.02) 1 # Remove top and right spines
2 ax . spines [ ’ top ’ ]. set_visible ( False )
Listing 41. Setting figure dimensions in mm 3 ax . spines [ ’ right ’]. set_visible ( False )
4
5 # Reduce tick length
15.3 Font Sizes and Style 6 ax . tick_params ( length =3 ,
7 width =0.8)
Journal figures must use readable fonts. A min- 8

imum of 7 pt for tick labels and 8–9 pt for axis 9 # Remove tick marks on minor grid
10 ax . tick_params ( which = ’ minor ’ ,
labels is standard.
11 length =0)
1 import matplotlib as mpl 12

2 13 # Use subtle grid ( optional )


3 mpl . rcParams . update ({ 14 ax . yaxis . grid ( True ,
4 # Typography 15 linestyle = ’: ’ ,
5 ’ font . family ’: ’ serif ’, 16 linewidth =0.5 ,
6 ’ font . serif ’: [ ’ Times New 17 color = ’# CCCCCC ’ ,
Roman ’ , 18 alpha =0.7)
7 ’ DejaVu Serif ’ 19 ax . set_axisbelow ( True )
], 20

8 ’ font . size ’: 9, 21 # Tight layout


9 ’ axes . labelsize ’: 9, 22 fig . tight_layout ( pad =0.5)
10 ’ axes . titlesize ’: 10 ,
11 ’ legend . fontsize ’: 8, Listing 43. Minimising chart junk
12 ’ xtick . labelsize ’: 8,
13 ’ ytick . labelsize ’: 8,
14
15.5 Exporting at Publication Quality
15 # Lines
16 ’ lines . linewidth ’: 1.5 , 1 import os
17 ’ axes . linewidth ’: 0.8 , 2
18 ’ xtick . major . width ’ :0.8 , 3 OUTPUT_DIR = ’ figures / ’
19 ’ ytick . major . width ’ :0.8 , 4 os . makedirs ( OUTPUT_DIR , exist_ok = True )
20 5
21 # Spines 6 def save_figure ( fig , name ,
22 ’ axes . spines . top ’: False , 7 formats =( ’ pdf ’ , ’ tiff ’) ,

14
Mastering Graphing in Python

8 dpi =300) :
9 " " " Save figure to multiple formats . " 1 ax . annotate (
"" 2 r ’$ \ sigma = \ sqrt {\ langle x ^2 \
10 for fmt in formats : rangle ’
11 path = os . path . join ( 3 r ’ - \ langle x \ rangle ^2} $ ’ ,
12 OUTPUT_DIR , 4 xy =(0.5 , 0.9) ,
13 f ’{ name }.{ fmt } ’) 5 xycoords = ’ axes fraction ’ ,
14 fig . savefig ( 6 fontsize =9 ,
15 path , 7 ha = ’ center ’)
8
16 dpi = dpi ,
17 bbox_inches = ’ tight ’, 9 # Inline equation in axis label
18 pad_inches =0.02 , 10 ax . set_ylabel (
19 facecolor = ’ white ’ , 11 r ’ Signal - to - noise ratio ’
20 edgecolor = ’ none ’) 12 r ’ $ \ mathrm { SNR } = ’
21 print (f ’ Saved : { path } ’) 13 r ’\ mu /\ sigma$ ’)
22
23 # Usage Listing 46. Mathematical annotations
24 fig , ax = plt . subplots ( figsize =(3.35 ,
2.5) )
25 # ... plot ... 17 Reproducible Figure Workflows
26 save_figure ( fig , ’ fig_01_main_result ’)

Listing 44. Publication export workflow


Reproducibility is foundational to science. Figure-
generating code should be deterministic, version-
16 Working with LaTeX Labels controlled, and self-contained.

17.1 Random Seeds


Matplotlib supports LATEX rendering for mathe- 1 import numpy as np
matical labels, axis titles, and annotations. This 2 import random
is essential for physics, mathematics, and engineer- 3
4 SEED = 42
ing papers.
5 np . random . seed ( SEED )
6 random . seed ( SEED )
16.1 Enabling LaTeX Rendering 7
8 # For pandas sample / shuffle operations
1 import matplotlib as mpl 9 pd . options . mode . copy_on_write = True
2 import matplotlib . pyplot as plt
3 Listing 47. Global random seed management
4 # Method 1: True LaTeX ( requires
installation )
5 mpl . rcParams . update ({ 17.2 Configuration Files
6 ’ text . usetex ’: True ,
7 ’ font . family ’: ’ serif ’ , 1 # styles / research . mplstyle ( save as
8 ’ font . serif ’: [ ’ Computer file )
Modern ’], 2 # Load with : plt . style . use (’ styles /
9 ’ text . latex . preamble ’: research ’)
10 r ’\ usepackage { amsmath } ’ 3
11 r ’\ usepackage { amssymb } ’ 4 axes . spines . top : False
12 r ’\ usepackage { siunitx } ’, 5 axes . spines . right : False
13 }) 6 font . family : serif
14 7 font . size : 9
15 # Method 2: mathtext ( no LaTeX install 8 axes . labelsize : 9
needed ) 9 axes . titlesize : 10
16 # Use $ ... $ syntax ; subset of LaTeX 10 legend . fontsize : 8
17 ax . set_xlabel ( 11 xtick . labelsize : 8
18 r ’ Wavelength $ \ lambda$ ( nm ) ’) 12 ytick . labelsize : 8
19 ax . set_ylabel ( 13 lines . linewidth : 1.5
20 r ’ Intensity $I / I_0$ ’) 14 savefig . dpi : 300
21 ax . set_title ( 15 savefig . bbox : tight
22 r ’$E = \ frac {\ hbar ^2 k ^2}{2 m } $ ’) 16 pdf . fonttype : 42

Listing 45. Full LaTeX rendering Listing 48. Reusable style configuration

15
Mastering Graphing in Python 17.3 Figure Factory Pattern

8 lw =1.8 ,
1 import matplotlib . pyplot as plt 9 title = ’ Annual sales by product ’ ,
2
10 xlabel = ’ Year ’,
3 plt . style . use ( ’ styles / research . mplstyle ’ 11 ylabel = ’ Revenue ( USD M ) ’ ,
) 12 legend = True )
4 # All subsequent plots use these 13 plt . tight_layout ()
defaults 14 plt . savefig ( ’ sales . pdf ’ , dpi =300)
Listing 49. Applying a style file Listing 51. [Link]() API

17.3 Figure Factory Pattern 18.2 GroupBy and FacetGrid


1 class FigureFactory : 1 import seaborn as sns
2 " " " Creates figures with consistent 2
style . " " " 3 g = sns . FacetGrid (
3 4 df ,
4 def __init__ ( self , style = ’ research ’ , 5 col = ’ category ’ ,
5 col_width_mm =85) : 6 hue = ’ condition ’ ,
6 plt . style . use ( style ) 7 col_wrap =3 ,
7 self . col = col_width_mm / 25.4 8 height =3 ,
8 9 aspect =1.1 ,
9 def single_col ( self , 10 palette = ’ Set2 ’ ,
10 aspect =0.75 , ** kw ): 11 sharey = True )
11 h = self . col * aspect 12
12 return plt . subplots ( 13 g. map_dataframe (
13 figsize =( self . col , h) , ** kw ) 14 sns . lineplot ,
14 15 x= ’ time ’ , y= ’ value ’ ,
15 def double_col ( self , 16 lw =1.6 , alpha =0.85)
16 aspect =0.45 , ** kw ): 17
17 w = self . col * 2 + 5/25.4 18 g. add_legend ()
18 h = w * aspect 19 g. set_titles ( col_template = ’{ col_name } ’)
19 return plt . subplots ( 20 g. set_axis_labels ( ’ Time ( s ) ’ , ’ Value ’)
20 figsize =(w , h) , ** kw ) 21 g. tight_layout ()
21 22 g. savefig ( ’ facet_grid . pdf ’, dpi =300)
22 def save ( self , fig , name ,
23 fmt = ’ pdf ’): Listing 52. Facet grid across categories
24 fig . savefig (
25 f ’ figures /{ name }.{ fmt } ’ ,
26 dpi =300)
27 plt . close ( fig )
19 Performance: Large Datasets
28
29 # Usage
30 ff = FigureFactory ()
31 fig , ax = ff . single_col ()
For datasets with N > 105 points, standard scat-
32 ax . plot (x , y) ter plots become unreadable due to overplotting
33 ff . save ( fig , ’ fig01_main ’) and slow to render.
Listing 50. Figure factory for consistent multi-figure
papers 19.1 Rasterisation
1 # Rasterise scatter to speed up PDF
export
18 Integration with Pandas and NumPy 2 ax . scatter (x , y ,
3 rasterized = True , # key
param
4 s =2 , alpha =0.3)
18.1 Plotting Directly from DataFrames 5
6 # Alternatively , rasterise the whole
1 import pandas as pd axes
2 7 ax . set_rasterized ( True )
3 df . plot ( 8 fig . savefig ( ’ large_scatter . pdf ’ ,
4 x = ’ year ’ , y =[ ’ sales_a ’ , ’ sales_b ’], 9 dpi =150)
5 kind = ’ line ’,
6 figsize =(6 , 3.5) , Listing 53. Rasterising scatter artists
7 color =[ ’ #2980 B9 ’ , ’# E74C3C ’],

16
Mastering Graphing in Python 19.2 Datashader for Very Large Data

19.2 Datashader for Very Large Data 7. Wrong scale: plotting raw counts instead of
1 import datashader as ds
normalised densities when comparing groups of
2 import datashader . transfer_functions as different sizes.
tf
3 import pandas as pd
4 import numpy as np 8. Y-axis not starting at zero for bar charts:
5 truncated y-axes exaggerate relative differ-
6 df = pd . DataFrame ({ ences.
7 ’x ’: np . random . randn (5 _000_000 ) ,
8 ’y ’: np . random . randn (5 _000_000 ) })
9
9. Using rainbow/jet colourmaps: introduces
10 cvs = ds . Canvas ( plot_width =800 ,
11 plot_height =600)
false features (see section 12).
12 agg = cvs . points (df , ’x ’ , ’y ’)
13 img = tf . shade ( agg , cmap = ’ viridis ’ ,
14 how = ’ log ’) 10. Non-reproducible random elements: not
15 img . to_pil () . save ( ’ datashader . png ’) setting [Link]() before generating
noise or jitter.
Listing 54. Datashader with Matplotlib

19.3 Binned Visualisations


20.2 Debugging Layout Issues
1 hb = ax . hexbin (
2 x_large , y_large ,
3 gridsize =50 , 1 # Show bounding boxes of all artists
4 cmap = ’ inferno ’ , 2 from matplotlib . patches import Rectangle
3
5 mincnt =1 , # hide empty bins
6 linewidths =0.2) 4 def show_layout ( fig ):
7 cb = plt . colorbar (hb , ax = ax ) 5 renderer = fig . canvas . get_renderer ()
8 cb . set_label ( ’ Point density ’) 6 for ax in fig . axes :
7 bb = ax . get_window_extent (
Listing 55. Hexbin for large scatter data renderer )
8 print (f ’ Axes bbox : { bb } ’)
9 for child in ax . get_children () :
10 try :
20 Common Pitfalls and Debugging 11 cbb = child .
get_window_extent (
12 renderer )
13 if cbb . width > 1:
20.1 The Ten Most Common Errors 14 print (f ’ { type (
child ) . __name__
1. Mixing pyplot and OO APIs: calling }: ’
[Link]() when working with explicit ax ob- 15 f ’{ cbb } ’)
jects has no effect. Always use ax.set_xlabel(). 16 except Exception :
17 pass
2. Forgotten fig.tight_layout(): labels and ti- 18

tles clip outside the figure boundary. 19 # Diagnose tight_layout warnings


20 import warnings
3. Missing legend() call: adding label= to plot 21 with warnings . catch_warnings (
22 record = True ) as w:
calls does nothing until [Link]() is called.
23 warnings . simplefilter ( ’ always ’)
4. Overwriting figures: not calling 24 fig . tight_layout ()
25 for warning in w:
[Link](fig) in loops causes memory 26 print ( warning . message )
leaks in long batch jobs.
Listing 56. Diagnosing layout problems
5. Low-resolution PNG: saving at default
dpi=72 produces blurry figures in print. Always
use dpi=300 minimum.
6. Aspect ratio distortion: not setting figsize
to match the target column width compresses
or stretches plots. 21 Quick Reference

17
Mastering Graphing in Python

1. Master the object-oriented Matplotlib in-


terface: explicit fig, ax references are essen-
Table 5. Essential Matplotlib commands. tial for complex figures.
2. Choose chart types to match data struc-
Command Effect ture: show raw data alongside summaries
wherever sample sizes permit.
[Link](x,y) Line plot
[Link](x,y) Scatter plot 3. Use perceptually uniform colourmaps
[Link](x,h) Vertical bar chart (viridis, plasma, cividis) and CVD-safe qual-
[Link](y,w) Horizontal bar chart itative palettes.
[Link](x,bins=) Histogram 4. Save as vector formats (PDF or EPS) for all
[Link](data) Box plot line art.
[Link](data) Violin plot 5. Set dimensions in physical units to match
[Link](x,y,yerr=) Error-bar plot
journal column widths; use minimum 8 pt fonts.
ax.fill_between(x,y1,y2) Filled area
[Link](Z) Image / heatmap
6. Encode redundantly: colour + line style +
[Link](X,Y,Z) Filled contours marker shape serves all readers including those
ax.set_xscale(’log’) Log x-axis with CVD.
[Link]() Show legend 7. Version-control figure scripts and set ran-
[Link]() Arrow annotation dom seeds for full reproducibility.
fig.tight_layout() Fix spacing
[Link](’[Link]’) Export figure Python’s visualisation ecosystem continues to
evolve rapidly. Libraries such as HoloViews,
Altair, and PyVista extend the capabilities de-
Table 6. Recommended colourmaps by data type. scribed here into big data and volumetric domains.
The principles of perceptual accuracy, honest rep-
Data type Colourmap resentation, and minimalist design, however, re-
Sequential (light to dark) viridis, main constant across all tools and all scales of
plasma data.
Sequential (perceptually uniform) cividis (CVD-
safe)
Diverging (centred) RdBu_r, References
coolwarm
Categorical (≤ 8) Set2, Wong
palette
Cyclic (phase, angle) twilight, hsv [1] E. R. Tufte. The Visual Display of Quanti-
Topographic/terrain terrain, tative Information. Graphics Press, Cheshire,
gist_earth CT, 1983.
Avoid jet, rainbow,
hot [2] L. Wilkinson. The Grammar of Graphics,
2nd ed. Springer, New York, 2005.

22 Conclusion [3] K. Moreland. Diverging color maps for scien-


tific visualization. In Proceedings of the 5th In-
ternational Symposium on Advances in Visual
Computing, pages 92–103, 2009.
Effective scientific visualisation is as much craft
as science. The principles and patterns cov- [4] B. Wong. Points of view: Color blindness. Na-
ered in this guide the Matplotlib object hier- ture Methods, 8(6):441, 2011.
archy, statistical chart selection, perceptually uni-
form colourmaps, CVD-safe palettes, publication- [5] J. D. Hunter. Matplotlib: A 2D graphics envi-
dimension figure export, and reproducible figure ronment. Computing in Science & Engineering,
workflows collectively enable the production of 9(3):90–95, 2007.
figures that communicate results clearly, honestly,
and accessibly. [6] M. L. Waskom. seaborn: Statistical data vi-
sualization. Journal of Open Source Software,
The key takeaways are: 6(60):3021, 2021.

18
Mastering Graphing in Python References

[7] Plotly Technologies Inc. Collaborative data sci-


ence. Plotly, 2015. [Link]
[8] S. van der Walt, S. C. Colbert, and G. Varo-
quaux. The NumPy array: A structure for ef-
ficient numerical computation. Computing in
Science & Engineering, 13(2):22–30, 2011.
[9] P. Virtanen et al. SciPy 1.0: Fundamental algo-
rithms for scientific computing in Python. Na-
ture Methods, 17(3):261–272, 2020.

19

You might also like