[Bug]: Modifying NumPy array after passing to set_xticks() unexpectedly alters plot ticks · Issue #32313 · matplotlib/matplotlib · GitHub
Skip to content

[Bug]: Modifying NumPy array after passing to set_xticks() unexpectedly alters plot ticks #32313

Open

Description

@williamlus

Bug summary

When passing a NumPy array to ax.set_xticks(), Matplotlib retains a reference to the array instead of creating a copy. Any in-place modifications made to the array after calling set_xticks() directly mutate the plot's tick locations. Passing a standard Python list does not exhibit this issue, suggesting Matplotlib should create an explicit copy of array input internally.

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt

attributes = ['Speed', 'Reliability', 'Comfort', 'Safety', 'Efficiency']
fig = plt.figure()
ax1 = fig.add_subplot(2, 1, 1, projection='polar')
theta = np.linspace(0, 2*np.pi, 5, endpoint=False)
# theta = np.linspace(0, 2*np.pi, 5, endpoint=False).tolist() # this works
ax1.set_xticks(theta)
ax1.set_xticklabels(attributes)
for i in range(5): theta[i] += np.pi * 2

Actual outcome

Image

Expected outcome

Image

Additional information

No response

Operating system

No response

Matplotlib Version

0.2.0.dev55193+unknown.g2153774ae

Matplotlib Backend

No response

Python version

No response

Jupyter version

No response

Installation

None

Activity

  1. timhoffm commented on Sep 7, 2026

    @timhoffm
    Member

    @williamlus are these actual production bugs you are stumbling over or are you running tools that inverstigate theoretical error paths.

    On the array-modification topic: I'm unclear whether we have a general guarantee that we isolate from passed parameters. Sometimes we do explicitly, but this is really a can of worms. Effectively, one would have to push copying down to https://github.com/matplotlib/matplotlib/blob/v3.11.1/lib/matplotlib/axis.py#L2309. But there unit conversion may or may not produce a new array. While we could change that to always make a copy, the result is passed in FixedLocator. But FixedLocator can also be used as public API directly, so that it itself would need to do a copy to defend against post-hoc modification. This means we need to do multiple unnecessary copies.

    Overall, I would say, that the behavior is explicitly not defined. You should not use modify ticks through this mechanism, but we also don't guarantee that objects are decoupled.

  2. williamlus commented on Sep 8, 2026

    @williamlus
    Author

    Sorry for bothering you with this! To be completely honest, I started out working in production, but later found software testing and bug hunting really fascinating, so I built a tool to help discover potential edge cases like this one.

    I shared it because I found the behavior quite interesting—modifying the array after passing it to the first subplot implicitly alters the tick locations for both subplots. Here is the complete minimal code snippet to demonstrate the behavior. In this case you still need to manually make a copy of the theta array for the second plot (for example, theta = theta + np.pi * 2) before modifying it.

    import numpy as np
    import matplotlib.pyplot as plt
    
    attributes = ['Speed', 'Reliability', 'Comfort', 'Safety', 'Efficiency']
    theta = np.linspace(0, 2*np.pi, len(attributes), endpoint=False)
    fig = plt.figure(figsize=(8, 6))
    
    ax1 = fig.add_subplot(2, 1, 1, projection='polar')
    ax1.set_xticks(theta)
    ax1.set_xticklabels(attributes)
    
    theta += np.pi * 2
    
    ax2 = fig.add_subplot(2, 1, 2, projection='polar')
    ax2.set_thetamin(360)
    ax2.set_thetamax(720)
    ax2.set_xticks(theta)
    ax2.set_xticklabels(attributes)
    
    plt.show()
    Image
  3. Rudra-G-23 commented on Sep 19, 2026

    @Rudra-G-23

    Hi, I’m interested in investigating this issue. I read the discussion here and the closed #32367, and my understanding is that simply copying inside FixedLocator is not sufficient because the broader question is whether Matplotlib should guarantee isolation from mutations of caller-provided arrays.

    Before implementing anything, would you prefer this behavior to remain undefined, or is there an API boundary where you would consider copying the input appropriate? If a copy/isolation guarantee is desired, I’d be happy to trace the set_ticks/unit-conversion/FixedLocator paths and add tests for the agreed behavior.

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