FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

[Bug]: Scatter Plot Returns Different Plots in Different Versions · Issue #21482 · matplotlib/matplotlib · GitHub

Repository navigation

[Bug]: Scatter Plot Returns Different Plots in Different Versions #21482

Closed

Description

Bug summary

I'm working on a generative art generator library for python called Samila based on the matplotlib scatter plot. It gets two functions and maps a square space into a arbitrary shape. We want the generated shape to be the same for given functions and given random seed in order to be reproducible.

Recently we were working on functions with complex values and notified that scatter plot output is not the same in different versions on matplotlib.

I wanted to know why is it like this and what's the problem with matplotlib. If this is a bug it could be horrible for matplotlib to plot different figures for a specific code in its different versions.

Code for reproduction

import random
import math
import matplotlib.pyplot as plt
import itertools

def f1(x,y):
    return math.cos(x**2 * y)**1.926 - math.floor(x - y)**1.861 - math.floor(y**2 * x)**1.688
def f2(x,y):
    return x - y**1.617 - math.ceil(y)**1.477 - abs(x**2 * y) ** 1.647 - math.cos(x * y)**1.668
def float_range(start, stop, step):
    while start < stop:
        yield float(start)
        start += step


data1 = []
data2 = []
range1 = list(float_range(-1*math.pi, math.pi, 0.01))
range_prod = list(itertools.product(range1, range1))
for item in range_prod:
    data1.append(f1(item[0], item[1]))
    data2.append(f2(item[0], item[1]))

color = (0.159, 0.085, 0.191)
spot_size = 0.01
projection = "polar"

fig = plt.figure()
fig.set_size_inches(10, 10)
ax = fig.add_subplot(111, projection=projection)
ax.scatter(
        data2,
        data1,
        alpha=0.1,
        edgecolors=color,
        s=spot_size)
ax.set_axis_off()
ax.patch.set_zorder(-1)
ax.add_artist(ax.patch)

plt.show()

Actual outcome

in matplotlib.__version__ == 3.0.3:

in matplotlib.__version__ == 3.4.3:

Expected outcome

Same result in different versions.

Operating system

Ubuntu 20.04

Matplotlib Version

3.0.3 and 3.4.3

Python version

3.8.10



[You can track this bug in the stackoverflow too]

Activity

  1. jklymak commented on Oct 28, 2021

    Member

    What you have left out is that both versions return:

    ComplexWarning: Casting complex values to real discards the imaginary part
      offsets = np.asanyarray(offsets, float)
    

    Please cast data1 and data2 to float as you see fit - scatter cannot handle complex values, and passing them is undefined. Clearly some details of where in the plotting chain the bad values are dealt with has changed, but I don't feel it is worth chasing down for poorly formed inputs.

  2. mwaskom commented on Oct 28, 2021

    Observation: I can get both versions of your plot (more or less) out of the same version of matplotlib by rewriting the math using numpy (which is both clearer and more performant):

    import math
    import itertools
    
    def f1(x,y):
        return math.cos(x**2 * y)**1.926 - math.floor(x - y)**1.861 - math.floor(y**2 * x)**1.688
    def f2(x,y):
        return x - y**1.617 - math.ceil(y)**1.477 - abs(x**2 * y) ** 1.647 - math.cos(x * y)**1.668
    def float_range(start, stop, step):
        while start < stop:
            yield float(start)
            start += step
    
    
    data1 = []
    data2 = []
    range1 = list(float_range(-1*math.pi, math.pi, 0.01))
    range_prod = list(itertools.product(range1, range1))
    for item in range_prod:
        data1.append(f1(item[0], item[1]))
        data2.append(f2(item[0], item[1]))
    
    f, ax = plt.subplots(figsize=(3, 3), subplot_kw=dict(projection="polar"))
    ax.scatter(data2, data1, s=.25)
    ax.set_axis_off()

    import numpy as np
    
    def f1(x,y):
        return np.cos(x ** 2 * y) ** 1.926 - np.floor(x - y) ** 1.861 - np.floor(y ** 2 * x) ** 1.688
    def f2(x,y):
        return x - y ** 1.617 - np.ceil(y) ** 1.477 - np.abs(x ** 2 * y) ** 1.647 - np.cos(x * y) ** 1.668
    
    xx = np.arange(-np.pi, np.pi + .01, .01)
    
    data1 = f1(xx, xx)
    data2 = f2(xx, xx)
    
    f, ax = plt.subplots(figsize=(3, 3), subplot_kw=dict(projection="polar"))
    ax.scatter(data2, data1, s=.25)
    ax.set_axis_off()

    Your data-generating functions have a bunch of numerical issues (which numpy warns about but math silently ignores). I doubt this has anything to do with a change in the drawing logic of matplotlib per se, but maybe a change in the way that invalid/complex pure-python (i.e. not numpy) dytpes are handled?

  3. sadrasabouri commented on Oct 28, 2021

    Author

    What you have left out is that both versions return:

    ComplexWarning: Casting complex values to real discards the imaginary part
      offsets = np.asanyarray(offsets, float)
    

    Please cast data1 and data2 to float as you see fit - scatter cannot handle complex values, and passing them is undefined. Clearly some details of where in the plotting chain the bad values are dealt with has changed, but I don't feel it is worth chasing down for poorly formed inputs.

    I don't think that's the issue. I try casting the data before plotting by np.real and float like bellow:

    data1 = list(map(np.real, data1))
    data1 = list(map(float, data1))
    data2 = list(map(np.real, data2))
    data2 = list(map(float, data2))
    

    unfortunately no difference.

  4. jklymak commented on Oct 28, 2021

    Member

    @sadrasabouri please indicate if the current version of Matplotlib has a bug, preferably with a minimal example that demonstrates the issue, and explicitly says what you expect is correct result.

    I'm also not clear why you are double casting above.

  5. sadrasabouri commented on Oct 28, 2021

    Author

    ... with a minimal example that ...

    Minimal Example Saved Me 😄

    Matplotlib changes its plotting strategy from 3.0.3 which ignores points with negative radius to 3.4.3 in which they're plotted.

    I couldn't find this using compare release notes and it was so confusing for me. Hope there will be an warning for this situation avoiding future issues. (I can work on this if you think it's a bug)

    data1 = [-2, -5,  2, 2]
    data2 = [-2, 2, -2, 2]
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection="polar")
    ax.scatter(
            data2,
            data1,
            s=30)
    
    plt.show()
    

    in matplotlib.__version__ == 3.0.3 we got:

    while in matplotlib.__version__ == 3.4.3:

  6. jklymak commented on Oct 28, 2021

    Member

    Ah OK, that makes sense. Thanks for digging up the minimal example!

    This project predates GitHub, let alone release notes, so you will have to read the documentation which have API changes. I'm not 100% sure when this came in.

  7. QuLogic commented on Oct 29, 2021

    Member

    That was #4699, added in 2.1.0.

  8. jklymak commented on Oct 29, 2021

    Member

    @QuLogic right, but think something must have happened with the axes limits as well. Probably #13980.

    I think the current behaviour is desired, and we have explained the difference in versions, so lets close this. @sadrasabouri if you need deterministic behaviour between versions, I think setting the r-limits explicitly is your best bet. Thanks....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL