Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix BoundaryNorm cursor data output #22835

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions lib/matplotlib/artist.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -1303,10 +1304,20 @@ 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_idx = max(0, cur_idx - 1)
# use max diff to prevent delta == 0
delta = np.diff(
self.norm.boundaries[neigh_idx:cur_idx + 2]
).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.
Expand Down
163 changes: 163 additions & 0 deletions lib/matplotlib/tests/test_artist.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

import pytest

from matplotlib import cm
import matplotlib.colors as mcolors
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.lines as mlines
Expand Down Expand Up @@ -372,3 +374,164 @@ class MyArtist4(MyArtist3):
pass

assert MyArtist4.set is MyArtist3.set


def test_format_cursor_data_BoundaryNorm():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you testing this in test_artist? are there other format tests in test_artist?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because my changes are in artist.py. What's a better place?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... fair!

"""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)

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

# 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=cmap, norm=norm)

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

# 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)
Copy link
Member

@oscargus oscargus Apr 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you are not using this variable? (And therefore not the cm import.) Nor the similar in the previous section.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. Fixed it! (Though, I think resampling the colormap to match the number of regions only makes a difference when viewing the plots.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think so, so the alternate fix of just removing the cmap may have been preferred. But now these tests will also serve as examples, so I am not strongly in favor in removing it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me too, that's why I left them in. The tests are more complete this way and produce expected results if anyone decided to look at the plots, or took my tests as examples.

norm = mcolors.BoundaryNorm(np.linspace(-1, 1, 2000), 2000)
img = ax.imshow(X, cmap=cmap, norm=norm)

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

# 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, 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()

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, 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()

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, 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()

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, 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()

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, 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()