From 1cfb18bbe864673500ad4d82a46d2409ab5e8b6c Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Sat, 11 Jul 2020 12:22:45 -0500 Subject: [PATCH 1/7] Created _repr_png_ and _repr_html_ for Colormap objects. --- lib/matplotlib/colors.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 2471c8a9698c..ffbf21c3c023 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -65,11 +65,14 @@ .. _xkcd color survey: https://xkcd.com/color/rgb/ """ +import base64 from collections.abc import Sized import functools +import io import itertools from numbers import Number import re +from PIL import Image import numpy as np import matplotlib.cbook as cbook @@ -691,6 +694,25 @@ def reversed(self, name=None): """ raise NotImplementedError() + def _repr_png_(self): + """Generate a PNG representation of the Colormap.""" + IMAGE_SIZE = (400, 50) + X = np.tile(np.linspace(0, 1, IMAGE_SIZE[0]), (IMAGE_SIZE[1], 1)) + pixels = self(X, bytes=True) + png_bytes = io.BytesIO() + Image.fromarray(pixels).save(png_bytes, format='png') + return png_bytes.getvalue() + + def _repr_html_(self): + """Generate an HTML representation of the Colormap.""" + png_bytes = self._repr_png_() + png_base64 = base64.b64encode(png_bytes).decode('ascii') + return ('' + self.name + '' + + '') + class LinearSegmentedColormap(Colormap): """ From d62cd5558419e0a4b40af63746064878b8aafea3 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Sat, 11 Jul 2020 12:28:00 -0500 Subject: [PATCH 2/7] Add a border to clarify the boundary of the image. --- lib/matplotlib/colors.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index ffbf21c3c023..e4c059730c00 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -711,6 +711,7 @@ def _repr_html_(self): '') From d3ca7e251846fa1f10ecd6b2ff8619fd6eee7a25 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Sat, 11 Jul 2020 12:38:50 -0500 Subject: [PATCH 3/7] Add tests for _repr_png_ and _repr_html_. --- lib/matplotlib/tests/test_colors.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py index ba1192d16ac3..5bb156dcc47c 100644 --- a/lib/matplotlib/tests/test_colors.py +++ b/lib/matplotlib/tests/test_colors.py @@ -1135,3 +1135,16 @@ def test_hex_shorthand_notation(): def test_DivergingNorm_deprecated(): with pytest.warns(cbook.MatplotlibDeprecationWarning): norm = mcolors.DivergingNorm(vcenter=0) + + +def test_repr_png(): + cmap = plt.get_cmap('viridis') + png = cmap._repr_png_() + assert len(png) > 0 + + +def test_repr_html(): + cmap = plt.get_cmap('viridis') + html = cmap._repr_html_() + assert len(html) > 0 + assert cmap.name in html From 34be66eb44719ef1c14998fb399f0c69f136ca32 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Sat, 11 Jul 2020 12:45:13 -0500 Subject: [PATCH 4/7] Added What's New entry. --- doc/users/next_whats_new/colormap_repr.rst | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/users/next_whats_new/colormap_repr.rst diff --git a/doc/users/next_whats_new/colormap_repr.rst b/doc/users/next_whats_new/colormap_repr.rst new file mode 100644 index 000000000000..077f6fca12e9 --- /dev/null +++ b/doc/users/next_whats_new/colormap_repr.rst @@ -0,0 +1,6 @@ +IPython representations for Colormap objects +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `matplotlib.colors.Colormap` object now has image representations for +IPython / Jupyter backends. Cells returning a color map on the last line will +display an image of the color map. From 3da7fc44056cec24718a92820161fa0710a2c2fd Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Sat, 11 Jul 2020 12:52:10 -0500 Subject: [PATCH 5/7] Add PngInfo. --- lib/matplotlib/colors.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index e4c059730c00..266d3a6aeadb 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -73,6 +73,7 @@ from numbers import Number import re from PIL import Image +from PIL.PngImagePlugin import PngInfo import numpy as np import matplotlib.cbook as cbook @@ -700,7 +701,8 @@ def _repr_png_(self): X = np.tile(np.linspace(0, 1, IMAGE_SIZE[0]), (IMAGE_SIZE[1], 1)) pixels = self(X, bytes=True) png_bytes = io.BytesIO() - Image.fromarray(pixels).save(png_bytes, format='png') + pnginfo = PngInfo().add_text('name', self.name) + Image.fromarray(pixels).save(png_bytes, format='png', pnginfo=pnginfo) return png_bytes.getvalue() def _repr_html_(self): From a490278f1127410ede1a4b5495f213be80749f76 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Sat, 11 Jul 2020 13:01:51 -0500 Subject: [PATCH 6/7] Update PngInfo. --- lib/matplotlib/colors.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 266d3a6aeadb..5cc0be9bc363 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -75,6 +75,7 @@ from PIL import Image from PIL.PngImagePlugin import PngInfo +import matplotlib as mpl import numpy as np import matplotlib.cbook as cbook from matplotlib import docstring @@ -701,7 +702,13 @@ def _repr_png_(self): X = np.tile(np.linspace(0, 1, IMAGE_SIZE[0]), (IMAGE_SIZE[1], 1)) pixels = self(X, bytes=True) png_bytes = io.BytesIO() - pnginfo = PngInfo().add_text('name', self.name) + title = self.name + ' color map' + author = f'Matplotlib v{mpl.__version__}, https://matplotlib.org' + pnginfo = PngInfo() + pnginfo.add_text('Title', title) + pnginfo.add_text('Description', title) + pnginfo.add_text('Author', author) + pnginfo.add_text('Software', author) Image.fromarray(pixels).save(png_bytes, format='png', pnginfo=pnginfo) return png_bytes.getvalue() From 9d4633874ddbf6939d75e0fd02d2a14a8da682f1 Mon Sep 17 00:00:00 2001 From: Bradley Dice Date: Sun, 12 Jul 2020 11:56:20 -0500 Subject: [PATCH 7/7] Enforce stricter tests for _repr_png_. --- lib/matplotlib/tests/test_colors.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py index 5bb156dcc47c..00ed7fdfb907 100644 --- a/lib/matplotlib/tests/test_colors.py +++ b/lib/matplotlib/tests/test_colors.py @@ -1,7 +1,9 @@ import copy import itertools +from io import BytesIO import numpy as np +from PIL import Image import pytest from numpy.testing import assert_array_equal, assert_array_almost_equal @@ -1141,6 +1143,13 @@ def test_repr_png(): cmap = plt.get_cmap('viridis') png = cmap._repr_png_() assert len(png) > 0 + img = Image.open(BytesIO(png)) + assert img.width > 0 + assert img.height > 0 + assert 'Title' in img.text + assert 'Description' in img.text + assert 'Author' in img.text + assert 'Software' in img.text def test_repr_html():