The Wayback Machine - https://web.archive.org/web/20240110183412/https://github.com/matplotlib/matplotlib/issues/26286
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: White voids near boundaries of polar plot relating to figure size and saving dpi #26286

Closed
alisheikholeslam opened this issue Jul 11, 2023 · 10 comments

Comments

@alisheikholeslam
Copy link

alisheikholeslam commented Jul 11, 2023

Bug summary

I have a polar plot but it have some white areas near the circle boundary in just some sides of the plot. At first, I thought it needs some interpolations and tried interpolating based on some available methods e.g. 1 and 2. But not the good results. Interpolating using SciPy griddata with linear method solve the main issue but produce some shadows on the plot, and the cubic method result some inappropriate colors (which shown the results incorrect). Finally, I figure out that this issue is related to figure size that I specified and the dpi that I use. with low dpi it was cured a lot but low quality png. when I deactivate the related line for specifying figure size (plt.rcParams["figure.figsize"] = (19.2, 9.6)), it is shown correctly. How to pass the issue?

I will be appreciated if any answer about these questions too:

  1. why it happens
  2. how to solve it
  3. why it happens just in some sides of the plot?
  4. Do we need interpolating on such data?? If so, which algorithms will the best for that which does not show the results incorrectly as cubic method in scipy interpolation and without shadowing? if choosing between algorithms is based on the case, how to decide for that? It will be very helpful if be explained with examples.
  5. This issue makes me doubt that the data is correctly shown on the circle for analysis. Is it ok?

Code for reproduction

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("way1.png", dpi=save_dpi)

Actual outcome

Problem1
interpolate
without1
11

Expected outcome

way2

Additional information

Stack Overflow reposted link due to being unanswered here

Operating system

Windows 10

Matplotlib Version

3.5.3, 3.7.1, 3.7.2

Matplotlib Backend

No response

Python version

3.8, 3.10

Jupyter version

No response

Installation

conda

@alisheikholeslam
Copy link
Author

Because of no answering in the issues, I post it in stack overflow, too, as a bounty question, which didn’t get any answer, too. I would be very grateful if the developers or the experts of this library who know any solution or … would guide me and answer in one of these two links. I am pinging based on contribution in similar posts, @ianthomas23 , @jklymak , @timhoffm , @dstansby
Please accept my apologies for any inconvenience caused due to my inexperience in GitHub issues.

@jklymak
Copy link
Member

jklymak commented Jul 22, 2023

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. It's really hard to imagine doing much more for this, and your approaches of interpolating the data seem fine.

@QuLogic
Copy link
Member

QuLogic commented Jul 24, 2023

Now that contouring is in a separate repo in contourpy, @ianthomas23 may be able to provide more projection-specific contouring?

@alisheikholeslam
Copy link
Author

Now that contouring is in a separate repo in contourpy, @ianthomas23 may be able to provide more projection-specific contouring?

I have mentioned him in my last comment. I produce more points among the arrays and interpolate with method linear using RBF SciPy, It seems this way can be helpful in this regard, which result is smoother than linear method used in griddata SciPy (way 2). I will recheck my work, hope others could get a better solution.

@ianthomas23
Copy link
Member

@alisheikholeslam Both contour and tricontour produce lines and/or polygons that are piecewise linear, so sequences of (x, y) points that are connected with straight lines. Here you are contouring in polar space, the points are transformed to cartesian (i.e. screen) space and they are connected with straight lines. A line at constant radius, like all lines, is drawn straight but you would like it to be drawn as a circular segment. The more points you have, the shorter the lines are and the closer this looks to a circular segment.

If this bothered me I wouldn't draw the outer black circle, or I would draw it wider so no gaps are visibie.

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. Currently all such lines are drawn straight, with the exception of polar bar charts (there might be more exceptions, I haven't checked).

It would be possible, in general, to have a path transform function to convert straight-lines-in-polar-coordinates to curved-lines-in-cartesian-coordinates be approximating the curves using quadratic bezier curves, which would almost but not quite double the length of the points buffer. It would also need to deal with paths that are already bezier curves of course. The work required for this is (1) the maths, (2) the implementation, and (3) the API. I would expect that cartopy maintainers would have already done something along these lines (pun intended) as they deal with much more complicated transforms that just cartesian and polar.

@timhoffm
Copy link
Member

@ianthomas23 is there a configuration setting to increase the polygon point density? Going up a factor of 2-3 would likely be a practical workaround to fix the present case.

@ianthomas23
Copy link
Member

@ianthomas23 is there a configuration setting to increase the polygon point density? Going up a factor of 2-3 would likely be a practical workaround to fix the present case.

No there isn't.

@jklymak
Copy link
Member

jklymak commented Jul 25, 2023

Contouring is always an approximation. You will need to come up with a practical solution to this problem, rather than expect the algorithm to change.

In the above, if I do ax.set_ylim(0, 89) the gaps disappear. If you really want the ring to go to exactly 90, then fill in a dummy row of data at deviation=100 and do ax.set_ylim(0, 90).

@alisheikholeslam
Copy link
Author

@jklymak , I think this solution or something like thickening (or using thicker) the boundary are not good solutions and depending on the input data; I saw several examples that not-filled area is not small, unlike the example in this post, and using this solution for curing will miss a big area. @ianthomas23 thanks for the explanation and the possible solution. I am not very familiar with cartopy library, but will try to communicate with its experts if have problem in my future plots. As I said earlier, as a workaround, I tried to produce some data and interpolation, which solves the white voids issue near the boundaries and produce almost acceptable results in the SO link. By the way, I am seeking for any better solution than mine and not sure about closing this issue and leave it to you. Thank you all for participating in this issue.

@dstansby
Copy link
Member

I think for the explanations given in comments above it's worth closing this as expected behaviour that we can't fix. Thanks for opening the issue though, and sorry there isn't a fix we can implement for it.

@dstansby dstansby closed this as not planned Won't fix, can't repro, duplicate, stale Dec 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants