2025, Nov 01 03:47
Преобразование сетки детектора в полярные координаты: theta против радиуса
Переводим матрицу бинов детектора в полярные координаты: theta и радиус. Почему cos(theta) искажает анализ и как построить правильный график в Python.
Преобразовать матрицу бинов детектора во что‑то действительно полезное для анализа чаще всего помогает верный выбор системы координат. Если распределение примерно круговое вокруг известного центра, отображение по радиусу и углу сразу выявляет структуру. Трудность не в API построения графиков, а в отображении: как перейти от декартовой сетки индексов бинов к полярному виду, который будет согласованным и однозначным. Ниже — короткое руководство по подходу: почему размещение cos(theta) на одной оси смешивает системы координат и как вместо этого получить аккуратную визуализацию «угол–радиус».
Постановка задачи
У нас есть двумерная сетка счетчиков, индексируемая как [x, y]. В некоторых ячейках нули, часть помечена как непригодные. Центр интереса — в точке (8, 8); для быстрой декартовой визуализации используем pcolor и пару окружностей‑ориентиров.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.patches import Circle
counts_grid = np.asarray(
[[ 0., 0., 0., 0., 0., 0., 2., 5., 2., 3., 3., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 4., 10., 9., 7., 10., 6., 6., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 9., 12., 10., 11., 14., 13., 11., 12., 6., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 12., 16., 17., 14., 13., 14., 13., 12., 12., 6., 0., 0., 0., 0.],
[ 0., 0., 10., 11., 0., 14., 18., 16., 14., 18., 16., 14., 13., 0., 9., 0., 0., 0.],
[ 0., 7., 10., 13., 13., 16., 16., 15., 14., 16., 13., 16., 13., 13., 13., 7., 0., 0.],
[ 1., 6., 15., 14., 17., 14., 13., 13., 14., 15., 1., 13., 13., 12., 12., 7., 2., 0.],
[ 5., 13., 11., 14., 12., 14., 14., 16., 16., 16., 12., 1., 12., 14., 12., 9., 5., 0.],
[ 2., 11., 11., 16., 13., 17., 15., 14., 0., 14., 14., 13., 13., 16., 10., 9., 6., 1.],
[ 4., 11., 13., 12., 14., 14., 16., 16., 14., 18., 16., 1., 14., 12., 12., 11., 5., 1.],
[ 1., 7., 10., 11., 13., 14., 1., 19., 15., 19., 1., 1., 14., 14., 11., 10., 1., 0.],
[ 0., 5., 10., 15., 14., 15., 16., 1., 14., 1., 1., 16., 12., 13., 10., 5., 0., 0.],
[ 0., 0., 7., 12., 16., 15., 13., 17., 14., 16., 14., 14., 14., 14., 7., 0., 0., 0.],
[ 0., 0., 0., 7., 0., 14., 14., 15., 16., 16., 14., 11., 13., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 8., 12., 14., 12., 14., 10., 11., 12., 7., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 8., 8., 11., 9., 9., 10., 5., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 4., 3., 7., 6., 3., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 2., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0.]]
)/12
counts_grid[4][4] = None
counts_grid[-5][-5] = None
counts_grid[4][-5] = None
counts_grid[-5][4] = None
counts_grid[8][8] = None
# Неисправные ячейки
counts_grid[6, 10] = None
counts_grid[10, 6] = None
counts_grid[7, 11] = None
counts_grid[11, 7] = None
counts_grid[11, 9] = None
counts_grid[11, 10] = None
counts_grid[10, 11] = None
counts_grid[9, 11] = None
counts_grid[10, 10] = None
fig_obj, axes_obj = plt.subplots()
plt.pcolor(counts_grid)
plt.colorbar(label="Count per hour")
ring = Circle((8.5, 8.5), 8, edgecolor='red', facecolor='none', linewidth=1)
axes_obj.add_patch(ring)
ring = Circle((8.5, 8.5), 6, edgecolor='red', facecolor='none', linewidth=1)
axes_obj.add_patch(ring)
plt.show()Что на самом деле происходит
Цель заключалась в том, чтобы поместить cos(phi) на ось X и расстояние от центра — на ось Y. В этом контексте плоский угол удобнее обозначать как theta. Использовать cos(theta) как ось — значит смешивать представления: x = r*cos(theta) — часть преобразования из полярных координат в декартовы, так что одна ось окажется полярной, а другая — нет. Есть и неоднозначность: cos(theta) сопоставляет двум разным углам одно и то же значение, поэтому точки с theta = pi/4 и theta = -pi/4 схлопнутся в одну x‑координату. Это приемлемо лишь тогда, когда анализ явно допускает такую вырожденность.
Более аккуратный способ диагностики круговой или радиальной структуры — последовательно работать в полярных координатах. Для каждого центра ячейки вычислите theta и радиус относительно выбранного центра, затем постройте график: theta по одной оси, радиус по другой, а цвет используйте для значения в ячейке. Так сохраняется взаимно‑однозначное соответствие между ячейками и точками, избегается непреднамеренное «складывание», и удобнее оценивать радиальную симметрию.
Решение: преобразовать индексы сетки в полярные координаты и построить theta против радиуса
Этот фрагмент с помощью meshgrid формирует декартовы координаты центров ячеек, смещает начало в точку (8, 8), «расплющивает» массивы, отбрасывает нулевые ячейки, переводит координаты в полярные и строит диаграмму рассеяния theta против радиуса, кодируя цветом значение ячейки.
x_idx = np.arange(counts_grid.shape[1])
y_idx = np.arange(counts_grid.shape[0])
xx, yy = np.meshgrid(x_idx, y_idx)
origin = (8, 8)
xx = xx - origin[0]
yy = yy - origin[1]
xx_vec = xx.flatten()
yy_vec = yy.flatten()
vals_vec = counts_grid.flatten()
# Оставляем ненулевые ячейки
keep = vals_vec != 0
xx_vec = xx_vec[keep]
yy_vec = yy_vec[keep]
vals_vec = vals_vec[keep]
angle = np.atan2(yy_vec, xx_vec)
radius = np.sqrt(xx_vec ** 2 + yy_vec ** 2)
plt.scatter(angle, radius, c=vals_vec, s=30)
plt.xlabel("Theta (radians)")
plt.ylabel("Radius (unknown unit)")
plt.colorbar(label="Count per hour")
plt.show()Если для дальнейшего анализа вам действительно нужен cos(theta), можно спроецировать угловую координату на этапе построения, заменив вызов scatter строкой ниже. Имейте в виду: таким образом симметричные углы намеренно сводятся к одним и тем же x‑значениям.
plt.scatter(np.cos(angle), radius, c=vals_vec, s=30)Почему это важно
Работа напрямую с theta и радиусом согласует визуализацию с геометрией поля с радиальной структурой. Это позволяет не смешивать полярные и декартовы компоненты на разных осях, сохраняет уникальность представления каждой ячейки и облегчает поиск закономерностей вдоль радиуса или угла. Удаление нулевых ячеек фокусирует график на информативных данных и снижает визуальный шум. Если позже решите спроецировать угловое измерение через cos(theta), вы сделаете это осознанно, понимая, что противоположные углы совпадут.
Выводы
Когда двумерная сетка намекает на круговую симметрию, переведите индексы в полярные координаты относительно интересующего центра и визуализируйте theta против радиуса. Используйте meshgrid для генерации декартовых координат ячеек, сдвигайте к выбранному началу, вычисляйте theta через atan2 и радиус через sqrt, а цветом показывайте значения. Оставляйте cos(theta) для случаев, когда намеренно нужно «схлопнуть» симметричные углы; в остальных ситуациях сохраняйте theta как есть, чтобы получить однозначную картину.
Статья основана на вопросе на StackOverflow от David K. и ответе Nick ODell.