在Matplotlib中基于像素值设置透明度

rqmkfv5c  于 2023-08-06  发布在  其他
关注(0)|答案(4)|浏览(134)

我正在尝试使用matplotlib来绘制我正在写的一篇论文的一些图形。我在2D numpy数组中有两组数据:一个ascii hillshade光栅,我可以很高兴地绘制和调整使用:

import matplotlib.pyplot as pp
import numpy as np

hillshade = np.genfromtxt('hs.asc', delimiter=' ', skip_header=6)[:,:-1]

pp.imshow(hillshade, vmin=0, vmax=255)
pp.gray()
pp.show()

字符串
其给出:
x1c 0d1x的数据
第二个ascii光栅描绘了流经景观的河流的特性。该数据可以以与上述相同的方式绘制,但是数组中不对应于河流网络的值被指定为无数据值-9999。目的是将“无数据”值设置为透明,以便河流值覆盖山体阴影。
这是河流数据,理想情况下,这里表示为0的每个像素都是完全透明的。



在这方面做了一些研究后,我似乎可以将我的数据转换为RGBA数组,并设置alpha值,使不需要的单元格透明。然而,river数组中的值是浮点数,不能被转换(因为原始值是图中的整个点),我相信imshow函数在使用RGBA格式时只能接受无符号整数。
有没有办法绕过这个限制?我曾希望我可以简单地创建一个包含像素值和alpha值的元组,并像那样绘制它们,但这似乎不可能。
我还尝试使用PIL创建一个河流数据的PNG文件,其中没有数据值是透明的,但是这似乎会自动将像素值缩放到0-255,从而丢失了我需要保留的值。
我欢迎任何人对这个问题的任何见解。

vwhgwdsa

vwhgwdsa1#

只需要mask你的“river”数组。
例如,在

rivers = np.ma.masked_where(rivers == 0, rivers)

字符串
作为以这种方式叠加两个图的快速示例:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm

# Generate some data...
gray_data = np.arange(10000).reshape(100, 100)

masked_data = np.random.random((100,100))
masked_data = np.ma.masked_where(masked_data < 0.9, masked_data)

# Overlay the two images
fig, ax = plt.subplots()
ax.imshow(gray_data, cmap=cm.gray)
ax.imshow(masked_data, cmap=cm.jet, interpolation='none')
plt.show()


的数据
另外,顺便说一下,imshow很乐意接受其RGBA格式的浮点数。它只是期望所有值都在0和1之间。

o75abkj4

o75abkj42#

另一种不使用掩码数组的方法是设置颜色Map如何处理低于clim最小值的裁剪值(无耻地使用Joe Kington的例子):

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm

# Generate some data...
gray_data = np.arange(10000).reshape(100, 100)

masked_data = np.random.random((100,100))

my_cmap = cm.jet
my_cmap.set_under('k', alpha=0)

# Overlay the two images
fig, ax = plt.subplots()
ax.imshow(gray_data, cmap=cm.gray)
im = ax.imshow(masked_data, cmap=my_cmap, 
          interpolation='none', 
          clim=[0.9, 1])
plt.show()

字符串


的数据
还有一个set_over用于裁剪顶部,还有一个set_bad用于设置颜色Map表如何处理数据中的“坏”值。
这样做的一个优点是,您可以通过使用im.set_clim([bot, top])调整clim来更改阈值

wqsoz72f

wqsoz72f3#

另一种选择是将所有保持透明的单元格设置为np.nan(不知道这里哪个更有效,我猜基于climtacaswell's answer将是最快的)。适配Joe Kington's answer示例:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm

# Generate some data...
gray_data = np.arange(10000).reshape(100, 100)

masked_data = np.random.random((100,100))
masked_data[np.where(masked_data < 0.9)] = np.nan

# Overlay the two images
fig, ax = plt.subplots()
ax.imshow(gray_data, cmap=cm.gray)
ax.imshow(masked_data, cmap=cm.jet, interpolation='none')
plt.show()

字符串


的数据
请注意,对于dtype=bool数组,您不应该遵循IDE的建议,为了PEP 8(E712)而比较masked_data is True,而是坚持使用masked_data == True进行元素比较,否则掩码将失败:

zpjtge22

zpjtge224#

另一种策略是导出河流分支网络。这通常是水文流量路由工具中的一个选项。我不确定你在这里使用了哪个工具,但下面是一个使用Python pysheds库的示例,它需要一个光栅类型文件,因此使用tiff文件而不是2D numpy数组:

from pysheds.grid import Grid
import matplotlib.pyplot as plt
import numpy as np

# Instantiate grid from raster
grid = Grid.from_raster('test1.tif')
dem = grid.read_raster('test1.tif')

# Fill pits
pit_filled_dem = grid.fill_pits(dem)

# Fill depressions
flooded_dem = grid.fill_depressions(pit_filled_dem)

# Resolve flats and compute flow directions
inflated_dem = grid.resolve_flats(flooded_dem)
fdir = grid.flowdir(inflated_dem)

# Compute accumulation
acc = grid.accumulation(fdir)

# Extract river branch network for accumulations > 1000 units
branches = grid.extract_river_network(fdir, acc > 1000)

# Create fig and axes objects of matplotlib figure
fig, ax = plt.subplots()

# Set limits and aspect and tick formatting
plt.xlim(grid.bbox[0], grid.bbox[2])
plt.ylim(grid.bbox[1], grid.bbox[3])
ax.set_aspect('equal')
ax.ticklabel_format(style='sci', scilimits=(0,0), axis='both')

# Set the axes color to gray to demonstrate non-river pixels 
ax.set_facecolor('lightgray')

# Plot the river branch network using for loop
for branch in branches['features']:
    line = np.asarray(branch['geometry']['coordinates'])
    plt.plot(line[:, 0], line[:, 1], color='k')

字符串


的数据

相关问题