Python: создание 2D-гистограммы из матрицы numpy

Я новичок в питоне.

У меня есть матрица numpy размером 42x42 со значениями в диапазоне 0-996. Я хочу создать двухмерную гистограмму, используя эти данные. Я просматривал учебные пособия, но все они, кажется, показывают, как создавать 2D-гистограммы из случайных данных, а не из матрицы чисел.

Пока я импортировал:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors

Я не уверен, что это правильный импорт, я просто пытаюсь понять, что могу, из учебных пособий, которые я вижу.

У меня есть матрица numpy M со всеми значениями в ней (как описано выше). В конце концов, я хочу, чтобы это выглядело примерно так:

2D-гистограмма

очевидно, что мои данные будут другими, поэтому мой график должен выглядеть иначе. Кто-нибудь может мне помочь?

Изменить. Для моих целей приведенный ниже пример Hooked с использованием matshow - это именно то, что я ищу.


person Kestrel    schedule 26.11.2014    source источник
comment
каковы ваши x и y в матрице numpy, в основном 42 строки и 42 столбца. каковы ваши значения x, y?   -  person Kirubaharan J    schedule 26.11.2014
comment
Да, моя матрица состоит из 42 строк и 42 столбцов. В каждом индексе есть целое число от 0 до 996, которое было вычислено и помещено туда ранее в программе.   -  person Kestrel    schedule 27.11.2014


Ответы (4)


Если у вас есть необработанные данные подсчетов, вы можете использовать plt.hexbin для создания графиков для вас (IMHO, это лучше, чем квадратная решетка): адаптировано из примера _ 2_:

import numpy as np
import matplotlib.pyplot as plt

n = 100000
x = np.random.standard_normal(n)
y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
plt.hexbin(x,y)

plt.show()

введите описание изображения здесь

Если у вас уже есть Z-значения в матрице, как вы упомянули, просто используйте plt.imshow или plt.matshow:

XB = np.linspace(-1,1,20)
YB = np.linspace(-1,1,20)
X,Y = np.meshgrid(XB,YB)
Z = np.exp(-(X**2+Y**2))
plt.imshow(Z,interpolation='none')

введите описание изображения здесь

person Hooked    schedule 26.11.2014
comment
matshow это именно то, что я ищу. Большое спасибо! - person Kestrel; 26.11.2014
comment
Чтобы оси были правильно помечены, вы можете передать экстент в imshow с минимальными и максимальными значениями краев бункера. - person Jim Hunziker; 11.09.2018
comment
Также ознакомьтесь с официальными примерами, используя matplotlib < / i> функции imshow, pcolormesh и NonUniformImage. - person Stefano; 24.05.2021

Если у вас есть не только матрица 2D-гистограммы, но и лежащие в основе (x, y) данные, то вы можете построить диаграмму рассеяния (x, y) точек и раскрасить каждую точку в соответствии с ее значением счетчика в матрице 2D-гистограммы:

import numpy as np
import matplotlib.pyplot as plt

n = 10000
x = np.random.standard_normal(n)
y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
xedges, yedges = np.linspace(-4, 4, 42), np.linspace(-25, 25, 42)
hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges))
xidx = np.clip(np.digitize(x, xedges), 0, hist.shape[0]-1)
yidx = np.clip(np.digitize(y, yedges), 0, hist.shape[1]-1)
c = hist[xidx, yidx]
plt.scatter(x, y, c=c)

plt.show()

Пример диаграммы рассеяния 2D-гистограммы

person unutbu    schedule 26.11.2014

Я большой поклонник «гистограммы разброса», но я не думаю, что другие решения полностью соответствуют им. Вот функция, которая их реализует. Основным преимуществом этой функции по сравнению с другими решениями является то, что она сортирует точки по историческим данным (см. Аргумент mode). Это означает, что результат больше похож на традиционную гистограмму (т.е. вы не получите хаотичного перекрытия маркеров в разных ячейках). Гистограмма разброса

MCVE для этого рисунка (используя мою функцию):

import numpy as np
import matplotlib.pyplot as plt
from hist_scatter import scatter_hist2d

fig = plt.figure(figsize=[5, 4])
ax = plt.gca()

x = randgen.randn(npoint)
y = 2 + 3 * x + 4 * randgen.randn(npoint)

scat = scatter_hist2d(x, y,
                      bins=[np.linspace(-4, 4, 42),
                            np.linspace(-25, 25, 42)],
                      s=5,
                      cmap=plt.get_cmap('viridis'))
ax.axhline(0, color='k', linestyle='--', zorder=3, linewidth=0.5)
ax.axvline(0, color='k', linestyle='--', zorder=3, linewidth=0.5)
plt.colorbar(scat)

Есть куда расти?

Основным недостатком этого подхода является то, что точки в областях с наибольшей плотностью перекрывают точки в областях с более низкой плотностью, что приводит к некоторому искажению областей каждой ячейки. Я потратил довольно много времени на изучение двух подходов к решению этой проблемы:

1) использование маркеров меньшего размера для бункеров с более высокой плотностью

2) применение маски отсечения к каждой ячейке

Первый дает слишком безумные результаты. Второй выглядит красиво, особенно если вы обрезаете только те ячейки, которые имеют> ~ 20 точек, но он чрезвычайно медленный (этот рисунок занял около минуты).

Итак, в конечном итоге я решил, что, тщательно выбирая размер маркера и размер ячейки (s и bins), вы можете получить визуально приятные результаты и не так уж плохи с точки зрения искажения данных. В конце концов, эти двухмерные гистограммы обычно предназначены для визуального использования основных данных, а не для их количественного представления. Поэтому я думаю, что этот подход намного превосходит «традиционные 2D-гистограммы» (например, plt.hist2d или plt.hexbin), и я предполагаю, что если вы нашли эту страницу, вы также не являетесь поклонником традиционных (одноцветных) диаграмм рассеяния.

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

person farenorth    schedule 20.02.2019

Ответ @ unutbu содержит ошибку: xidx и yidx рассчитываются неверно (по крайней мере, в моем образце данных). Правильный способ должен быть:

xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1)
yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1)

Поскольку значение возврата np.digitize, которое нас интересует, находится между 1 и len(xedges) - 1, но c = hist[xidx, yidx] нужны индексы между 0 и hist.shape - 1.


Ниже приводится сравнение результатов. Как видите, вы получите похожий, но не тот же результат.

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

n = 10000
x = np.random.standard_normal(n)
y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
xedges, yedges = np.linspace(-4, 4, 42), np.linspace(-25, 25, 42)
hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges))

xidx = np.clip(np.digitize(x, xedges), 0, hist.shape[0] - 1)
yidx = np.clip(np.digitize(y, yedges), 0, hist.shape[1] - 1)
c = hist[xidx, yidx]
old = ax1.scatter(x, y, c=c, cmap='jet')

xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1)
yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1)

c = hist[xidx, yidx]
new = ax2.scatter(x, y, c=c, cmap='jet')


plt.show()

То же самое, но другое

person TheoryX    schedule 15.09.2017
comment
Публикуя ответ, убедитесь, что ваш ответ не основан на информации, содержащейся в других ответах. Вы правильно описали проблему в другом ответе (что неплохо), но затем предоставили только частичное решение, которое нельзя использовать, не глядя на другой ответ. Пожалуйста, отредактируйте свой ответ и включите полный фрагмент, иначе ваше сообщение, вероятно, будет удалено. - person Noel Widmer; 15.09.2017