Как нарисовать диаграмму рассеяния с линиями плотности контура в полярных координатах с помощью Matplotlib?
Я пытаюсь сделать точечную диаграмму в полярные координаты с контурными линиями, наложенными на облако точек. Я знаю, как это сделать в декартовых координатах, используя numpy.histogram2d
:
# Simple case: scatter plot with density contours in cartesian coordinates
import matplotlib.pyplot as pl
import numpy as np
np.random.seed(2015)
N = 1000
shift_value = -6.
x1 = np.random.randn(N) + shift_value
y1 = np.random.randn(N) + shift_value
fig, ax = pl.subplots(nrows=1,ncols=1)
ax.scatter(x1,y1,color='hotpink')
H, xedges, yedges = np.histogram2d(x1,y1)
extent = [xedges[0],xedges[-1],yedges[0],yedges[-1]]
cset1 = ax.contour(H,extent=extent)
# Modify xlim and ylim to be a bit more consistent with what's next
ax.set_xlim(xmin=-10.,xmax=+10.)
ax.set_ylim(ymin=-10.,ymax=+10.)
выход здесь:
однако, когда я пытаюсь перенести свой код на полярные координаты, я получаю искаженные контурные линии. Вот мой код и произведенный (неправильный) вывод:
# Case with polar coordinates; the contour lines are distorted
np.random.seed(2015)
N = 1000
shift_value = -6.
def CartesianToPolar(x,y):
r = np.sqrt(x**2 + y**2)
theta = np.arctan2(y,x)
return theta, r
x2 = np.random.randn(N) + shift_value
y2 = np.random.randn(N) + shift_value
theta2, r2 = CartesianToPolar(x2,y2)
fig2 = pl.figure()
ax2 = pl.subplot(projection="polar")
ax2.scatter(theta2, r2, color='hotpink')
H, xedges, yedges = np.histogram2d(x2,y2)
theta_edges, r_edges = CartesianToPolar(xedges[:-1],yedges[:-1])
ax2.contour(theta_edges, r_edges,H)
на неправильно вывод здесь:
есть ли способ иметь контурные линии в правильном масштабе?
EDIT для рассмотрения предложений, сделанных в комментариях.
EDIT2: кто-то предположил, что вопрос может быть дубликатом этот вопрос. Хотя я признаю, что проблемы схожи, моя касается конкретно построения контуров плотности точек над диаграммой рассеяния. Другой вопрос о том, как построить контур уровни любого количества, заданного вместе с координатами точек.
1 ответов
проблема в том, что вы конвертируете только края массива. Преобразуя только координаты X и y ребер, вы эффективно преобразуете координаты диагональной линии через 2D-массив. Эта линия имеет очень маленький диапазон theta
значения, и вы применяете этот диапазон ко всей сетке.
быстрое (но неправильное) исправление
в большинстве случаев вы можете преобразовать всю сетку (т. е. 2D-массивы x
и y
, изготовления 2D массивы theta
и r
) в полярных координатах.
вместо:
H, xedges, yedges = np.histogram2d(x2,y2)
theta_edges, r_edges = CartesianToPolar(xedges[:-1],yedges[:-1])
сделать что-то похожее на:
H, xedges, yedges = np.histogram2d(x2,y2)
xedges, yedges = np.meshgrid(xedges[:-1],yedges[:-1]
theta_edges, r_edges = CartesianToPolar(xedges, yedges)
как пример:
import numpy as np
import matplotlib.pyplot as plt
def main():
x2, y2 = generate_data()
theta2, r2 = cart2polar(x2,y2)
fig2 = plt.figure()
ax2 = fig2.add_subplot(111, projection="polar")
ax2.scatter(theta2, r2, color='hotpink')
H, xedges, yedges = np.histogram2d(x2,y2)
xedges, yedges = np.meshgrid(xedges[:-1], yedges[:-1])
theta_edges, r_edges = cart2polar(xedges, yedges)
ax2.contour(theta_edges, r_edges, H)
plt.show()
def generate_data():
np.random.seed(2015)
N = 1000
shift_value = -6.
x2 = np.random.randn(N) + shift_value
y2 = np.random.randn(N) + shift_value
return x2, y2
def cart2polar(x,y):
r = np.sqrt(x**2 + y**2)
theta = np.arctan2(y,x)
return theta, r
main()
, вы можете заметить, что это выглядит немного неправильно. Это потому что ax.contour
неявно предполагает, что входные данные на регулярной сетке. Мы дали ему регулярную сетку в декартовых координатах, но не регулярную сетку в полярных координирует. Предполагается, что мы прошли через обычную сетку в полярных координатах. Мы могли бы перепроверить сетку, но есть более простой способ.
правильное решение
чтобы правильно построить 2D-гистограмму, вычислите гистограмму в Полярном пространстве.
например, сделать что-то похожее на:
theta2, r2 = cart2polar(x2,y2)
H, theta_edges, r_edges = np.histogram2d(theta2, r2)
ax2.contour(theta_edges[:-1], r_edges[:-1], H)
как пример:
import numpy as np
import matplotlib.pyplot as plt
def main():
x2, y2 = generate_data()
theta2, r2 = cart2polar(x2,y2)
fig2 = plt.figure()
ax2 = fig2.add_subplot(111, projection="polar")
ax2.scatter(theta2, r2, color='hotpink')
H, theta_edges, r_edges = np.histogram2d(theta2, r2)
ax2.contour(theta_edges[:-1], r_edges[:-1], H)
plt.show()
def generate_data():
np.random.seed(2015)
N = 1000
shift_value = -6.
x2 = np.random.randn(N) + shift_value
y2 = np.random.randn(N) + shift_value
return x2, y2
def cart2polar(x,y):
r = np.sqrt(x**2 + y**2)
theta = np.arctan2(y,x)
return theta, r
main()
наконец, вы можете заметить небольшое изменение в приведенном выше результате. Это связано с соглашениями сетки, ориентированными на ячейки (x[0,0], y[0,0]
дает центр ячейки) против ориентированных на ребро соглашений сетки (x[0,0], y[0,0]
дает нижний левый угол ячейки. ax.contour
ожидает, что все будет центрировано по ячейкам, но вы даете ему выровненные по краю значения x и y.
это всего лишь полуклеточный сдвиг, но если вы хотите его исправить, Сделайте что-то вроде:
def centers(bins):
return np.vstack([bins[:-1], bins[1:]]).mean(axis=0)
H, theta_edges, r_edges = np.histogram2d(theta2, r2)
theta_centers, r_centers = centers(theta_edges), centers(r_edges)
ax2.contour(theta_centers, r_centers, H)