Last active
October 25, 2018 20:40
-
-
Save btel/a6b97e50e0f26a1a5eaa to your computer and use it in GitHub Desktop.
Thined version of matplotlib Axes for better performance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
When improving the performance of plotting high-dimensional data using | |
faceted scatter plots, I noticed that much of time was spent on the axis | |
creation (even 50%!). | |
On my machine creating 20x20 array of subplots without actually plotting | |
anything takes about 11 seconds (for comparison plotting 5000 points on | |
all of them takes only 0.6s!): | |
import matplotlib | |
matplotlib.interactive(True) | |
import matplotlib.pyplot as plt | |
fig, axes = plt.subplots(20,20) | |
plt.show() | |
Profiling shows that 50% of computation time is spent on axis/ticks | |
creation [1], which I have to remove anyways. Is there any easy way of | |
creating thinned axes without ticks and spines? | |
So far I solved the problem by subclassing Axes class (see this gist | |
[2]) and removing all spines and ticks. Running the above example gives | |
a 10x boost in performance (from 11s to 0.9s). | |
import thin_axes | |
fig, axes = plt.subplots(20,20, subplot_kw=dict(projection='thin')) | |
plt.show() | |
Profiling results show more uniform distribution of computing time | |
across functions (most time is spent on creating and applying transforms | |
[3]). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
#coding=utf-8 | |
import matplotlib | |
matplotlib.use("Agg") | |
import matplotlib.pyplot as plt | |
import thin_axes | |
import time | |
import numpy as np | |
import platform | |
print " ".join(platform.uname()) | |
def plot(axes): | |
for a in axes.flatten(): | |
x, y = np.random.randn(2, 5000) | |
a.plot(x, y, '.') | |
start_time = time.time() | |
fig, axes = plt.subplots(20,20) | |
plt.savefig('test.png') | |
print "Standard axes {} s".format(time.time() - start_time) | |
plt.close() | |
start_time = time.time() | |
fig, axes = plt.subplots(20,20, subplot_kw=dict(projection='thin')) | |
plt.savefig('test.png') | |
print "Thin axes {} s".format(time.time() - start_time) | |
plt.close() | |
start_time = time.time() | |
fig, axes = plt.subplots(20,20) | |
plt.savefig('test.png') | |
print "Standard axes with plotting {} s".format(time.time() - start_time) | |
plt.close() | |
start_time = time.time() | |
fig, axes = plt.subplots(20,20, subplot_kw=dict(projection='thin')) | |
plot(axes) | |
plt.savefig('test.png') | |
print "Thin axes with plotting {} s".format(time.time() - start_time) | |
plt.close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Darwin Bartoszs-MacBook-Pro.local 13.1.0 Darwin Kernel Version 13.1.0: Wed Apr 2 23:52:02 PDT 2014; root:xnu-2422.92.1~2/RELEASE_X86_64 x86_64 i386 | |
Standard axes 46.3883450031 s | |
Thin axes 2.5897591114 s | |
Standard axes with plotting 51.6446781158 s | |
Thin axes with plotting 7.36941695213 s |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from matplotlib.axes import Axes | |
from matplotlib.ticker import NullLocator | |
from matplotlib.projections import register_projection | |
import matplotlib.axis as maxis | |
class NoTicksXAxis(maxis.XAxis): | |
def reset_ticks(self): | |
self._lastNumMajorTicks = 1 | |
self._lastNumMinorTicks = 1 | |
def set_clip_path(self, clippath, transform=None): | |
pass | |
class NoTicksYAxis(maxis.YAxis): | |
def reset_ticks(self): | |
self._lastNumMajorTicks = 1 | |
self._lastNumMinorTicks = 1 | |
def set_clip_path(self, clippath, transform=None): | |
pass | |
class ThinAxes(Axes): | |
"""Thin axes without spines and ticks to accelerate axes creation""" | |
name = 'thin' | |
def _init_axis(self): | |
self.xaxis = NoTicksXAxis(self) | |
self.yaxis = NoTicksYAxis(self) | |
def cla(self): | |
""" | |
Override to set up some reasonable defaults. | |
""" | |
Axes.cla(self) | |
self.xaxis.set_minor_locator(NullLocator()) | |
self.yaxis.set_minor_locator(NullLocator()) | |
self.xaxis.set_major_locator(NullLocator()) | |
self.yaxis.set_major_locator(NullLocator()) | |
def _gen_axes_spines(self): | |
return {} | |
# Now register the projection with matplotlib so the user can select | |
# it. | |
register_projection(ThinAxes) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment