Skip to content

Marker sizes in Axes3D scatter plot are changing all the time #19787

Closed

Description

@xlucn

Bug report

Bug summary

The marker sizes that specified with s= argument in scatter function are wrong, and even worse, the markers are changing their sizes every time the plot is re-rendered (panning or resizing). It seems that the sizes are randomly reassigned to these markers.

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()

# matplotlib 3.4
ax = Axes3D(fig, auto_add_to_figure=False)
fig.add_axes(ax)
# matplotlib 3.3.4
# Axes3D(fig)

x = np.random.rand(200)
y = np.random.rand(200)
z = np.random.rand(200)
ax.scatter(x, y, z, s=x*50)

plt.show()

Actual outcome

matplotlib_axes3d_marker_size_issue.mp4

Expected outcome

As shown in the screen recording, the sizes are correct and not changing. matplotlib was 3.3.4 in the following example.

matplotlib_axes3d_marker_size_expected.mp4

Matplotlib version

  • Operating system: Arch Linux
  • Matplotlib version (import matplotlib; print(matplotlib.__version__)): 3.4.0
  • Matplotlib backend (print(matplotlib.get_backend())): Qt5Agg
  • Python version: 3.9.2
  • Jupyter version (if applicable): Not using it
  • Other libraries: numpy 1.20.1

I installed both python, numpy and matplotlib with pacman package manager from Arch's official repository.

Activity

  1. jklymak commented on Mar 27, 2021

    @jklymak
    Member

    This bisects to e6d9cbb (#18189) Ping @tacaswell.

  2. added this to the v3.4.1 milestone on Mar 27, 2021
  3. tacaswell commented on Mar 28, 2021

    @tacaswell
    Member

    Well, that is quite bad.

    Thank you for the bisect @jklymak Looking at this now.

  4. tacaswell commented on Mar 28, 2021

    @tacaswell
    Member

    The issue is that when we re-compute the 3D projection we resort the values based on their depth from the viewer (so markers "in the back" do not render "in the front"). We have a bunch of logic to make sure that the colors also track, but we need the same logic to be added to the size.

    if you add color to this example you see that they keep their colors even if their sizes jump around.

    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    
    fig = plt.figure()
    
    # matplotlib 3.4
    ax = Axes3D(fig, auto_add_to_figure=False)
    fig.add_axes(ax)
    # matplotlib 3.3.4
    # Axes3D(fig)
    
    x = np.random.rand(200)
    y = np.random.rand(200)
    z = np.random.rand(200)
    ax.scatter(x, y, z, s=x*50, c=x**2)
    
    plt.show()
  5. added
    Release criticalFor bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions.
    on Mar 28, 2021
  6. tacaswell commented on Mar 28, 2021

    @tacaswell
    Member

    Attn @QuLogic This appears to be super broken.

    I have been testing with:

    th = np.linspace(0, 2*np.pi*6, 2000)
    
    x = np.sin(th)
    y = np.cos(th)
    z = th
    sc = ax.scatter(x, y, z, s=(5 + th), c=th**2)

    which has both a color and size structure I can predict what should be.

  7. tacaswell commented on Mar 28, 2021

    @tacaswell
    Member

    The color mapping was broken by 4c3d644 via #18480

    There are enough coupled changes here (both to the mplot3d code and the colors), I do not think this is something we are going to be able to revert our way out of.

  8. tacaswell commented on Mar 28, 2021

    @tacaswell
    Member
    import numpy as np
    from mpl_toolkits.mplot3d import Axes3D
    import matplotlib.pyplot as plt
    
    fig = plt.figure()
    
    
    
    try:
        # matplotlib 3.4
        ax = Axes3D(fig, auto_add_to_figure=False)
        fig.add_axes(ax)
    except AttributeError:
        # matplotlib 3.3.4
        ax = Axes3D(fig)
        if ax not in fig.axes:
            fig.add_axes(ax)
    
    th = np.linspace(0, 2*np.pi*6, 2000)
    
    x = np.sin(th)
    y = np.cos(th)
    z = th
    sc = ax.scatter(x, y, z, s=(5 + th), c=th**2)
    fig.savefig('/tmp/a.png')
    fig.savefig('/tmp/b.png')
    plt.show()

    OK, figured out why this passed tests (at least as far as the size goes, the first render is right!):

    a

    b

    It also looks like all of our tests with 3D scatter than do not have fixed color are using the figure comparison method so they are wrong together and we missed the color regression 😞 .

  9. tacaswell commented on Mar 29, 2021

    @tacaswell
    Member

    v3.3.4

    a

    #19812

    a

  10. tacaswell commented on Mar 29, 2021

    @tacaswell
    Member
    import numpy as np
    from mpl_toolkits.mplot3d import Axes3D
    import matplotlib.pyplot as plt
    import matplotlib as mpl
    
    fig = plt.figure()
    
    
    try:
        # matplotlib 3.4
        ax = Axes3D(fig, auto_add_to_figure=False)
        fig.add_axes(ax)
    except AttributeError:
        # matplotlib 3.3.4
        ax = Axes3D(fig)
        if ax not in fig.axes:
            fig.add_axes(ax)
    
    th = np.linspace(0, 2 * np.pi * 6, 2000)
    
    x = np.sin(th)
    y = np.cos(th)
    z = th
    sc = ax.scatter(x, y, z, s=(1 + th * 5), c=th ** 2)
    fig.suptitle(mpl.__version__)
    fig.savefig("/tmp/a.png", bbox_inches="tight")
    fig.savefig("/tmp/b.png")
    fig.savefig("/tmp/c.png")
    plt.show()
  11. added a commit that references this issue on Mar 31, 2021
    f888285
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions