Настройка прозрачности на основе пиксельных значений в Matplotlib

18

Я пытаюсь использовать 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()

Что дает:

И второй растр ascii, который определяет свойства реки, текущей по ландшафту. Эти данные могут быть построены таким же образом, как указано выше, однако значения в массиве, которые не соответствуют речной сети, не имеют значения данных -9999. Цель состоит в том, чтобы значения данных не были прозрачными, поэтому значения рек лежат на холме.

Это речные данные, в идеале каждый пиксель, представленный здесь как 0, будет полностью прозрачным.

Проведя некоторые исследования по этому вопросу, похоже, я смогу преобразовать свои данные в массив RGBA и установить альфа-значения только для того, чтобы сделать нежелательные ячейки прозрачными. Однако значения в массиве рек являются поплавками и не могут быть преобразованы (поскольку исходные значения являются целыми точками фигуры), и я считаю, что функция imshow может принимать только целые числа без знака, используя формат RGBA.

Есть ли способ ограничить это ограничение? Я надеялся, что могу просто создать кортеж с пиксельным значением и альфа-значением и построить их так, но это не представляется возможным.

У меня также была игра с PIL , чтобы попытаться создать PNG-файл речных данных без прозрачного значения данных, однако это, похоже, автоматически масштабирует значения пикселей до 0-255, тем самым теряя значения I необходимо сохранить.

Я был бы рад любому прозрению, которое кто-либо может решить по этой проблеме.

    
задан sgrieve 18.06.2013 в 15:31
источник

2 ответа

32

Просто замаскируйте свой «речной» массив.

например.

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 с радостью примет float для своего формата RGBA. Он просто ожидает, что все будет в диапазоне от 0 до 1.

    
ответ дан Joe Kington 18.06.2013 в 15:46
источник
  • Блестящий! Спасибо. Я надеялся на элегантное решение, подобное этому, но явно лаял неправильное дерево. –  sgrieve 18.06.2013 в 16:07
  • Ограничено ли это 2-мя массивами или будет работать с 3 или более? –  MyCarta 11.03.2015 в 21:29
  • @MyCarta - он будет работать с большим количеством массивов, как вам хотелось бы, но ваши маскирующие выражения могут стать сложными. Чтобы объединить булевы выражения с массивами numpy, вам нужно использовать & вместо &, | вместо или ~ вместо вместо и т. д. Например: (a> 5) & (b> 5) вместо a> 5 и b> 5. Вы также не сможете связать операторов совершенно так же , например вам нужно (x> 2) & (x <5) вместо 2> x> 5. –  Joe Kington 11.03.2015 в 22:08
11

Альтернативный способ сделать это без использования маскированных массивов - установить, как цветовая карта имеет значения отсечения ниже минимума 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()

Здесь также есть set_over для отсечения сверху и set_bad для настройки того, как цветовая карта обрабатывает «плохие» значения в данных.

Преимущество такого способа заключается в том, что вы можете изменить свой порог, просто скорректировав clim с im.set_clim([bot, top])

    
ответ дан tacaswell 18.06.2013 в 23:04
источник