Skip to content

Commit ae7d004

Browse files
authored
Add rasterized arg for heatmaps (#359)
## Description <!-- Provide a brief description of the PR's purpose here. --> A useful feature in heatmap visualizations is to rasterize the heatmap itself but not the surrounding text of the plot. This is useful when saving to PDF for instance, as we want to rasterize the heatmap so that the PDF does not have to render hundreds or thousands of cells. Instead, it can just render a single image for the heatmap, while the surrounding text is maintained in vector format. Previously, we had to rasterize the entire plot, so even the text was converted to pixels when it can easily be represented in vector format. The API change is to add a `rasterized` argument to `grid_archive_heatmap`, `cvt_archive_heatmap`, and `sliding_boundareis_archive_heatmap`. This is similar to how Matplotlib methods like [pcolormesh](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.pcolormesh.html) handle rasterization. ## TODO <!-- Notable points that this PR has either accomplished or will accomplish. --> - [x] Add rasterized arg in grid_archive_heatmap — rasterized is passed into pcolormesh, and pcm_kwargs is not allowed to contain rasterized since that would result in a duplicate kwarg to pcolormesh - [x] Add rasterized arg in cvt_archive_heatmap — rasterized is passed into PolyCollection - [x] Add rasterized arg in sliding_boundaries_archive_heatmap ## Questions <!-- Any concerns or points of confusion? --> ## Status - [x] I have read the guidelines in [CONTRIBUTING.md](https://github.com/icaros-usc/pyribs/blob/master/CONTRIBUTING.md) - [x] I have formatted my code using `yapf` - [x] I have tested my code by running `pytest` - [x] I have linted my code with `pylint` - [x] I have added a one-line description of my change to the changelog in `HISTORY.md` - [x] This PR is ready to go
1 parent 847cf6e commit ae7d004

9 files changed

+70
-8
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ results/
126126

127127
# Allow matplotlib baseline images.
128128
!tests/**/*.png
129+
!tests/**/*.pdf
129130

130131
# Editor, IDE, and OS settings
131132
.vscode/

HISTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- **Backwards-incompatible:** Allow using kwargs for colorbar in
1515
parallel_axes_plot (#358)
1616
- Removes cbar_orientaton and cbar_pad args for parallel_axes_plot
17+
- Add `rasterized` arg for heatmaps (#359)
1718

1819
#### Documentation
1920

ribs/visualize/_cvt_archive_heatmap.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def cvt_archive_heatmap(archive,
2525
vmax=None,
2626
cbar="auto",
2727
cbar_kwargs=None,
28+
rasterized=False,
2829
clip=False,
2930
plot_centroids=False,
3031
plot_samples=False,
@@ -99,6 +100,12 @@ def cvt_archive_heatmap(archive,
99100
the colorbar on the specified Axes.
100101
cbar_kwargs (dict): Additional kwargs to pass to
101102
:func:`~matplotlib.pyplot.colorbar`.
103+
rasterized (bool): Whether to rasterize the heatmap. This can be useful
104+
for saving to a vector format like PDF. Essentially, only the
105+
heatmap will be converted to a raster graphic so that the archive
106+
cells will not have to be individually rendered. Meanwhile, the
107+
surrounding axes, particularly text labels, will remain in vector
108+
format.
102109
clip (bool, shapely.Polygon): Clip the heatmap cells to a given polygon.
103110
By default, we draw the cells along the outer edges of the heatmap
104111
as polygons that extend beyond the archive bounds, but these
@@ -259,6 +266,7 @@ def cvt_archive_heatmap(archive,
259266
edgecolors=ec,
260267
facecolors=facecolors,
261268
linewidths=lw,
269+
rasterized=rasterized,
262270
))
263271

264272
# Create a colorbar.

ribs/visualize/_grid_archive_heatmap.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ def grid_archive_heatmap(archive,
1818
vmin=None,
1919
vmax=None,
2020
cbar="auto",
21-
pcm_kwargs=None,
22-
cbar_kwargs=None):
21+
cbar_kwargs=None,
22+
rasterized=False,
23+
pcm_kwargs=None):
2324
"""Plots heatmap of a :class:`~ribs.archives.GridArchive` with 1D or 2D
2425
measure space.
2526
@@ -82,10 +83,18 @@ def grid_archive_heatmap(archive,
8283
:class:`~matplotlib.axes.Axes`. If ``None``, then colorbar is not
8384
displayed. If this is an :class:`~matplotlib.axes.Axes`, displays
8485
the colorbar on the specified Axes.
85-
pcm_kwargs (dict): Additional kwargs to pass to
86-
:func:`~matplotlib.pyplot.pcolormesh`.
8786
cbar_kwargs (dict): Additional kwargs to pass to
8887
:func:`~matplotlib.pyplot.colorbar`.
88+
rasterized (bool): Whether to rasterize the heatmap. This can be useful
89+
for saving to a vector format like PDF. Essentially, only the
90+
heatmap will be converted to a raster graphic so that the archive
91+
cells will not have to be individually rendered. Meanwhile, the
92+
surrounding axes, particularly text labels, will remain in vector
93+
format. This is implemented by passing ``rasterized`` to
94+
:func:`~matplotlib.pyplot.pcolormesh`, so passing ``"rasterized"``
95+
in the ``pcm_kwargs`` below will raise an error.
96+
pcm_kwargs (dict): Additional kwargs to pass to
97+
:func:`~matplotlib.pyplot.pcolormesh`.
8998
9099
Raises:
91100
ValueError: The archive's dimension must be 1D or 2D.
@@ -138,6 +147,7 @@ def grid_archive_heatmap(archive,
138147
cmap=cmap,
139148
vmin=vmin,
140149
vmax=vmax,
150+
rasterized=rasterized,
141151
**pcm_kwargs)
142152
elif archive.measure_dim == 2:
143153
# Retrieve data from archive.
@@ -178,6 +188,7 @@ def grid_archive_heatmap(archive,
178188
cmap=cmap,
179189
vmin=vmin,
180190
vmax=vmax,
191+
rasterized=rasterized,
181192
**pcm_kwargs)
182193

183194
# Create color bar.

ribs/visualize/_sliding_boundaries_archive_heatmap.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ def sliding_boundaries_archive_heatmap(archive,
2020
vmin=None,
2121
vmax=None,
2222
cbar="auto",
23-
cbar_kwargs=None):
23+
cbar_kwargs=None,
24+
rasterized=False):
2425
"""Plots heatmap of a :class:`~ribs.archives.SlidingBoundariesArchive` with
2526
2D measure space.
2627
@@ -90,6 +91,12 @@ def sliding_boundaries_archive_heatmap(archive,
9091
the colorbar on the specified Axes.
9192
cbar_kwargs (dict): Additional kwargs to pass to
9293
:func:`~matplotlib.pyplot.colorbar`.
94+
rasterized (bool): Whether to rasterize the heatmap. This can be useful
95+
for saving to a vector format like PDF. Essentially, only the
96+
heatmap will be converted to a raster graphic so that the archive
97+
cells will not have to be individually rendered. Meanwhile, the
98+
surrounding axes, particularly text labels, will remain in vector
99+
format.
93100
Raises:
94101
ValueError: The archive is not 2D.
95102
"""
@@ -138,7 +145,8 @@ def sliding_boundaries_archive_heatmap(archive,
138145
c=objective_batch,
139146
cmap=cmap,
140147
vmin=vmin,
141-
vmax=vmax)
148+
vmax=vmax,
149+
rasterized=rasterized)
142150
if boundary_lw > 0.0:
143151
# Careful with bounds here. Lines drawn along the x axis should extend
144152
# between the y bounds and vice versa -- see
@@ -147,12 +155,14 @@ def sliding_boundaries_archive_heatmap(archive,
147155
lower_bounds[1],
148156
upper_bounds[1],
149157
color='k',
150-
linewidth=boundary_lw)
158+
linewidth=boundary_lw,
159+
rasterized=rasterized)
151160
ax.hlines(y_boundary,
152161
lower_bounds[0],
153162
upper_bounds[0],
154163
color='k',
155-
linewidth=boundary_lw)
164+
linewidth=boundary_lw,
165+
rasterized=rasterized)
156166

157167
# Create color bar.
158168
set_cbar(t, ax, cbar, cbar_kwargs)

tests/visualize/visualize_test.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,37 @@ def test_cvt_archive_heatmap_voronoi_style(cvt_archive):
674674
cvt_archive_heatmap(cvt_archive, lw=3.0, ec="grey")
675675

676676

677+
#
678+
# Rasterization tests
679+
#
680+
681+
682+
@image_comparison(baseline_images=["grid_archive_heatmap_rasterized"],
683+
remove_text=False,
684+
extensions=["pdf"])
685+
def test_grid_archive_rasterized(grid_archive):
686+
plt.figure(figsize=(8, 6))
687+
grid_archive_heatmap(grid_archive, rasterized=True)
688+
689+
690+
@image_comparison(baseline_images=["cvt_archive_heatmap_rasterized"],
691+
remove_text=False,
692+
extensions=["pdf"])
693+
def test_cvt_archive_rasterized(cvt_archive):
694+
plt.figure(figsize=(8, 6))
695+
cvt_archive_heatmap(cvt_archive, rasterized=True)
696+
697+
698+
@image_comparison(baseline_images=["sliding_boundaries_heatmap_rasterized"],
699+
remove_text=False,
700+
extensions=["pdf"])
701+
def test_sliding_boundaries_archive_rasterized(sliding_archive):
702+
plt.figure(figsize=(8, 6))
703+
sliding_boundaries_archive_heatmap(sliding_archive,
704+
boundary_lw=1.0,
705+
rasterized=True)
706+
707+
677708
#
678709
# cvt_archive_heatmap clip tests
679710
#

0 commit comments

Comments
 (0)