Reorganizar los datos en una matriz bidimensional de acuerdo con la transformación de coordenadas polares a cartesianas

8

Tengo una matriz bidimensional que representa valores de función en posiciones en un sistema de coordenadas polares. Por ejemplo:

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)

Aquí el datase organiza en una cuadrícula rectangular correspondiente a las coordenadas polares. Quiero reorganizar los datos en la matriz de modo que los ejes representen el sistema de coordenadas cartesianas correspondiente. El diseño antiguo versus el nuevo se puede visualizar de la siguiente manera:

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)

Ejemplo

Aquí las coordenadas se dan explícitamente y la gráfica se ajusta en consecuencia. Quiero que los datos se reorganicen en la matriz de datos en su lugar. Debe contener todos los valores, opcionalmente rellenando con ceros para ajustarse a la forma (similar a scipy.ndimage.rotate(..., reshape=True)).

Si hago un bucle manual sobre las matrices polares para calcular las coordenadas cartesianas, el resultado contiene regiones vacías que idealmente también deberían llenarse:

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')

Intento de ejemplo

¿Hay alguna manera de lograr la transformación evitando regiones vacías en la matriz de datos resultante?

un invitado
fuente

Respuestas:

2

tl; dr: No, no sin cambiar algunas condiciones de su problema.

El artefacto que estás viendo es una propiedad de la transformación. No se debe a la resolución fija en ángulo para todos los radios. Por lo tanto, no se debe a una implementación incorrecta o incorrecta de la transformación. La cuadrícula cartesiana simplemente implica una resolución especial más alta en estas áreas ya que hay puntos resueltos del mapa polar.

  • La única forma "limpia" (que se me ocurre en este momento) de manejar esto es tener una resolución ajustable en las coordenadas polares para tener en cuenta la escala 1 / r. (Si ingresa datos lo permite)

  • Una forma un tanto engañosa de visualizar esto sin los huecos sería distribuirlos aleatoriamente sobre los huecos. El argumento aquí es que no tienes la resolución para decidir en qué contenedor iban a comenzar. Por lo tanto, podría arrojarlos aleatoriamente en uno que podría haber sido un posible origen y no arrojarlos todos en el mismo (como lo está haciendo en este momento). Sin embargo, me gustaría desalentar esta fortaleza. Simplemente te da una trama más bonita. Tenga en cuenta que esto es algo equivalente al comportamiento del diagrama superior derecho en su pregunta.

465b
fuente
De hecho, el problema es disminuir la resolución espacial con un radio creciente ya que la resolución angular es fija. Acabo de probar un enfoque en el que los datos angulares se interpolan para cada radio con densidad proporcional 1/rantes de que se calcule la transformación a coordenadas cartesianas. Los resultados parecen prometedores, solo y = 0quedan algunos artefactos , así que todavía lo estoy investigando.
a_guest
1

Esto realmente no da el resultado esperado, pero tal vez lo ayudará a lograr una solución después de algunas correcciones necesarias ...


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')

ingrese la descripción de la imagen aquí

EDITAR: Modificado utilizando np.arctan2según las sugerencias de OP.

dzang
fuente
Para obtener la dependencia angular correcta se np.arctan2debe utilizar, pero en cualquier caso esto introduce grandes discrepancias hacia los bordes del sistema de coordenadas cartesianas. En realidad, no hay puntos de datos, pero dado que este enfoque solo considera el punto de datos disponible más cercano, se llena mientras no debería.
a_guest
@a_guest, de hecho, solo considera el valor más cercano. Básicamente está haciendo una interpolación de vecino más cercano. Si necesita una interpolación más avanzada, supongo que se vuelve mucho más complicado, ya que la interpolación debe hacerse en el espacio radial. Tal vez sería una posibilidad usar la skimage.transform.resizemuestra polar de la imagen polar por un factor dado y usar una interpolación bilineal o bicúbica y luego usar este enfoque para hacer la transformación. Terminarías con una transformación más precisa.
Dzang
¿@a_guest limitando el radio a 1 podría resolver los problemas de las fronteras?
Dzang
0

Podría recorrer la matriz cartesiana, transformando cada punto de la cuadrícula en coordenadas polares y aproximando el valor de la función mediante la interpolación de los datos de la cuadrícula polar. Sin embargo, es posible que desee dejar en blanco las regiones de la esquina, por falta de datos lo suficientemente cercanos.

No creo que haya una mejor manera, a menos que, por supuesto, tenga acceso a la función original.

Arne
fuente
Si te entiendo correctamente, estos puntos de cuadrícula interpolados se colocarán "entre" los puntos de cuadrícula actuales. Por lo tanto, es indecidible de qué punto de cuadrícula provienen. ¿O te he entendido mal?
465b
Sí, cuando transforma uno de los puntos de la cuadrícula cartesiana en coordenadas polares, en general estará en algún lugar entre cuatro de los puntos de la cuadrícula polar. Entonces le asigna un valor de función tomando un promedio de los valores de función de esos cuatro puntos de la cuadrícula, ponderados de acuerdo con la distancia. A eso me refería con interpolación.
Arne
Ah bien. Pero esto solo hace que los puntos individuales sean "más grandes", ya que los distribuye en cuatro puntos, lo que ayuda a valores bajos de r solamente. Esto todavía dará como resultado un patrón en forma de estrella para valores más grandes de r
465b
No, no diría eso. Con el método descrito anteriormente, puede calcular una estimación distinta del valor de la función para cada punto de la cuadrícula cartesiana.
Arne