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

Skip to content

Commit ae239ea

Browse files
committed
Add four figure tests and changelog entry
1 parent f1a1fb4 commit ae239ea

6 files changed

Lines changed: 134 additions & 8 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Rendering of images now more accurate
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
There have been several fixes to improve the accuracy of how images are
4+
resampled and placed during rendering. Some inaccuracies were up to a pixel off
5+
in the output. The most apparent improvement is that the alignment of data
6+
pixels with tick marks and grid lines is now reliable. Nearly all image output
7+
has changed, but often only at a subtle level that is not obvious qualitatively.
84.8 KB
Loading
93.5 KB
Loading
17.5 KB
Loading
102 KB
Loading

lib/matplotlib/tests/test_image.py

Lines changed: 127 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,26 @@
1616
colors, image as mimage, patches, pyplot as plt, style, rcParams)
1717
from matplotlib.image import (AxesImage, BboxImage, FigureImage,
1818
NonUniformImage, PcolorImage)
19+
from matplotlib.patches import Rectangle
1920
from matplotlib.testing.decorators import check_figures_equal, image_comparison
2021
from matplotlib.transforms import Bbox, Affine2D, Transform, TransformedBbox
2122
import matplotlib.ticker as mticker
2223

2324
import pytest
2425

2526

27+
@pytest.fixture
28+
def nonaffine_identity():
29+
"""Non-affine identity transform for compositing with any affine transform"""
30+
class NonAffineIdentityTransform(Transform):
31+
input_dims = 2
32+
output_dims = 2
33+
34+
def inverted(self):
35+
return self
36+
return NonAffineIdentityTransform()
37+
38+
2639
@image_comparison(['interp_alpha.png'], remove_text=True)
2740
def test_alpha_interp():
2841
"""Test the interpolation of the alpha channel on RGBA images"""
@@ -1679,7 +1692,7 @@ def test__resample_valid_output():
16791692
np.full(256, 0.9)]).reshape(1, -1)),
16801693
]
16811694
)
1682-
def test_resample_nonaffine(data, interpolation, expected):
1695+
def test_resample_nonaffine(data, interpolation, expected, nonaffine_identity):
16831696
# Test that both affine and nonaffine transforms resample to the correct answer
16841697

16851698
# If the array is constant, the tolerance can be tight
@@ -1695,13 +1708,7 @@ def test_resample_nonaffine(data, interpolation, expected):
16951708

16961709
# Create a nonaffine version of the same transform
16971710
# by compositing with a nonaffine identity transform
1698-
class NonAffineIdentityTransform(Transform):
1699-
input_dims = 2
1700-
output_dims = 2
1701-
1702-
def inverted(self):
1703-
return self
1704-
nonaffine_transform = NonAffineIdentityTransform() + affine_transform
1711+
nonaffine_transform = nonaffine_identity + affine_transform
17051712

17061713
nonaffine_result = np.empty_like(expected)
17071714
mimage.resample(data, nonaffine_result, nonaffine_transform,
@@ -1873,3 +1880,115 @@ def test_interpolation_stage_rgba_respects_alpha_param(fig_test, fig_ref, intp_s
18731880
(im_rgb, new_array_alpha.reshape((ny, nx, 1))), axis=-1
18741881
), interpolation_stage=intp_stage
18751882
)
1883+
1884+
1885+
@image_comparison(['nn_pixel_alignment.png'])
1886+
def test_nn_pixel_alignment(nonaffine_identity):
1887+
fig, axs = plt.subplots(2, 3)
1888+
1889+
for j, N in enumerate([3, 7, 11]):
1890+
# In each column, the plots use the same data array
1891+
data = np.arange(N**2).reshape((N, N)) % 4
1892+
seps = np.arange(-0.5, N)
1893+
1894+
for i in range(2):
1895+
if i == 0:
1896+
# Top row uses an affine transform
1897+
axs[i, j].imshow(data, cmap='Grays', interpolation='nearest')
1898+
else:
1899+
# Bottom row uses a non-affine transform
1900+
axs[i, j].imshow(data, cmap='Grays', interpolation='nearest',
1901+
transform=nonaffine_identity + axs[i, j].transData)
1902+
1903+
axs[i, j].set_axis_off()
1904+
axs[i, j].vlines(seps, -1, N, lw=0.5, color='red', ls='dashed')
1905+
axs[i, j].hlines(seps, -1, N, lw=0.5, color='red', ls='dashed')
1906+
1907+
1908+
@image_comparison(['image_bounds_handling.png'], tol=0.006)
1909+
def test_image_bounds_handling(nonaffine_identity):
1910+
# TODO: The second and third panels in the bottom row show that the handling of
1911+
# image bounds is bugged for non-affine transforms and non-nearest-neighbor
1912+
# interpolation. If this bug gets fixed, the baseline image should be updated.
1913+
1914+
fig, axs = plt.subplots(2, 3)
1915+
1916+
N = 11
1917+
1918+
for j, interpolation in enumerate(['nearest', 'hanning', 'bilinear']):
1919+
data = np.arange(N**2).reshape((N, N))
1920+
data = data / N**2 + (data % 4) / 6
1921+
rotation = Affine2D().rotate_around(N/2-0.5, N/2-0.5, 1)
1922+
1923+
for i in range(2):
1924+
transform = rotation + axs[i, j].transData
1925+
if i == 1:
1926+
# Bottom row uses a non-affine transform
1927+
transform = nonaffine_identity + transform
1928+
1929+
axs[i, j].imshow(data, cmap='Grays', interpolation=interpolation,
1930+
transform=transform)
1931+
1932+
axs[i, j].set_axis_off()
1933+
box = Rectangle((-0.5, -0.5), N, N,
1934+
edgecolor='red', facecolor='none', lw=0.5, ls='dashed',
1935+
transform=rotation + axs[i, j].transData)
1936+
axs[i, j].add_artist(box)
1937+
1938+
1939+
@image_comparison(['rgba_clean_edges.png'], tol=0.003)
1940+
def test_rgba_clean_edges():
1941+
np.random.seed(19680801+9) # same as in test_upsampling()
1942+
data = np.random.rand(8, 8)
1943+
data = np.stack([data, data])
1944+
data[1, 2:4, 2:4] = np.nan
1945+
1946+
rotation = Affine2D().rotate_around(3.5, 3.5, 1)
1947+
1948+
fig, axs = plt.subplots(1, 2)
1949+
1950+
for i in range(2):
1951+
# Add background patches to check the fading to non-white colors
1952+
black = Rectangle((3.75, 2), 5, 5, color='black', zorder=0)
1953+
gray = Rectangle((0, -2), 3.75, 4, color='gray', zorder=0)
1954+
partly_black = Rectangle((3.75, -2), 5, 4, fc='black', ec='none',
1955+
alpha=0.5, zorder=0)
1956+
axs[i].add_patch(black)
1957+
axs[i].add_patch(gray)
1958+
axs[i].add_patch(partly_black)
1959+
1960+
axs[i].imshow(data[i, ...],
1961+
interpolation='bilinear', interpolation_stage='rgba',
1962+
transform=rotation + axs[i].transData)
1963+
1964+
axs[i].set_axis_off()
1965+
axs[i].set_xlim(-2.5, 9.5)
1966+
axs[i].set_ylim(-2.5, 9.5)
1967+
1968+
1969+
@image_comparison(['affine_fill_to_edges.png'])
1970+
def test_affine_fill_to_edges():
1971+
# The two rows show the two settings of origin
1972+
# The three columns show the original and the two mirror flips
1973+
fig, axs = plt.subplots(2, 3)
1974+
1975+
N = 7
1976+
data = np.arange(N**2).reshape((N, N)) % 3
1977+
1978+
transform = [Affine2D(),
1979+
Affine2D().translate(0, -N + 1).scale(1, -1),
1980+
Affine2D().translate(-N + 1, 0).scale(-1, 1)]
1981+
1982+
for j in range(3):
1983+
for i in range(2):
1984+
origin = 'upper' if i == 0 else 'lower'
1985+
1986+
axs[i, j].imshow(data, cmap='Grays',
1987+
interpolation='hanning', origin=origin,
1988+
transform=transform[j] + axs[i, j].transData)
1989+
1990+
axs[i, j].set_axis_off()
1991+
axs[i, j].vlines([-0.5, N - 0.5], -1, 2, lw=0.5, color='red')
1992+
axs[i, j].vlines([-0.5, N - 0.5], N - 3, N, lw=0.5, color='red')
1993+
axs[i, j].hlines([-0.5, N - 0.5], -1, 2, lw=0.5, color='red')
1994+
axs[i, j].hlines([-0.5, N - 0.5], N - 3, N, lw=0.5, color='red')

0 commit comments

Comments
 (0)