Matplotlib: заполнить из двоичных данных - PullRequest
0 голосов
/ 19 декабря 2018

У меня есть двоичный массив numpy, который содержит данные заливки, и две сетки, которые определяют ограничивающий прямоугольник для данных:

data = np.random.choice([0, 1], size=12).reshape((3, 4))
xGrid = np.linspace(1, 4, 4)
yGrid = np.linspace(0.1, 0.3, 3)

Я хотел бы нанести на график определенный цвет с определенной альфав любой точке сетки, где данные 1 и ничего , если данные 0.Две самые близкие функции matplotlib:

  • fill, которые требуют (x, y) координат и не могут работать с этими данными
  • imshow или matshow, чток сожалению, повсюду будет изображен какой-нибудь цвет То есть он также будет отображать некоторые цвета, нарисованные на карте цветов, где бы data == 0.Теперь я мог бы поиграть, чтобы сделать этот цвет фоновым цветом топора, но это довольно неприятно.

Ожидается, что ограничивающие рамки будут вести себя следующим образом: xGrid содержит три значения, иВ x-измерении есть три точки данных.Каждое значение в xGrid обозначает местоположение центральной точки для каждой из точек данных и аналогично для yGrid.Тогда «заполнение точки данных» соответствует заполнению прямоугольника, определяемого координатами центра (x, y).

Каков наилучший способ достижения этого?

Ответы [ 4 ]

0 голосов
/ 19 декабря 2018

В другой ответ Я упомянул, что возможные проблемы с эффективностью можно решить с помощью Rectangle патчей и PatchCollection - здесь это реализацияэтот подход.Сначала при инициализации обратите внимание на импорт Rectangle и PatchCollection

In [99]: import numpy as np 
    ...: import matplotlib.pyplot as plt 
    ...: from matplotlib.collections import PatchCollection 
    ...: from matplotlib.patches import Rectangle 
    ...:  
    ...: np.random.seed(2018) 
    ...: data = np.random.choice([0, 1], size=12).reshape((3, 4)) 
    ...: xGrid = np.linspace(1, 4, 4) 
    ...: yGrid = np.linspace(0.1, 0.3, 3) 
    ...: dx, dy = (xGrid[1]-xGrid[0])/2, (yGrid[1]-yGrid[0])/2 
    ...: print(data)                                                                             
[[0 0 0 1]
 [1 0 0 0]
 [1 1 1 1]]

Далее мы создаем PatchCollection: нам нужен предварительный списокпатчей, мы зациклились на строках data И y , а также на столбцах в каждой строке И x , если нам нужно добавить Rectangle ксписок патчей и, наконец, мы его создаем

In [100]: patches = [] 
     ...: for y, row in zip(yGrid, data): 
     ...:     for x, col in zip(xGrid, row): 
     ...:         if col: patches.append(Rectangle((x-dx, y-dy), 2*dx, 2*dy)) 
     ...: pc = PatchCollection(patches) 

И, в конце концов, для построения графика нам нужны два метода осей, поэтому требуется plt.gca(), мы изменяем прямоугольники, используя методы сбора пути, committколлекцию в ax и, наконец, мы явно вызываем метод autoscale_view, который требуется , чтобы иметь правильные пределы осей.

In [101]: ax = plt.gca() 
     ...: pc.set_facecolor('yellow') 
     ...: pc.set_edgecolor('black') 
     ...: ax.add_collection(pc) 
     ...: ax.autoscale_view()                                                                    

И это результат

enter image description here

0 голосов
/ 19 декабря 2018

Вы можете управлять цветом с помощью параметра colormap .Здесь быстрое решение с использованием imshow, с полным контролем всех параметров, в частности пользовательских цветов:

from pylab import imshow,show,cm
from matplotlib.colors import LinearSegmentedColormap
alpha=.7
cdict = {'blue': ((0.0, 0.0, 0.0), (1.0, 0.0, 0.0)),
 'green': ((0.0, 0.0, 0.0), (1.0, 0.0, 0.0)),
 'red': ((0.0, 0.0, 0.0), (1.0, alpha,alpha))} 
mycolors = LinearSegmentedColormap("my_colors",cdict,N=2)

ax=imshow(data,cmap=mycolors)
ax.axes.set_xticks(np.arange(len(xGrid)))
ax.axes.set_xticklabels([str(a) for a in xGrid])
ax.axes.set_yticks(np.arange(len(yGrid)))
ax.axes.set_yticklabels([str(a) for a in yGrid])
ax.axes.set_xbound(-.5,3.5)
ax.axes.set_ybound(-.5,2.5)
ax.axes.set_aspect(.2/3)

Для: enter image description here

0 голосов
/ 19 декабря 2018

С учетом того, что заполненные области должны быть нарисованы с использованием пересечений сетки в качестве центральных точек, мы имеем

In [27]: import numpy as np 
    ...: import matplotlib.pyplot as plt 
    ...: np.random.seed(2018) 
    ...: data = np.random.choice([0, 1], size=12).reshape((3, 4)) 
    ...: xGrid = np.linspace(1, 4, 4) 
    ...: yGrid = np.linspace(0.1, 0.3, 3)                                                 

In [28]: print(data)                                                                      
[[0 0 0 1]
 [1 0 0 0]
 [1 1 1 1]]

In [29]: dx, dy = (xGrid[1]-xGrid[0])/2, (yGrid[1]-yGrid[0])/2                                    

In [30]: xli, yli = [], [] 
    ...: for y in yGrid: 
    ...:     for x in xGrid: # the x's in data are changing faster, so inner loop
    ...:         xli.append([x-dx, x+dx, x+dx, x-dx, x-dx]) 
    ...:         yli.append([y-dy, y-dy, y+dy, y+dy, y-dy]) 

In [31]: for xs, ys, Bool in zip(xli, yli, data.flatten()): 
    ...:     if Bool : plt.fill(xs, ys, color='red')
    ...: plt.gca().set_facecolor('yellow')                                      

Выполнение кода выше дает мне enter image description here

Стоит отметить, что только закрашенные прямоугольники нарисованы, как показано путем заливки фона области построения другим цветом.

plt.fill задокументировано здесь и списки, созданные в первом цикле for, являются просто x , y координатами углов прямоугольника, которые могут быть нарисованы с помощью plt.fill.


Замечание по эффективности

Если нужно нарисовать несколько сотен прямоугольников, простой подход, описанный выше, будет в порядке, если мы перейдем к десяткам тысяч возможно мы хотим перебрать точки данных с помощью enumerate, если необходимо построить списки x , y и нарисовать прямоугольник на лету или,еще лучше для производительности, создайте патч Rectangle, вставьте его вPatchCollection и использовать метод ax.add_collection, когда мы завершим цикл на data - , доступен пример в документации Matplotlib, который можно легко адаптировать к области действия, и другой пример это мой новый ответ.

0 голосов
/ 19 декабря 2018

Использование imshow () на основе этого примера для использования alpha.

Я использую код set_ticks, заданный @ BM

def make_rgb_transparent(rgb, bg_rgb, alpha):
    return [alpha * c1 + (1 - alpha) * c2
            for (c1, c2) in zip(rgb, bg_rgb)]

import matplotlib
from matplotlib import colors

alpha =1.0
white = np.ones((1,3))
rgb = colors.colorConverter.to_rgb('red')
rgb_new = make_rgb_transparent(rgb, (1, 1, 1), alpha)
red_white_map = colors.LinearSegmentedColormap.from_list('map_white', np.vstack((white, rgb_new)),2)

ax=plt.imshow(data,cmap=red_white_map)
ax.axes.set_xticks(np.arange(len(xGrid)))
ax.axes.set_xticklabels([str(a) for a in xGrid])
ax.axes.set_yticks(np.arange(len(yGrid)))
ax.axes.set_yticklabels([str(a) for a in yGrid])

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...