英文:
Not filled, white voids near boundaries of polar plot
问题
我尝试使用matplotlib的contourf函数创建一个极坐标图(polar plot),但在图形边界附近产生了一些未填充的区域,仅在图的某些部分出现。似乎这个问题是一个常见的问题,可以在许多示例中看到,例如1。
起初,我认为可能需要一些插值,尝试了一些可用的方法,例如2。但是我无法生成一个完美的图。使用SciPy griddata函数进行线性插值解决了主要问题,但在图上产生了一些阴影,并且使用三次插值方法会导致一些不适当的颜色(显示结果不正确)。
最后,我猜想这个问题可能与我指定的图形大小和dpi有关。低dpi时,问题得到了很大的改善,但会得到低质量的PNG图像。当我取消关于指定图形大小的相关行(# plt.rcParams["figure.figsize"] = (19.2, 9.6)
)并使用dpi=600
时,图像显示相当正确,但不在所需的图形大小上。
主要问题是如何解决保存文件时的问题,以及所需指定的图形大小和dpi?必须指出,这个问题出现在保存的文件上。
除了解决问题的答案之外,如果有关于以下问题的任何答案,我将不胜感激:
-
为什么会发生这种情况?
-
为什么它只在图的某些侧面出现?在这个示例中,只在图的右上角有问题,而不是顶部。这个问题让我怀疑数据是否正确显示在圆上以进行分析。这样做可以吗?
-
我们是否需要对这样的数据进行插值?如果需要,哪种算法最适合不像Scipy插值中的三次方法那样不正确显示结果,也不会产生阴影,就像线性方法一样?如果在算法之间进行选择是基于案例的,如何决定?如果可以用示例来解释将非常有帮助。
import numpy as np
from matplotlib import cm
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (19.2, 9.6)
save_dpi = 600
Azimuth = np.tile(np.arange(0, 91, 10), 10)
Deviation = np.repeat(np.arange(0, 91, 10), 10)
color_data = np.array([2123, 2124, 2126, 2130, 2135, 2139, 2144, 2147, 2150, 2151, 2212,
2211, 2205, 2197, 2187, 2176, 2166, 2158, 2152, 2150, 2478, 2468,
2439, 2395, 2342, 2285, 2231, 2188, 2160, 2150, 2912, 2888, 2819,
2715, 2589, 2456, 2334, 2236, 2172, 2150, 3493, 3449, 3324, 3135,
2908, 2674, 2462, 2294, 2187, 2150, 4020, 4020, 3912, 3618, 3270,
2917, 2602, 2357, 2203, 2151, 4020, 4020, 4020, 4020, 3633, 3156,
2737, 2417, 2218, 2150, 4020, 4020, 4020, 4020, 3947, 3358, 2850,
2466, 2230, 2150, 4020, 4020, 4020, 4020, 4020, 3495, 2926, 2499,
2238, 2150, 4020, 4020, 4020, 4020, 4020, 3543, 2951, 2510, 2241,
2150])
ax = plt.subplot(projection='polar')
plt.xticks([])
plt.yticks([])
Az = np.unique(Azimuth)
Dev = np.unique(Deviation)
mAz, mDev = np.meshgrid(Az, Dev)
# way1: 原始方法
Xi, Yi, Zi = np.deg2rad(mAz), mDev, color_data.reshape(mAz.shape)
contour_plot = ax.contourf(Xi, Yi, Zi, levels=256, cmap=cm.viridis_r, zorder=1)
ax.plot()
plt.savefig("way1.png", dpi=save_dpi)
# way2: 插值方法
# import scipy.interpolate as sci_int
# Xi = np.linspace(0, 2 * np.pi, 256, endpoint=True)
# Yi = np.linspace(0, 90, 256, endpoint=True)
# Zi = sci_int.griddata(np.stack((np.deg2rad(mAz), mDev), axis=2).reshape(len(Azimuth), 2), color_data,
# (Xi[None, :], Yi[:, None]), method='linear')
# contour_plot = ax.contourf(Xi, Yi, Zi, levels=256, cmap=cm.viridis_r, zorder=1)
# ax.plot()
# plt.savefig("way2.png", dpi=save_dpi)
在Windows 10上测试:
**Python版本:**3.8和3.10
**Matplotlib版本:**3.5.3和3.7.2
英文:
I have tried to create a polar plot using matplotlib's contourf
, but it produces some not-filled areas near the circle boundary, in just some sides of the plot. It seems, this problem is a common problem that we can see in many examples e.g. 1.
At first, I thought it may needs some interpolations and tried interpolating based on some available methods e.g. 2. But I couldn't produce a perfect plot. Interpolating using SciPy griddata with linear method solved the main issue but produce some shadows on the plot, and the cubic method result in some inappropriate colors (which shown the results incorrect).
Finally, I guess this issue may be related to figure size that I specified and the dpi that I used. With low dpi it was cured a lot, but will get a low quality png. when I deactivate the related line for specifying figure size (# plt.rcParams["figure.figsize"] = (19.2, 9.6)
) with dpi=600
, it is shown fairly correct, but not on the needed figure size.
The main question is how to solve the issue for saved files, with the desired specified figure size and dpi? It must be said that the problem is appearing on the saved files.
Besides the answer to solve the issue, I will be appreciated if any answer about these questions too:
-
Why it happens?
-
Why it happens just in some sides of the plot? In this example it is problematic just on the right side of the quarter, not the upside. This issue makes me doubt that the data is correctly shown on the circle for analysis. Is it OK?
-
Do we need interpolating on such data? If so, which algorithms will be the best for that which does not show the results incorrectly as cubic method in Scipy interpolation and without shadowing as the linear method? If choosing between algorithms is based on the case, how to decide for that? It will be very helpful if be explained with examples.
import numpy as np
from matplotlib import cm
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (19.2, 9.6)
save_dpi = 600
Azimuth = np.tile(np.arange(0, 91, 10), 10)
Deviation = np.repeat(np.arange(0, 91, 10), 10)
color_data = np.array([2123, 2124, 2126, 2130, 2135, 2139, 2144, 2147, 2150, 2151, 2212,
2211, 2205, 2197, 2187, 2176, 2166, 2158, 2152, 2150, 2478, 2468,
2439, 2395, 2342, 2285, 2231, 2188, 2160, 2150, 2912, 2888, 2819,
2715, 2589, 2456, 2334, 2236, 2172, 2150, 3493, 3449, 3324, 3135,
2908, 2674, 2462, 2294, 2187, 2150, 4020, 4020, 3912, 3618, 3270,
2917, 2602, 2357, 2203, 2151, 4020, 4020, 4020, 4020, 3633, 3156,
2737, 2417, 2218, 2150, 4020, 4020, 4020, 4020, 3947, 3358, 2850,
2466, 2230, 2150, 4020, 4020, 4020, 4020, 4020, 3495, 2926, 2499,
2238, 2150, 4020, 4020, 4020, 4020, 4020, 3543, 2951, 2510, 2241,
2150])
ax = plt.subplot(projection='polar')
plt.xticks([])
plt.yticks([])
Az = np.unique(Azimuth)
Dev = np.unique(Deviation)
mAz, mDev = np.meshgrid(Az, Dev)
# way1: Original
Xi, Yi, Zi = np.deg2rad(mAz), mDev, color_data.reshape(mAz.shape)
contour_plot = ax.contourf(Xi, Yi, Zi, levels=256, cmap=cm.viridis_r, zorder=1)
ax.plot()
plt.savefig("way1.png", dpi=save_dpi)
# way2: Interpolation
# import scipy.interpolate as sci_int
# Xi = np.linspace(0, 2 * np.pi, 256, endpoint=True)
# Yi = np.linspace(0, 90, 256, endpoint=True)
# Zi = sci_int.griddata(np.stack((np.deg2rad(mAz), mDev), axis=2).reshape(len(Azimuth), 2), color_data,
# (Xi[None, :], Yi[:, None]), method='linear')
# contour_plot = ax.contourf(Xi, Yi, Zi, levels=256, cmap=cm.viridis_r, zorder=1)
# ax.plot()
# plt.savefig("way2.png", dpi=save_dpi)
Tested on windows 10 by:
Python ver.: 3.8 & 3.10
Matplotlib ver.: 3.5.3 & 3.7.2
答案1
得分: 1
在matplotlib存储库的相关讨论之后,似乎没有任何简单和常规的解决方案(也许cartopy已经准备了一些有用的东西); 等高线算法并不知道它是在极坐标图上操作,因此当在极坐标空间中绘制等高线时,多边形会被近似
> 实际上,这并不是一个等高线问题,而是一个关于一个坐标系中的直线是否应该转换为另一个坐标系中的直线或非直线的问题。它同样适用于在极坐标中指定的任何多边形(例如一个简单的三角形),在笛卡尔(屏幕)坐标中呈现。
为了解决这个问题的一个子解决方案,我尝试生成更多点(方位角和偏差)并插值它们对应的color_data(你拥有的点越多,线条越短,看起来越接近一个圆形段),以减少/覆盖这个缺陷。在这方面,对于这个例子,SciPy的径向基函数(RBF)插值用以下代码得到了一个可以接受的答案(可以为这类问题进行开发/调整):
from scipy.interpolate import RBFInterpolator
coordinates_org = np.column_stack((Azimuth, Deviation))
Az = np.linspace(0, 90, 181, endpoint=True)
Dev = np.linspace(0, 90, 181, endpoint=True)
Az_2D, Dev_2D = np.meshgrid(Az, Dev)
coordinates_int = np.column_stack((Az_2D.ravel(), Dev_2D.ravel()))
rbf = RBFInterpolator(coordinates_org, color_data, kernel="linear")
color_data_int = rbf(coordinates_int).reshape(len(Az), len(Dev))
contour_plot = ax.contourf(np.deg2rad(Az), Dev, color_data_int, levels=1000, cmap=cm.viridis_r)
ax.plot()
plt.savefig("way3.png", dpi=save_dpi)
我对这个解决方案进行了一些调整,以适用于另一个例子,并通过一些修改来比较其结果与一些各种插值方法,如下所示。在这个比较中,使用griddata的圆上方可能会用不同于1000的其他级别进行填充,我记得它是1000。根据比较,这个解决方案(RBF)产生的结果比在问题中使用way 2的griddata要好;此外,quintic方法似乎效果最好。
英文:
After a related discussion in matplotlib repo, it seems there is not any simple and conventional solution for that (perhaps cartopy have prepared something helpful); The contouring algorithm doesn't know that it is acting on a polar plot, so when the contours are drawn in polar space the polygons are approximated.
> This isn't actually a contouring issue, it is an issue of whether a
> straight line in one coordinate system should be transformed to a
> straight or non-straight line in another coordinate system. It applies
> equally to any polygon (e.g. just a simple triangle) specified in, for
> example, polar coordinates, and rendered in cartesian (screen)
> coordinates.
Just for a sub-solution, I tried to produce more points (Azimuth & Deviation) and interpolate their corresponding color_data (the more points you have, the shorter the lines are and the closer this looks to a circular segment) to reduce/cover this shortcoming. In this regard, and for this example, Radial basis function (RBF) interpolation of SciPy get an acceptable answer with the following code (which could be developed/adjusted for such problems):
from scipy.interpolate import RBFInterpolator
coordinates_org = np.column_stack((Azimuth, Deviation))
Az = np.linspace(0, 90, 181, endpoint=True)
Dev = np.linspace(0, 90, 181, endpoint=True)
Az_2D, Dev_2D = np.meshgrid(Az, Dev)
coordinates_int = np.column_stack((Az_2D.ravel(), Dev_2D.ravel()))
rbf = RBFInterpolator(coordinates_org, color_data, kernel="linear")
color_data_int = rbf(coordinates_int).reshape(len(Az), len(Dev))
contour_plot = ax.contourf(np.deg2rad(Az), Dev, color_data_int, levels=1000, cmap=cm.viridis_r)
ax.plot()
plt.savefig("way3.png", dpi=save_dpi)
I adjust this solution for another example by some modifications to compare its results with some various interpolation methods, which can be seen below. In this comparison, unfilled area above the circles for griddata might be filled using other levels than used, which was 1000 as I remember. Based on the comparison, this solution (RBF) produces better results than using griddata as way 2 in the question; Also, quintic method seems got the best:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论