Перегруппировать данные в двумерном массиве в соответствии с преобразованием из полярных в декартовы координаты - PullRequest
8 голосов
/ 10 марта 2020

У меня есть двумерный массив, который представляет значения функций в позициях в полярной системе координат. Например:

import numpy as np

radius = np.linspace(0, 1, 50)
angle = np.linspace(0, 2*np.pi, radius.size)
r_grid, a_grid = np.meshgrid(radius, angle)
data = np.sqrt((r_grid/radius.max())**2
               + (a_grid/angle.max())**2)

Здесь data расположен в прямоугольной сетке angular, соответствующей полярным координатам. Я хочу переставить данные в массиве так, чтобы оси представляли соответствующую декартову систему координат. Старый и новый макет можно визуализировать следующим образом:

import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=plt.figaspect(0.5))
ax1.set(title='Polar coordinates', xlabel='Radius', ylabel='Angle')
ax1.pcolormesh(r_grid, a_grid, data)
ax2.set(title='Cartesian coordinates', xlabel='X', ylabel='Y')
x_grid = r_grid * np.cos(a_grid)
y_grid = r_grid * np.sin(a_grid)
ax2.pcolormesh(x_grid, y_grid, data)

Example

Здесь координаты даны в явном виде и график соответствующим образом скорректирован. Я хочу, чтобы данные были переставлены в самом массиве данных вместо этого. Он должен содержать все значения, необязательно, заполняя нулями, чтобы соответствовать форме (аналогично scipy.ndimage.rotate(..., reshape=True)).

Если я вручную l oop поверх полярных массивов для вычисления декартовых координат результат содержит пустые области, которые в идеале также должны быть заполнены:

new = np.zeros_like(data)
visits = np.zeros_like(new)
for r, a, d in np.nditer((r_grid, a_grid, data)):
    i = 0.5 * (1 + r * np.sin(a)) * new.shape[0]
    j = 0.5 * (1 + r * np.cos(a)) * new.shape[1]
    i = min(int(i), new.shape[0] - 1)
    j = min(int(j), new.shape[1] - 1)
    new[i, j] += d
    visits[i, j] += 1
new /= np.maximum(visits, 1)
ax2.imshow(new, origin='lower')

Example attempt

Есть ли способ добиться преобразования, избегая пустых областей в результирующем массиве данных?

Ответы [ 3 ]

2 голосов
/ 10 марта 2020

tl; dr: Нет, не без изменения некоторых условий вашей проблемы.

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

  • Единственный «чистый» способ (о котором я могу думать прямо сейчас) справиться с этим, чтобы иметь регулируемое разрешение в полярных координатах для учета масштабирования 1 / r. (Если вы вводите данные, это позволяет)

  • Несколько обманчивый способ визуализации этого без пропусков будет случайным образом распределять их по пропускам. Аргумент здесь заключается в том, что у вас нет разрешения решать, в каком бункере они должны были начинаться. Таким образом, вы можете просто случайным образом бросить их в тот, который мог быть возможным источником, и не бросать их все в один (как вы делаете сейчас). Тем не менее, я хотел бы препятствовать этой сильности. Это просто дает вам более симпатичный сюжет. Обратите внимание, что это в некоторой степени эквивалентно поведению верхнего правого графика в вашем вопросе.

1 голос
/ 10 марта 2020

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


import numpy as np

radius = np.linspace(0, 1, 50)
angle = np.linspace(0, 2*np.pi, radius.size)
r_grid, a_grid = np.meshgrid(radius, angle)
data = np.sqrt((r_grid/radius.max())**2
               + (a_grid/angle.max())**2)


def polar_to_cartesian(data):
    new = np.zeros_like(data) * np.nan
    x = np.linspace(-1, 1, new.shape[1])
    y = np.linspace(-1, 1, new.shape[0])
    for i in range(new.shape[0]):
        for j in range(new.shape[1]):
            x0, y0 = x[j], y[i]
            r, a = np.sqrt(x0**2 + y0**2), np.arctan2(y0, x0)
            data_i = np.argmin(np.abs(a_grid[:, 0] - a))
            data_j = np.argmin(np.abs(r_grid[0, :] - r))
            val = data[data_i, data_j]

            if r <= 1:
                new[i, j] = val

    return new

new = polar_to_cartesian(data)
fig, ax = plt.subplots()
ax.imshow(new, origin='lower')

enter image description here

РЕДАКТИРОВАТЬ: Изменено с помощью np.arctan2 в соответствии с предложениями OP.

0 голосов
/ 10 марта 2020

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

Я не думаю, что есть лучший способ, если, конечно, у вас нет доступа к исходной функции.

...