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]: Data 0 cannot be plotted by matplotlib.pyplot just because some data is less than 0. #21382

Open
JK-SHI opened this issue Oct 19, 2021 · 5 comments

Comments

@JK-SHI
Copy link

JK-SHI commented Oct 19, 2021

Bug summary

Data 0 cannot be plotted and the corresponding area in the the figure remains transparent, if some data is less than 0.

I tried to trace the problem and find that the reason seems to be a bug in ContourSet._get_lowers_and_uppers.(Line 1065 in contour.py(3.3.4))

    if self.zmin == lowers[0]:
        # Include minimum values in lowest interval
        lowers = lowers.copy()  # so we don't change self._levels
        if self.logscale:
            lowers[0] = 0.99 * self.zmin
        else:
            lowers[0] -= 1

while lowers[0] is the same as self.zmin, it will be reduced a little before using.
However, while lowers[0] is greater than self.zmin ( = -1.7E-13 ), it will not be reduced and remains as it is.
I think the condition should be revised to self.zmin <= lowers[0] from self.zmin == lowers[0].

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt

def main():
    z0 = np.array([[0., 0., 2.], [0., 0., 1.], [2., 1., 0.]])
    z1 = np.array([[0., 0., 2.], [0., 0., 1.], [2., 1., -1.7E-13]])

    fig = plt.figure(figsize=(2, 4))

    ax0 = fig.add_subplot(121)
    ax0.contourf(z0, cmap='jet')
    ax0.set_aspect('equal')

    ax1 = fig.add_subplot(122)
    ax1.contourf(z1, cmap='jet')
    ax1.set_aspect('equal')

    plt.show()

if __name__ == "__main__":
    main()

Actual outcome

test_contourf_jet4

the left-bottom area in the right figure is not plotted and remains transparent,
just because the data z[2,2] is changed from 0 to -1.7E-13.

Expected outcome

test_contourf_jet4r

The figure in the right site is expected to be the same as the left one.

Operating system

Windows 10

Matplotlib Version

3.3.4

Matplotlib Backend

module://ipykernel.pylab.backend_inline

Python version

3.8.8

Jupyter version

6.0.1

Other libraries

No response

Installation

conda

Conda channel

No response

@JK-SHI JK-SHI mentioned this issue Oct 20, 2021
7 tasks
@jklymak
Copy link
Member

jklymak commented Oct 21, 2021

The contouring algorithm automatically chooses levels based on the logic in tickers.MaxNLocator. This algorithm returns the smallest level as 0 in this case because your -1.7e-13 is not different from zero given the range 0-2

If you want the contour to not be cut off, then that is what the extend kwarg is for:

    ax1.contourf(z1, cmap='jet', extend='both')

or, simply specify the levels manually.

    ax1.contourf(z1, levels=np.linspace(np.min(z1), np.max(z1), 10), cmap='jet')

I'm going to close this as there are two workarounds and I think the algorithm is working as we expect. Thanks!

@jklymak jklymak closed this as completed Oct 21, 2021
@jklymak jklymak added topic: contour Community support Users in need of help. labels Oct 21, 2021
@JK-SHI
Copy link
Author

JK-SHI commented Oct 21, 2021

Thank you for the examination.
I understand that -1.7E-13 is not different from zero given the range 0-2 and is treated as zero, but the problem is that the data 0 is cut off, which is usually plotted given the range 0-2. Please note that data cut off in the left-bottom area is zero, not -1.7E-13 . I still think it is not natural/reasonable for that lower[0] is lowered for zmin==0, but not lowered for zmin<=0, which needs more space.

Both of the 2 methods proposed by Mr./Ms. Jody Klymak can work well. Thank you very much.
In fact, I added a check function and reset the data like -1.7E-13 to zero before calling contour to avoid this problem in my program several weeks ago.
It took time to identify the cause because the behavior of zero is strange while the reason is not zero but other data like -1.7E-13 .
Later I traced the problem and found the reason seems to be in _get_lowers_and_uppers, and confirmed the revision ("<=") can solve the problem.
If the behavior will not be improved, maybe I can use the methods proposed by Mr./Ms. Jody Klymak next time.
Anyway, Thank you very much!

@JK-SHI
Copy link
Author

JK-SHI commented Oct 21, 2021 via email

@anntzer
Copy link
Contributor

anntzer commented Oct 21, 2021

Actually, I think that we could handle this case better: MaxNLocator already returns sometimes one extra tick out of the limits (and the tick drawing code gets rid of it further downstream); I'd say here it could likewise see that -1.7e-13 is below the lowest tick, and choose to return an extra one below that.

@anntzer anntzer reopened this Oct 21, 2021
@anntzer anntzer removed the Community support Users in need of help. label Oct 21, 2021
@JK-SHI
Copy link
Author

JK-SHI commented Oct 24, 2021

Thank you for the opinion on this matter.
I traced the code around MaxNLocator.
MaxNLocator._raw_ticks method makes the difference between array z1 and array z0.
Maybe the lower limit ("low") can be decreased 1 to plot the data 0,
2067 low = edge.le(_vmin - best_vmin)
2068 high = edge.ge(_vmax - best_vmin)
2069 ticks = np.arange(low, high + 1) * step + best_vmin
but I cannot find a reasonable proposal to revise _Edge_integer.le() and _Edge_integer.closeto(),
and I think it is not a good idea to revise "low" forcibly here (even given some conditions)
because the orginal code _Edge_integer.le() and _Edge_integer.closeto() is coded to deal with this kind of matter and are working well as they are expected.
if condition(.......):
low -= 1
I hope you can work out a good idea to deal with this kind matter and make the lib more kindful.

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

3 participants