Sắp xếp lại dữ liệu trong mảng hai chiều theo sự chuyển đổi từ tọa độ cực sang Cartesian


8

Tôi có một mảng hai chiều đại diện cho các giá trị hàm tại các vị trí trong một hệ tọa độ cực. Ví dụ:

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)

Ở đây datađược sắp xếp trong một lưới hình chữ nhật tương ứng với tọa độ cực. Tôi muốn sắp xếp lại dữ liệu trong mảng sao cho các trục đại diện cho hệ tọa độ Cartesian tương ứng. Bố cục cũ so với mới có thể được hình dung như sau:

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)

Thí dụ

Ở đây các tọa độ được đưa ra rõ ràng và cốt truyện được điều chỉnh cho phù hợp. Tôi muốn dữ liệu được sắp xếp lại trong mảng dữ liệu thay thế. Nó nên chứa tất cả các giá trị, tùy ý điền vào các số 0 để phù hợp với hình dạng (tương tự scipy.ndimage.rotate(..., reshape=True)).

Nếu tôi lặp thủ công các mảng cực để tính toán tọa độ Descartes, kết quả sẽ chứa các vùng trống cũng lý tưởng nhất phải được điền vào:

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

Ví dụ thử

Có cách nào để đạt được sự chuyển đổi trong khi tránh các vùng trống trong mảng dữ liệu kết quả không?

Câu trả lời:


2

tl; dr: Không, không phải không thay đổi một số điều kiện của vấn đề của bạn.

Vật phẩm bạn đang thấy là một tài sản của sự biến đổi. Nó không phải là do độ phân giải cố định trong góc cho tất cả các bán kính. Do đó, nó không phải là do việc thực hiện chuyển đổi sai hay xấu. Lưới Cartesian chỉ đơn giản ngụ ý độ phân giải đặc biệt cao hơn tại các khu vực này vì có các điểm được giải quyết từ bản đồ cực.

  • Cách "sạch" duy nhất (mà tôi có thể nghĩ ra ngay bây giờ) để xử lý việc này là có độ phân giải có thể điều chỉnh trong tọa độ cực để tính tỷ lệ 1 / r. (Nếu bạn nhập dữ liệu cho phép nó)

  • Một cách gian lận để hình dung điều này mà không có khoảng trống sẽ phân phối chúng ngẫu nhiên qua các khoảng trống. Đối số ở đây là, bạn không có nghị quyết để quyết định họ sẽ bắt đầu với thùng nào. Vì vậy, bạn chỉ có thể ném ngẫu nhiên chúng vào một trong đó có thể là một nguồn gốc có thể và không ném tất cả chúng vào cùng một (như bạn đang làm ngay bây giờ). Tuy nhiên, tôi muốn ngăn cản sự cố chấp này. Nó chỉ cung cấp cho bạn một cốt truyện đẹp hơn. Lưu ý rằng điều này có phần tương đương với hành vi của âm mưu phía trên bên phải trong câu hỏi của bạn.


Thật vậy, vấn đề là giảm độ phân giải không gian với bán kính tăng do độ phân giải góc được cố định. Tôi vừa thử một cách tiếp cận trong đó dữ liệu góc được nội suy cho từng bán kính với mật độ tỷ lệ với 1/rtrước khi chuyển đổi sang tọa độ Descartes được tính toán. Kết quả có vẻ đầy hứa hẹn, chỉ còn một vài hiện vật xung quanh y = 0, vì vậy tôi vẫn đang xem xét nó.
a_guest

1

Điều này không thực sự mang lại kết quả như mong đợi, nhưng có thể sẽ giúp bạn đạt được giải pháp sau một số điều chỉnh cần thiết ...


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

nhập mô tả hình ảnh ở đây

EDIT: Được sửa đổi bằng cách sử dụng np.arctan2theo các đề xuất của OP.


Để có được sự phụ thuộc góc chính xác np.arctan2nên được sử dụng, nhưng trong mọi trường hợp, điều này đưa ra sự khác biệt lớn đối với các cạnh của hệ tọa độ Cartesian. Trong thực tế không có điểm dữ liệu nhưng vì cách tiếp cận này chỉ xem xét điểm dữ liệu có sẵn gần nhất mà nó được điền trong khi không nên.
a_guest

@a_guest thực sự nó chỉ xem xét giá trị gần nhất. Về cơ bản, nó đang thực hiện một phép nội suy lân cận gần nhất. Nếu bạn cần một phép nội suy nâng cao hơn, tôi đoán nó sẽ phức tạp hơn nhiều vì phép nội suy phải được thực hiện trong không gian xuyên tâm. Có lẽ nó sẽ là một khả năng sử dụng skimage.transform.resizeđể đảo lộn hình ảnh cực theo một yếu tố nhất định và sử dụng phép nội suy song tuyến tính và sau đó sử dụng phương pháp này để thực hiện phép biến đổi. Bạn sẽ kết thúc với một chuyển đổi chính xác hơn.
dzang

@a_guest giới hạn bán kính xuống 1 có thể giải quyết các vấn đề biên giới?
dzang

0

Bạn có thể lặp qua mảng Cartesian, biến đổi từng điểm lưới thành tọa độ cực và xấp xỉ giá trị hàm bằng cách nội suy từ dữ liệu lưới cực của bạn. Mặc dù vậy, bạn vẫn có thể muốn để trống các vùng góc, vì thiếu dữ liệu đủ gần.

Tôi không nghĩ có một cách tốt hơn, trừ khi tất nhiên bạn có quyền truy cập vào chức năng ban đầu.


Nếu tôi hiểu bạn một cách chính xác, các điểm lưới nội suy này sẽ là vị trí "giữa" các điểm lưới hiện tại. Do đó, không thể chắc chắn họ đến từ điểm lưới nào. Hay tôi đã hiểu lầm bạn?
465b

Có, khi bạn chuyển đổi một trong các điểm lưới Cartesian thành tọa độ cực, nhìn chung nó sẽ ở đâu đó ở giữa bốn điểm lưới cực. Vì vậy, bạn gán cho nó một giá trị hàm bằng cách lấy trung bình các giá trị hàm của bốn điểm lưới đó, được tính trọng số theo khoảng cách. Đó là những gì tôi có nghĩa là nội suy.
Arne


À, được rồi. Nhưng điều này chỉ làm cho các điểm riêng lẻ "lớn hơn" vì nó phân phối nó trên bốn điểm, chỉ giúp cho các giá trị thấp của r. Điều này vẫn sẽ dẫn đến một mô hình hình ngôi sao cho các giá trị lớn hơn của r
465b

Không, tôi sẽ không nói như vậy. Với phương pháp được nêu ở trên, bạn có thể tính toán một ước tính riêng biệt của giá trị hàm cho mỗi điểm lưới Cartesian duy nhất.
Arne
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.