Skip to content

Commit 16e8a7a

Browse files
authored
Merge pull request #23331 from meeseeksmachine/auto-backport-of-pr-22835-on-v3.5.x
Backport PR #22835 on branch v3.5.x (Fix BoundaryNorm cursor data output)
2 parents c4cae98 + 5992285 commit 16e8a7a

File tree

2 files changed

+178
-4
lines changed

2 files changed

+178
-4
lines changed

lib/matplotlib/artist.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import matplotlib as mpl
1414
from . import _api, cbook
15+
from .colors import BoundaryNorm
1516
from .cm import ScalarMappable
1617
from .path import Path
1718
from .transforms import (Bbox, IdentityTransform, Transform, TransformedBbox,
@@ -1280,10 +1281,20 @@ def format_cursor_data(self, data):
12801281
return "[]"
12811282
normed = self.norm(data)
12821283
if np.isfinite(normed):
1283-
# Midpoints of neighboring color intervals.
1284-
neighbors = self.norm.inverse(
1285-
(int(self.norm(data) * n) + np.array([0, 1])) / n)
1286-
delta = abs(neighbors - data).max()
1284+
if isinstance(self.norm, BoundaryNorm):
1285+
# not an invertible normalization mapping
1286+
cur_idx = np.argmin(np.abs(self.norm.boundaries - data))
1287+
neigh_idx = max(0, cur_idx - 1)
1288+
# use max diff to prevent delta == 0
1289+
delta = np.diff(
1290+
self.norm.boundaries[neigh_idx:cur_idx + 2]
1291+
).max()
1292+
1293+
else:
1294+
# Midpoints of neighboring color intervals.
1295+
neighbors = self.norm.inverse(
1296+
(int(normed * n) + np.array([0, 1])) / n)
1297+
delta = abs(neighbors - data).max()
12871298
g_sig_digits = cbook._g_sig_digits(data, delta)
12881299
else:
12891300
g_sig_digits = 3 # Consistent with default below.

lib/matplotlib/tests/test_artist.py

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import pytest
77

8+
from matplotlib import cm
9+
import matplotlib.colors as mcolors
810
import matplotlib.pyplot as plt
911
import matplotlib.patches as mpatches
1012
import matplotlib.lines as mlines
@@ -374,3 +376,164 @@ class MyArtist4(MyArtist3):
374376
pass
375377

376378
assert MyArtist4.set is MyArtist3.set
379+
380+
381+
def test_format_cursor_data_BoundaryNorm():
382+
"""Test if cursor data is correct when using BoundaryNorm."""
383+
X = np.empty((3, 3))
384+
X[0, 0] = 0.9
385+
X[0, 1] = 0.99
386+
X[0, 2] = 0.999
387+
X[1, 0] = -1
388+
X[1, 1] = 0
389+
X[1, 2] = 1
390+
X[2, 0] = 0.09
391+
X[2, 1] = 0.009
392+
X[2, 2] = 0.0009
393+
394+
# map range -1..1 to 0..256 in 0.1 steps
395+
fig, ax = plt.subplots()
396+
fig.suptitle("-1..1 to 0..256 in 0.1")
397+
norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 20), 256)
398+
img = ax.imshow(X, cmap='RdBu_r', norm=norm)
399+
400+
labels_list = [
401+
"[0.9]",
402+
"[1.]",
403+
"[1.]",
404+
"[-1.0]",
405+
"[0.0]",
406+
"[1.0]",
407+
"[0.09]",
408+
"[0.009]",
409+
"[0.0009]",
410+
]
411+
for v, label in zip(X.flat, labels_list):
412+
# label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.1))
413+
assert img.format_cursor_data(v) == label
414+
415+
plt.close()
416+
417+
# map range -1..1 to 0..256 in 0.01 steps
418+
fig, ax = plt.subplots()
419+
fig.suptitle("-1..1 to 0..256 in 0.01")
420+
cmap = cm.get_cmap('RdBu_r', 200)
421+
norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 200), 200)
422+
img = ax.imshow(X, cmap=cmap, norm=norm)
423+
424+
labels_list = [
425+
"[0.90]",
426+
"[0.99]",
427+
"[1.0]",
428+
"[-1.00]",
429+
"[0.00]",
430+
"[1.00]",
431+
"[0.09]",
432+
"[0.009]",
433+
"[0.0009]",
434+
]
435+
for v, label in zip(X.flat, labels_list):
436+
# label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.01))
437+
assert img.format_cursor_data(v) == label
438+
439+
plt.close()
440+
441+
# map range -1..1 to 0..256 in 0.01 steps
442+
fig, ax = plt.subplots()
443+
fig.suptitle("-1..1 to 0..256 in 0.001")
444+
cmap = cm.get_cmap('RdBu_r', 2000)
445+
norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 2000), 2000)
446+
img = ax.imshow(X, cmap=cmap, norm=norm)
447+
448+
labels_list = [
449+
"[0.900]",
450+
"[0.990]",
451+
"[0.999]",
452+
"[-1.000]",
453+
"[0.000]",
454+
"[1.000]",
455+
"[0.090]",
456+
"[0.009]",
457+
"[0.0009]",
458+
]
459+
for v, label in zip(X.flat, labels_list):
460+
# label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.001))
461+
assert img.format_cursor_data(v) == label
462+
463+
plt.close()
464+
465+
# different testing data set with
466+
# out of bounds values for 0..1 range
467+
X = np.empty((7, 1))
468+
X[0] = -1.0
469+
X[1] = 0.0
470+
X[2] = 0.1
471+
X[3] = 0.5
472+
X[4] = 0.9
473+
X[5] = 1.0
474+
X[6] = 2.0
475+
476+
labels_list = [
477+
"[-1.0]",
478+
"[0.0]",
479+
"[0.1]",
480+
"[0.5]",
481+
"[0.9]",
482+
"[1.0]",
483+
"[2.0]",
484+
]
485+
486+
fig, ax = plt.subplots()
487+
fig.suptitle("noclip, neither")
488+
norm = mcolors.BoundaryNorm(
489+
np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='neither')
490+
img = ax.imshow(X, cmap='RdBu_r', norm=norm)
491+
for v, label in zip(X.flat, labels_list):
492+
# label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33))
493+
assert img.format_cursor_data(v) == label
494+
495+
plt.close()
496+
497+
fig, ax = plt.subplots()
498+
fig.suptitle("noclip, min")
499+
norm = mcolors.BoundaryNorm(
500+
np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='min')
501+
img = ax.imshow(X, cmap='RdBu_r', norm=norm)
502+
for v, label in zip(X.flat, labels_list):
503+
# label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33))
504+
assert img.format_cursor_data(v) == label
505+
506+
plt.close()
507+
508+
fig, ax = plt.subplots()
509+
fig.suptitle("noclip, max")
510+
norm = mcolors.BoundaryNorm(
511+
np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='max')
512+
img = ax.imshow(X, cmap='RdBu_r', norm=norm)
513+
for v, label in zip(X.flat, labels_list):
514+
# label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33))
515+
assert img.format_cursor_data(v) == label
516+
517+
plt.close()
518+
519+
fig, ax = plt.subplots()
520+
fig.suptitle("noclip, both")
521+
norm = mcolors.BoundaryNorm(
522+
np.linspace(0, 1, 4, endpoint=True), 256, clip=False, extend='both')
523+
img = ax.imshow(X, cmap='RdBu_r', norm=norm)
524+
for v, label in zip(X.flat, labels_list):
525+
# label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33))
526+
assert img.format_cursor_data(v) == label
527+
528+
plt.close()
529+
530+
fig, ax = plt.subplots()
531+
fig.suptitle("clip, neither")
532+
norm = mcolors.BoundaryNorm(
533+
np.linspace(0, 1, 4, endpoint=True), 256, clip=True, extend='neither')
534+
img = ax.imshow(X, cmap='RdBu_r', norm=norm)
535+
for v, label in zip(X.flat, labels_list):
536+
# label = "[{:-#.{}g}]".format(v, cbook._g_sig_digits(v, 0.33))
537+
assert img.format_cursor_data(v) == label
538+
539+
plt.close()

0 commit comments

Comments
 (0)
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