Настройка прозрачности на основе значений пикселей в Matplotlib
Я пытаюсь использовать 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()
Что дает:
![Hillshade]()
И второй растр ascii, который определяет свойства реки, текущей по ландшафту. Эти данные могут быть построены таким же образом, как указано выше, однако значения в массиве, которые не соответствуют речной сети, не имеют значения данных -9999. Цель состоит в том, чтобы значения данных не были прозрачными, поэтому значения рек лежат на холме.
Это речные данные, в идеале каждый пиксель, представленный здесь как 0, будет полностью прозрачным.
![River data]()
Проведя некоторые исследования по этому вопросу, похоже, я смогу преобразовать свои данные в массив RGBA и установить альфа-значения только для того, чтобы сделать нежелательные ячейки прозрачными. Однако значения в массиве рек являются поплавками и не могут быть преобразованы (поскольку исходные значения являются целыми точками фигуры), и я полагаю, что функция imshow
может принимать только целые числа без знака, если используется формат RGBA.
Есть ли способ ограничить это ограничение? Я надеялся, что могу просто создать кортеж с пиксельным значением и альфа-значением и построить их так, но это не представляется возможным.
У меня также была игра с PIL
, чтобы попытаться создать PNG файл речных данных без прозрачного значения данных, однако это, похоже, автоматически масштабирует значения пикселей до 0-255, тем самым теряя значения я необходимо сохранить.
Я был бы рад любому прозрению, которое кто-либо может решить по этой проблеме.
Ответы
Ответ 1
Просто замаскируйте свой "речной" массив.
например
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
радостью примет float для своего формата RGBA. Он просто ожидает, что все будет в диапазоне от 0 до 1.
Ответ 2
Альтернативный способ сделать это с использованием маскированных массивов - установить, как цветовая карта имеет значения отсечения ниже минимума clim
(бесстыдно с использованием примера Джо Кингтона):
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
для отсечения сверху и a set_bad
для настройки того, как цветовая карта обрабатывает "плохие" значения в данных.
Преимущество такого способа заключается в том, что вы можете изменить свой порог, просто изменив clim
на im.set_clim([bot, top])