Graphing in Python
Graphing in Python
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.
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
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
Mastering Graphing in Python 3.4 Line Styles, Markers, and Colours
4
Mastering Graphing in Python
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
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
Mastering Graphing in Python 9.2 Rolling Statistics
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
10
Mastering Graphing in Python 12.2 Qualitative Colours for Categorical Data
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ř).
12
Mastering Graphing in Python 14.1 Basic Plotly Express
13
Mastering Graphing in Python 15.2 Figure Dimensions
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
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 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
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
17
Mastering Graphing in Python
18
Mastering Graphing in Python References
19