Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitdb7847f

Browse files
authored
Merge pull request#14889 from tillahoffmann/arrayalpha2
Support pixel-by-pixel alpha in imshow.
2 parentsbebb206 +bec9259 commitdb7847f

File tree

4 files changed

+69
-40
lines changed

4 files changed

+69
-40
lines changed

‎examples/images_contours_and_fields/image_transparency_blend.py

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
Blend transparency with color to highlight parts of data with imshow.
77
88
A common use for :func:`matplotlib.pyplot.imshow` is to plot a 2-D statistical
9-
map. While ``imshow`` makes it easy to visualize a 2-D matrix as an image,
10-
it doesn't easily let you add transparency to the output. For example, one can
11-
plot a statistic (such as a t-statistic) and color the transparency of
12-
each pixel according to its p-value. This example demonstrates how you can
13-
achieve this effect using :class:`matplotlib.colors.Normalize`. Note that it is
14-
not possible to directly pass alpha values to :func:`matplotlib.pyplot.imshow`.
9+
map. The function makes it easy to visualize a 2-D matrix as an image and add
10+
transparency to the output. For example, one can plot a statistic (such as a
11+
t-statistic) and color the transparency of each pixel according to its p-value.
12+
This example demonstrates how you can achieve this effect.
1513
1614
First we will generate some data, in this case, we'll create two 2-D "blobs"
1715
in a 2-D grid. One blob will be positive, and the other negative.
@@ -50,42 +48,38 @@ def normal_pdf(x, mean, var):
5048
# We'll also create a grey background into which the pixels will fade
5149
greys=np.full((*weights.shape,3),70,dtype=np.uint8)
5250

53-
# First we'll plot these blobs usingonly``imshow``.
51+
# First we'll plot these blobs using ``imshow`` without transparency.
5452
vmax=np.abs(weights).max()
55-
vmin=-vmax
56-
cmap=plt.cm.RdYlBu
53+
imshow_kwargs= {
54+
'vmax':vmax,
55+
'vmin':-vmax,
56+
'cmap':'RdYlBu',
57+
'extent': (xmin,xmax,ymin,ymax),
58+
}
5759

5860
fig,ax=plt.subplots()
5961
ax.imshow(greys)
60-
ax.imshow(weights,extent=(xmin,xmax,ymin,ymax),cmap=cmap)
62+
ax.imshow(weights,**imshow_kwargs)
6163
ax.set_axis_off()
6264

6365
###############################################################################
6466
# Blending in transparency
6567
# ========================
6668
#
6769
# The simplest way to include transparency when plotting data with
68-
# :func:`matplotlib.pyplot.imshow` is to convert the 2-D data array to a
69-
# 3-D image array of rgba values. This can be done with
70-
# :class:`matplotlib.colors.Normalize`. For example, we'll create a gradient
70+
# :func:`matplotlib.pyplot.imshow` is to pass an array matching the shape of
71+
# the data to the ``alpha`` argument. For example, we'll create a gradient
7172
# moving from left to right below.
7273

7374
# Create an alpha channel of linearly increasing values moving to the right.
7475
alphas=np.ones(weights.shape)
7576
alphas[:,30:]=np.linspace(1,0,70)
7677

77-
# Normalize the colors b/w 0 and 1, we'll then pass an MxNx4 array to imshow
78-
colors=Normalize(vmin,vmax,clip=True)(weights)
79-
colors=cmap(colors)
80-
81-
# Now set the alpha channel to the one we created above
82-
colors[...,-1]=alphas
83-
8478
# Create the figure and image
8579
# Note that the absolute values may be slightly different
8680
fig,ax=plt.subplots()
8781
ax.imshow(greys)
88-
ax.imshow(colors,extent=(xmin,xmax,ymin,ymax))
82+
ax.imshow(weights,alpha=alphas,**imshow_kwargs)
8983
ax.set_axis_off()
9084

9185
###############################################################################
@@ -102,18 +96,11 @@ def normal_pdf(x, mean, var):
10296
alphas=Normalize(0,.3,clip=True)(np.abs(weights))
10397
alphas=np.clip(alphas,.4,1)# alpha value clipped at the bottom at .4
10498

105-
# Normalize the colors b/w 0 and 1, we'll then pass an MxNx4 array to imshow
106-
colors=Normalize(vmin,vmax)(weights)
107-
colors=cmap(colors)
108-
109-
# Now set the alpha channel to the one we created above
110-
colors[...,-1]=alphas
111-
11299
# Create the figure and image
113100
# Note that the absolute values may be slightly different
114101
fig,ax=plt.subplots()
115102
ax.imshow(greys)
116-
ax.imshow(colors,extent=(xmin,xmax,ymin,ymax))
103+
ax.imshow(weights,alpha=alphas,**imshow_kwargs)
117104

118105
# Add contour lines to further highlight different levels.
119106
ax.contour(weights[::-1],levels=[-.1,.1],colors='k',linestyles='-')

‎lib/matplotlib/axes/_axes.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5504,9 +5504,10 @@ def imshow(self, X, cmap=None, norm=None, aspect=None,
55045504
which can be set by *filterrad*. Additionally, the antigrain image
55055505
resize filter is controlled by the parameter *filternorm*.
55065506
5507-
alpha : scalar, optional
5507+
alpha : scalar or array-like, optional
55085508
The alpha blending value, between 0 (transparent) and 1 (opaque).
5509-
This parameter is ignored for RGBA input data.
5509+
If *alpha* is an array, the alpha blending values are applied pixel
5510+
by pixel, and *alpha* must have the same shape as *X*.
55105511
55115512
vmin, vmax : scalar, optional
55125513
When using scalar data and no explicit *norm*, *vmin* and *vmax*

‎lib/matplotlib/image.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
importmath
88
importos
99
importlogging
10+
fromnumbersimportNumber
1011
frompathlibimportPath
1112
importurllib.parse
1213

@@ -95,7 +96,7 @@ def composite_images(images, renderer, magnification=1.0):
9596
ifdataisnotNone:
9697
x*=magnification
9798
y*=magnification
98-
parts.append((data,x,y,image.get_alpha()or1.0))
99+
parts.append((data,x,y,image._get_scalar_alpha()))
99100
bboxes.append(
100101
Bbox([[x,y], [x+data.shape[1],y+data.shape[0]]]))
101102

@@ -281,9 +282,29 @@ def set_alpha(self, alpha):
281282
----------
282283
alpha : float
283284
"""
284-
martist.Artist.set_alpha(self,alpha)
285+
ifalphaisnotNoneandnotisinstance(alpha,Number):
286+
alpha=np.asarray(alpha)
287+
ifalpha.ndim!=2:
288+
raiseTypeError('alpha must be a float, two-dimensional '
289+
'array, or None')
290+
self._alpha=alpha
291+
self.pchanged()
292+
self.stale=True
285293
self._imcache=None
286294

295+
def_get_scalar_alpha(self):
296+
"""
297+
Get a scalar alpha value to be applied to the artist as a whole.
298+
299+
If the alpha value is a matrix, the method returns 1.0 because pixels
300+
have individual alpha values (see `~._ImageBase._make_image` for
301+
details). If the alpha value is a scalar, the method returns said value
302+
to be applied to the artist as a whole because pixels do not have
303+
individual alpha values.
304+
"""
305+
return1.0ifself._alphaisNoneornp.ndim(self._alpha)>0 \
306+
elseself._alpha
307+
287308
defchanged(self):
288309
"""
289310
Call this whenever the mappable is changed so observers can
@@ -487,14 +508,17 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
487508
# pixel it will be between [0, 1] (such as a rotated image).
488509
out_mask=np.isnan(out_alpha)
489510
out_alpha[out_mask]=1
511+
# Apply the pixel-by-pixel alpha values if present
512+
alpha=self.get_alpha()
513+
ifalphaisnotNoneandnp.ndim(alpha)>0:
514+
out_alpha*=_resample(self,alpha,out_shape,
515+
t,resample=True)
490516
# mask and run through the norm
491517
output=self.norm(np.ma.masked_array(A_resampled,out_mask))
492518
else:
493519
ifA.shape[2]==3:
494520
A=_rgb_to_rgba(A)
495-
alpha=self.get_alpha()
496-
ifalphaisNone:
497-
alpha=1
521+
alpha=self._get_scalar_alpha()
498522
output_alpha=_resample(# resample alpha channel
499523
self,A[...,3],out_shape,t,alpha=alpha)
500524
output=_resample(# resample rgb channels
@@ -509,9 +533,7 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
509533

510534
# Apply alpha *after* if the input was greyscale without a mask
511535
ifA.ndim==2:
512-
alpha=self.get_alpha()
513-
ifalphaisNone:
514-
alpha=1
536+
alpha=self._get_scalar_alpha()
515537
alpha_channel=output[:, :,3]
516538
alpha_channel[:]=np.asarray(
517539
np.asarray(alpha_channel,np.float32)*out_alpha*alpha,
@@ -593,7 +615,7 @@ def draw(self, renderer, *args, **kwargs):
593615
# actually render the image.
594616
gc=renderer.new_gc()
595617
self._set_gc_clip(gc)
596-
gc.set_alpha(self.get_alpha())
618+
gc.set_alpha(self._get_scalar_alpha())
597619
gc.set_url(self.get_url())
598620
gc.set_gid(self.get_gid())
599621

‎lib/matplotlib/tests/test_image.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,3 +1118,22 @@ def test_image_cursor_formatting():
11181118

11191119
data=np.nan
11201120
assertim.format_cursor_data(data)=='[nan]'
1121+
1122+
1123+
@check_figures_equal()
1124+
deftest_image_array_alpha(fig_test,fig_ref):
1125+
'''per-pixel alpha channel test'''
1126+
x=np.linspace(0,1)
1127+
xx,yy=np.meshgrid(x,x)
1128+
1129+
zz=np.exp(-3* ((xx-0.5)**2)+ (yy-0.7**2))
1130+
alpha=zz/zz.max()
1131+
1132+
cmap=plt.get_cmap('viridis')
1133+
ax=fig_test.add_subplot(111)
1134+
ax.imshow(zz,alpha=alpha,cmap=cmap,interpolation='nearest')
1135+
1136+
ax=fig_ref.add_subplot(111)
1137+
rgba=cmap(colors.Normalize()(zz))
1138+
rgba[...,-1]=alpha
1139+
ax.imshow(rgba,interpolation='nearest')

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp