Performance#
Whether exploring data in interactive mode or programmatically saving lots of plots, rendering performance can be a challenging bottleneck in your pipeline. Matplotlib provides multiple ways to greatly reduce rendering time at the cost of a slight change (to a settable tolerance) in your plot's appearance. The methods available to reduce rendering time depend on the type of plot that is being created.
Line segment simplification#
For plots that have line segments (e.g. typical line plots, outlines
of polygons, etc.), rendering performance can be controlled by
rcParams["path.simplify"]
(default: True
) and rcParams["path.simplify_threshold"]
(default: 0.111111111111
), which
can be defined e.g. in the matplotlibrc
file (see
Customizing Matplotlib with style sheets and rcParams for more information about
the matplotlibrc
file). rcParams["path.simplify"]
(default: True
) is a Boolean
indicating whether or not line segments are simplified at all.
rcParams["path.simplify_threshold"]
(default: 0.111111111111
) controls how much line segments are simplified;
higher thresholds result in quicker rendering.
The following script will first display the data without any simplification, and then display the same data with simplification. Try interacting with both of them:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
# Setup, and create the data to plot
y = np.random.rand(100000)
y[50000:] *= 2
y[np.geomspace(10, 50000, 400).astype(int)] = -1
mpl.rcParams['path.simplify'] = True
mpl.rcParams['path.simplify_threshold'] = 0.0
plt.plot(y)
plt.show()
mpl.rcParams['path.simplify_threshold'] = 1.0
plt.plot(y)
plt.show()
Matplotlib currently defaults to a conservative simplification
threshold of 1/9
. To change default settings to use a different
value, change the matplotlibrc
file. Alternatively, users
can create a new style for interactive plotting (with maximal
simplification) and another style for publication quality plotting
(with minimal simplification) and activate them as necessary. See
Customizing Matplotlib with style sheets and rcParams for instructions on
how to perform these actions.
The simplification works by iteratively merging line segments
into a single vector until the next line segment's perpendicular
distance to the vector (measured in display-coordinate space)
is greater than the path.simplify_threshold
parameter.
Note
Changes related to how line segments are simplified were made in version 2.1. Rendering time will still be improved by these parameters prior to 2.1, but rendering time for some kinds of data will be vastly improved in versions 2.1 and greater.
Marker subsampling#
Markers can also be simplified, albeit less robustly than line
segments. Marker subsampling is only available to Line2D
objects
(through the markevery
property). Wherever Line2D
construction
parameters are passed through, such as pyplot.plot
and Axes.plot
,
the markevery
parameter can be used:
plt.plot(x, y, markevery=10)
The markevery
argument allows for naive subsampling, or an
attempt at evenly spaced (along the x axis) sampling. See the
Markevery Demo
for more information.
Splitting lines into smaller chunks#
If you are using the Agg backend (see What is a backend?),
then you can make use of rcParams["agg.path.chunksize"]
(default: 0
)
This allows users to specify a chunk size, and any lines with
greater than that many vertices will be split into multiple
lines, each of which has no more than agg.path.chunksize
many vertices. (Unless agg.path.chunksize
is zero, in
which case there is no chunking.) For some kind of data,
chunking the line up into reasonable sizes can greatly
decrease rendering time.
The following script will first display the data without any chunk size restriction, and then display the same data with a chunk size of 10,000. The difference can best be seen when the figures are large, try maximizing the GUI and then interacting with them:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['path.simplify_threshold'] = 1.0
# Setup, and create the data to plot
y = np.random.rand(100000)
y[50000:] *= 2
y[np.geomspace(10, 50000, 400).astype(int)] = -1
mpl.rcParams['path.simplify'] = True
mpl.rcParams['agg.path.chunksize'] = 0
plt.plot(y)
plt.show()
mpl.rcParams['agg.path.chunksize'] = 10000
plt.plot(y)
plt.show()
Legends#
The default legend behavior for axes attempts to find the location
that covers the fewest data points (loc='best'
). This can be a
very expensive computation if there are lots of data points. In
this case, you may want to provide a specific location.
Using the fast style#
The fast style can be used to automatically set simplification and chunking parameters to reasonable settings to speed up plotting large amounts of data. The following code runs it:
import matplotlib.style as mplstyle
mplstyle.use('fast')
It is very lightweight, so it works well with other styles. Be sure the fast style is applied last so that other styles do not overwrite the settings:
mplstyle.use(['dark_background', 'ggplot', 'fast'])