根据Matplotlib中的像素值设置透明度

时间:2013-06-18 13:31:22

标签: python matplotlib python-imaging-library

我正在尝试使用matplotlib为我正在制作的论文绘制一些数字。我在2D numpy数组中有两组数据:ascii hillshade raster,我可以愉快地绘制和调整使用:

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

给出了:

Hillshade

第二个ascii栅格,描绘了流经景观的河流的属性。该数据可以以与上述相同的方式绘制,但是阵列中不对应于河网的值被指定为-9999的无数据值。目的是将无数据值设置为透明,以便河流值覆盖山体阴影。

这是河流数据,理想情况下,此处表示为0的每个像素都是完全透明的。

River data

对此进行了一些研究后,我似乎可以将我的数据转换为RGBA数组,并将alpha值设置为仅使不需要的单元格透明。但是,河流数组中的值是浮点数并且无法转换(因为原始值是图中的整点),我相信imshow函数只能使用RGBA格式时采用无符号整数。

有没有办法解决这个限制?我希望我可以简单地创建一个带有像素值和alpha值的元组,然后将它们绘制成这样,但这似乎不可能。

我还有一个PIL的游戏试图创建一个没有数据值透明的河流数据的PNG文件,但是这似乎会自动将像素值缩放到0-255,从而失去了我需要保留的价值。

我欢迎任何人对这个问题有任何见解。

3 个答案:

答案 0 :(得分:38)

只需mask您的“河流”阵列。

e.g。

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

enter image description here

另外,在旁注中,imshow将很乐意接受其RGBA格式的浮点数。它只是希望一切都在0到1之间。

答案 1 :(得分:12)

使用蒙面数组执行此操作的另一种方法是设置颜色贴图处理剪裁值的方式,使其低于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()

example

还有一个用于剪裁顶部的set_over和一个set_bad用于设置颜色映射处理数据中“错误”值的方式。

这样做的一个好处是,只需使用clim

调整im.set_clim([bot, top])即可更改阈值

答案 2 :(得分:1)

另一个选项是将所有应保持透明的单元格设置为 np.nan (不确定这里哪个更有效,我猜基于 climtacaswell's answer 将是 fastet)。调整 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()

enter image description here

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