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

Skip to content

Commit 2d37c64

Browse files
committed
Fix pixel alignment for PcolorImage and NonUniformImage
Calculations now take into account that rendering will be to the nearest display pixel.
1 parent d9d7d15 commit 2d37c64

1 file changed

Lines changed: 28 additions & 23 deletions

File tree

lib/matplotlib/image.py

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,21 +1055,24 @@ def make_image(self, renderer, magnification=1.0, unsampled=False):
10551055
B[:, :, 0:3] = A
10561056
B[:, :, 3] = 255
10571057
A = B
1058-
l, b, r, t = self.axes.bbox.extents
1059-
width = int(((round(r) + 0.5) - (round(l) - 0.5)) * magnification)
1060-
height = int(((round(t) + 0.5) - (round(b) - 0.5)) * magnification)
1058+
magnified_extents = (self.axes.bbox.extents * magnification + 0.5).astype(int)
1059+
l, b, r, t = magnified_extents / magnification
1060+
width = int((r - l) * magnification)
1061+
height = int((t - b) * magnification)
10611062

10621063
invertedTransform = self.axes.transData.inverted()
1063-
x_pix = invertedTransform.transform(
1064-
[(x, b) for x in np.linspace(l, r, width)])[:, 0]
1065-
y_pix = invertedTransform.transform(
1066-
[(l, y) for y in np.linspace(b, t, height)])[:, 1]
1064+
x_pix_edges = invertedTransform.transform(
1065+
[(x, b) for x in np.linspace(l, r, width + 1)])[:, 0]
1066+
y_pix_edges = invertedTransform.transform(
1067+
[(l, y) for y in np.linspace(b, t, height + 1)])[:, 1]
1068+
x_pix_centers = (x_pix_edges[:-1] + x_pix_edges[1:]) / 2
1069+
y_pix_centers = (y_pix_edges[:-1] + y_pix_edges[1:]) / 2
10671070

10681071
if self._interpolation == "nearest":
10691072
x_mid = (self._Ax[:-1] + self._Ax[1:]) / 2
10701073
y_mid = (self._Ay[:-1] + self._Ay[1:]) / 2
1071-
x_int = x_mid.searchsorted(x_pix)
1072-
y_int = y_mid.searchsorted(y_pix)
1074+
x_int = x_mid.searchsorted(x_pix_centers)
1075+
y_int = y_mid.searchsorted(y_pix_centers)
10731076
# The following is equal to `A[y_int[:, None], x_int[None, :]]`,
10741077
# but many times faster. Both casting to uint32 (to have an
10751078
# effectively 1D array) and manual index flattening matter.
@@ -1080,16 +1083,16 @@ def make_image(self, renderer, magnification=1.0, unsampled=False):
10801083
else: # self._interpolation == "bilinear"
10811084
# Use np.interp to compute x_int/x_float has similar speed.
10821085
x_int = np.clip(
1083-
self._Ax.searchsorted(x_pix) - 1, 0, len(self._Ax) - 2)
1086+
self._Ax.searchsorted(x_pix_centers) - 1, 0, len(self._Ax) - 2)
10841087
y_int = np.clip(
1085-
self._Ay.searchsorted(y_pix) - 1, 0, len(self._Ay) - 2)
1088+
self._Ay.searchsorted(y_pix_centers) - 1, 0, len(self._Ay) - 2)
10861089
idx_int = np.add.outer(y_int * A.shape[1], x_int)
10871090
x_frac = np.clip(
1088-
np.divide(x_pix - self._Ax[x_int], np.diff(self._Ax)[x_int],
1091+
np.divide(x_pix_centers - self._Ax[x_int], np.diff(self._Ax)[x_int],
10891092
dtype=np.float32), # Downcasting helps with speed.
10901093
0, 1)
10911094
y_frac = np.clip(
1092-
np.divide(y_pix - self._Ay[y_int], np.diff(self._Ay)[y_int],
1095+
np.divide(y_pix_centers - self._Ay[y_int], np.diff(self._Ay)[y_int],
10931096
dtype=np.float32),
10941097
0, 1)
10951098
f00 = np.outer(1 - y_frac, 1 - x_frac)
@@ -1242,22 +1245,24 @@ def make_image(self, renderer, magnification=1.0, unsampled=False):
12421245
if (padded_A[0, 0] != bg).all():
12431246
padded_A[[0, -1], :] = padded_A[:, [0, -1]] = bg
12441247

1245-
l, b, r, t = self.axes.bbox.extents
1246-
width = (round(r) + 0.5) - (round(l) - 0.5)
1247-
height = (round(t) + 0.5) - (round(b) - 0.5)
1248-
width = round(width * magnification)
1249-
height = round(height * magnification)
1248+
# Round to the nearest output pixels after magnification
1249+
l, b, r, t = (self.axes.bbox.extents * magnification + 0.5).astype(int)
1250+
width = r - l
1251+
height = t - b
1252+
12501253
vl = self.axes.viewLim
12511254

1252-
x_pix = np.linspace(vl.x0, vl.x1, width)
1253-
y_pix = np.linspace(vl.y0, vl.y1, height)
1254-
x_int = self._Ax.searchsorted(x_pix)
1255-
y_int = self._Ay.searchsorted(y_pix)
1255+
x_pix_edges = np.linspace(vl.x0, vl.x1, width + 1)
1256+
y_pix_edges = np.linspace(vl.y0, vl.y1, height + 1)
1257+
x_pix_centers = (x_pix_edges[:-1] + x_pix_edges[1:]) / 2
1258+
y_pix_centers = (y_pix_edges[:-1] + y_pix_edges[1:]) / 2
1259+
x_int = self._Ax.searchsorted(x_pix_centers)
1260+
y_int = self._Ay.searchsorted(y_pix_centers)
12561261
im = ( # See comment in NonUniformImage.make_image re: performance.
12571262
padded_A.view(np.uint32).ravel()[
12581263
np.add.outer(y_int * padded_A.shape[1], x_int)]
12591264
.view(np.uint8).reshape((height, width, 4)))
1260-
return im, l, b, IdentityTransform()
1265+
return im, l / magnification, b / magnification, IdentityTransform()
12611266

12621267
def _check_unsampled_image(self):
12631268
return False

0 commit comments

Comments
 (0)