From ffad256999f5683fd6080b627875a3320a3cb1d6 Mon Sep 17 00:00:00 2001 From: Kayran Schmidt Date: Wed, 13 Apr 2022 00:18:53 +0200 Subject: [PATCH 1/5] Fix #21915 --- lib/matplotlib/artist.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 1f33b9d3ec11..0f47035ed99c 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -12,6 +12,7 @@ import matplotlib as mpl from . import _api, cbook +from .colors import BoundaryNorm from .cm import ScalarMappable from .path import Path from .transforms import (Bbox, IdentityTransform, Transform, TransformedBbox, @@ -1303,10 +1304,22 @@ def format_cursor_data(self, data): return "[]" normed = self.norm(data) if np.isfinite(normed): - # Midpoints of neighboring color intervals. - neighbors = self.norm.inverse( - (int(self.norm(data) * n) + np.array([0, 1])) / n) - delta = abs(neighbors - data).max() + if isinstance(self.norm, BoundaryNorm): + # not an invertible normalization mapping + cur_idx = np.argmin(np.abs(self.norm.boundaries - data)) + neigh_idx1 = max(0, cur_idx - 1) + neigh_idx2 = min( + len(self.norm.boundaries) - 1, cur_idx + 1) + # use max diff to prevent delta == 0 + delta = np.diff( + self.norm.boundaries[[neigh_idx1, cur_idx, neigh_idx2]] + ).max() + + else: + # Midpoints of neighboring color intervals. + neighbors = self.norm.inverse( + (int(normed * n) + np.array([0, 1])) / n) + delta = abs(neighbors - data).max() g_sig_digits = cbook._g_sig_digits(data, delta) else: g_sig_digits = 3 # Consistent with default below. From 50d413d79f3316dc1cdc98145f5191b32df74a45 Mon Sep 17 00:00:00 2001 From: Kayran Schmidt Date: Wed, 13 Apr 2022 00:59:02 +0200 Subject: [PATCH 2/5] Add test for BoundaryNorm cursor data output --- lib/matplotlib/tests/test_artist.py | 116 ++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/lib/matplotlib/tests/test_artist.py b/lib/matplotlib/tests/test_artist.py index a9324f0bea58..adccd06d8d76 100644 --- a/lib/matplotlib/tests/test_artist.py +++ b/lib/matplotlib/tests/test_artist.py @@ -5,6 +5,8 @@ import pytest +from matplotlib import cbook, cm +import matplotlib.colors as mcolors import matplotlib.pyplot as plt import matplotlib.patches as mpatches import matplotlib.lines as mlines @@ -372,3 +374,117 @@ class MyArtist4(MyArtist3): pass assert MyArtist4.set is MyArtist3.set + + +def test_format_cursor_data_BoundaryNorm(): + """Test if cursor data is correct when using BoundaryNorm.""" + X = np.empty((3, 3)) + X[0, 0] = 0.9 + X[0, 1] = 0.99 + X[0, 2] = 0.999 + X[1, 0] = -1 + X[1, 1] = 0 + X[1, 2] = 1 + X[2, 0] = 0.09 + X[2, 1] = 0.009 + X[2, 2] = 0.0009 + + # map range -1..1 to 0..256 in 0.1 steps + fig, ax = plt.subplots() + fig.suptitle("-1..1 to 0..256 in 0.1") + norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 20), 256) + img = ax.imshow(X, cmap='RdBu_r', norm=norm) + for v in X.flat: + label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.1)) + assert img.format_cursor_data(v) == label + + plt.close() + + # map range -1..1 to 0..256 in 0.01 steps + fig, ax = plt.subplots() + fig.suptitle("-1..1 to 0..256 in 0.01") + cmap = cm.get_cmap('RdBu_r', 200) + norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 200), 200) + img = ax.imshow(X, cmap='RdBu_r', norm=norm) + for v in X.flat: + label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.01)) + assert img.format_cursor_data(v) == label + + plt.close() + + # map range -1..1 to 0..256 in 0.01 steps + fig, ax = plt.subplots() + fig.suptitle("-1..1 to 0..256 in 0.001") + cmap = cm.get_cmap('RdBu_r', 2000) + norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 2000), 2000) + img = ax.imshow(X, cmap='RdBu_r', norm=norm) + for v in X.flat: + label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.001)) + assert img.format_cursor_data(v) == label + + plt.close() + + # out of bounds values for 0..1 + Y = np.empty((7, 1)) + Y[0] = -1.0 + Y[1] = 0.0 + Y[2] = 0.1 + Y[3] = 0.5 + Y[4] = 0.9 + Y[5] = 1.0 + Y[6] = 2.0 + + fig, ax = plt.subplots() + fig.suptitle("noclip, neither") + norm = mcolors.BoundaryNorm( + np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='neither') + img = ax.imshow(X, cmap='RdBu_r', norm=norm) + for v in X.flat: + label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) + assert img.format_cursor_data(v) == label + + plt.close() + + fig, ax = plt.subplots() + fig.suptitle("noclip, min") + norm = mcolors.BoundaryNorm( + np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='min') + img = ax.imshow(X, cmap='RdBu_r', norm=norm) + for v in X.flat: + label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) + assert img.format_cursor_data(v) == label + + plt.close() + + fig, ax = plt.subplots() + fig.suptitle("noclip, max") + norm = mcolors.BoundaryNorm( + np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='max') + img = ax.imshow(X, cmap='RdBu_r', norm=norm) + for v in X.flat: + label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) + assert img.format_cursor_data(v) == label + + plt.close() + + fig, ax = plt.subplots() + fig.suptitle("noclip, both") + norm = mcolors.BoundaryNorm( + np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='both') + img = ax.imshow(X, cmap='RdBu_r', norm=norm) + for v in X.flat: + label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) + assert img.format_cursor_data(v) == label + + plt.close() + + fig, ax = plt.subplots() + fig.suptitle("clip, neither") + norm = mcolors.BoundaryNorm( + np.linspace(0, 1, 4, endpoint=True), 256, clip=True, extend='neither') + img = ax.imshow(X, cmap='RdBu_r', norm=norm) + for v in X.flat: + label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) + assert img.format_cursor_data(v) == label + + plt.close() From 455abb4646867d52fdd8cdff6e0fc91105152935 Mon Sep 17 00:00:00 2001 From: Kayran Schmidt Date: Wed, 13 Apr 2022 18:56:00 +0200 Subject: [PATCH 3/5] Use slicing for cleaner code --- lib/matplotlib/artist.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 0f47035ed99c..24a60fd4d121 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -1307,12 +1307,10 @@ def format_cursor_data(self, data): if isinstance(self.norm, BoundaryNorm): # not an invertible normalization mapping cur_idx = np.argmin(np.abs(self.norm.boundaries - data)) - neigh_idx1 = max(0, cur_idx - 1) - neigh_idx2 = min( - len(self.norm.boundaries) - 1, cur_idx + 1) + neigh_idx = max(0, cur_idx - 1) # use max diff to prevent delta == 0 delta = np.diff( - self.norm.boundaries[[neigh_idx1, cur_idx, neigh_idx2]] + self.norm.boundaries[neigh_idx:cur_idx + 2] ).max() else: From e75e8ea7c81061b652fe7a40d77bca53cd95722a Mon Sep 17 00:00:00 2001 From: Kayran Schmidt Date: Thu, 21 Apr 2022 12:44:26 +0200 Subject: [PATCH 4/5] Use resampled colormaps --- lib/matplotlib/tests/test_artist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_artist.py b/lib/matplotlib/tests/test_artist.py index adccd06d8d76..13da16b52c6f 100644 --- a/lib/matplotlib/tests/test_artist.py +++ b/lib/matplotlib/tests/test_artist.py @@ -405,7 +405,7 @@ def test_format_cursor_data_BoundaryNorm(): fig.suptitle("-1..1 to 0..256 in 0.01") cmap = cm.get_cmap('RdBu_r', 200) norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 200), 200) - img = ax.imshow(X, cmap='RdBu_r', norm=norm) + img = ax.imshow(X, cmap=cmap, norm=norm) for v in X.flat: label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.01)) assert img.format_cursor_data(v) == label @@ -417,7 +417,7 @@ def test_format_cursor_data_BoundaryNorm(): fig.suptitle("-1..1 to 0..256 in 0.001") cmap = cm.get_cmap('RdBu_r', 2000) norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 2000), 2000) - img = ax.imshow(X, cmap='RdBu_r', norm=norm) + img = ax.imshow(X, cmap=cmap, norm=norm) for v in X.flat: label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.001)) assert img.format_cursor_data(v) == label From ec8b93e21b3d9962543ae85c2776195eb594d27f Mon Sep 17 00:00:00 2001 From: Kayran Schmidt Date: Thu, 23 Jun 2022 13:51:35 +0200 Subject: [PATCH 5/5] Test against explicit, predefined labels --- lib/matplotlib/tests/test_artist.py | 99 +++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 26 deletions(-) diff --git a/lib/matplotlib/tests/test_artist.py b/lib/matplotlib/tests/test_artist.py index 13da16b52c6f..0fb1fa442fe7 100644 --- a/lib/matplotlib/tests/test_artist.py +++ b/lib/matplotlib/tests/test_artist.py @@ -5,7 +5,7 @@ import pytest -from matplotlib import cbook, cm +from matplotlib import cm import matplotlib.colors as mcolors import matplotlib.pyplot as plt import matplotlib.patches as mpatches @@ -394,8 +394,20 @@ def test_format_cursor_data_BoundaryNorm(): fig.suptitle("-1..1 to 0..256 in 0.1") norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 20), 256) img = ax.imshow(X, cmap='RdBu_r', norm=norm) - for v in X.flat: - label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.1)) + + labels_list = [ + "[0.9]", + "[1.]", + "[1.]", + "[-1.0]", + "[0.0]", + "[1.0]", + "[0.09]", + "[0.009]", + "[0.0009]", + ] + for v, label in zip(X.flat, labels_list): + # label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.1)) assert img.format_cursor_data(v) == label plt.close() @@ -406,8 +418,20 @@ def test_format_cursor_data_BoundaryNorm(): cmap = cm.get_cmap('RdBu_r', 200) norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 200), 200) img = ax.imshow(X, cmap=cmap, norm=norm) - for v in X.flat: - label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.01)) + + labels_list = [ + "[0.90]", + "[0.99]", + "[1.0]", + "[-1.00]", + "[0.00]", + "[1.00]", + "[0.09]", + "[0.009]", + "[0.0009]", + ] + for v, label in zip(X.flat, labels_list): + # label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.01)) assert img.format_cursor_data(v) == label plt.close() @@ -418,29 +442,52 @@ def test_format_cursor_data_BoundaryNorm(): cmap = cm.get_cmap('RdBu_r', 2000) norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 2000), 2000) img = ax.imshow(X, cmap=cmap, norm=norm) - for v in X.flat: - label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.001)) + + labels_list = [ + "[0.900]", + "[0.990]", + "[0.999]", + "[-1.000]", + "[0.000]", + "[1.000]", + "[0.090]", + "[0.009]", + "[0.0009]", + ] + for v, label in zip(X.flat, labels_list): + # label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.001)) assert img.format_cursor_data(v) == label plt.close() - # out of bounds values for 0..1 - Y = np.empty((7, 1)) - Y[0] = -1.0 - Y[1] = 0.0 - Y[2] = 0.1 - Y[3] = 0.5 - Y[4] = 0.9 - Y[5] = 1.0 - Y[6] = 2.0 + # different testing data set with + # out of bounds values for 0..1 range + X = np.empty((7, 1)) + X[0] = -1.0 + X[1] = 0.0 + X[2] = 0.1 + X[3] = 0.5 + X[4] = 0.9 + X[5] = 1.0 + X[6] = 2.0 + + labels_list = [ + "[-1.0]", + "[0.0]", + "[0.1]", + "[0.5]", + "[0.9]", + "[1.0]", + "[2.0]", + ] fig, ax = plt.subplots() fig.suptitle("noclip, neither") norm = mcolors.BoundaryNorm( np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='neither') img = ax.imshow(X, cmap='RdBu_r', norm=norm) - for v in X.flat: - label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) + for v, label in zip(X.flat, labels_list): + # label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) assert img.format_cursor_data(v) == label plt.close() @@ -450,8 +497,8 @@ def test_format_cursor_data_BoundaryNorm(): norm = mcolors.BoundaryNorm( np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='min') img = ax.imshow(X, cmap='RdBu_r', norm=norm) - for v in X.flat: - label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) + for v, label in zip(X.flat, labels_list): + # label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) assert img.format_cursor_data(v) == label plt.close() @@ -461,8 +508,8 @@ def test_format_cursor_data_BoundaryNorm(): norm = mcolors.BoundaryNorm( np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='max') img = ax.imshow(X, cmap='RdBu_r', norm=norm) - for v in X.flat: - label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) + for v, label in zip(X.flat, labels_list): + # label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) assert img.format_cursor_data(v) == label plt.close() @@ -472,8 +519,8 @@ def test_format_cursor_data_BoundaryNorm(): norm = mcolors.BoundaryNorm( np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='both') img = ax.imshow(X, cmap='RdBu_r', norm=norm) - for v in X.flat: - label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) + for v, label in zip(X.flat, labels_list): + # label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) assert img.format_cursor_data(v) == label plt.close() @@ -483,8 +530,8 @@ def test_format_cursor_data_BoundaryNorm(): norm = mcolors.BoundaryNorm( np.linspace(0, 1, 4, endpoint=True), 256, clip=True, extend='neither') img = ax.imshow(X, cmap='RdBu_r', norm=norm) - for v in X.flat: - label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) + for v, label in zip(X.flat, labels_list): + # label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33)) assert img.format_cursor_data(v) == label plt.close() pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy