Skip to content

[Bug]: PolyCollection set_offsets does not accept [[], []] like Line2D #22401

Open

Description

@ianhi

Bug summary

The return value of plot a Line2D lets you set_data as [[], []] this is nice because you can do both of

line = plt.plot([],[])[0]
line.set_data([[],[]])

allowing you to make a line disappear by setting it's data to empty. This comes up surprisingly often for me when using mpl-interactions to explore datasets

However, plt.scatter does not have the same symmetry of behavior. You can do

scatter = plt.scatter([[], [])

but you cannot then do

scatter.set_offsets([[],[]])

Code for reproduction

# works
line = plt.plot([],[])[0]

# works
line.set_data([[],[]])

# works
scatter = plt.scatter([],[])

# fails
scatter.set_offsets([[],[]])

Actual outcome

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Input In [76], in <module>
      1 scatter = plt.scatter([],[])
----> 2 scatter.set_offsets([[],[]])

File ~/mambaforge/envs/mpl-inter/lib/python3.9/site-packages/matplotlib/collections.py:566, in Collection.set_offsets(self, offsets)
    563 if offsets.shape == (2,):  # Broadcast (2,) -> (1, 2) but nothing else.
    564     offsets = offsets[None, :]
    565 self._offsets = np.column_stack(
--> 566     (np.asarray(self.convert_xunits(offsets[:, 0]), 'float'),
    567      np.asarray(self.convert_yunits(offsets[:, 1]), 'float')))
    568 self.stale = True

IndexError: index 0 is out of bounds for axis 1 with size 0

Expected outcome

No error and the scatter should not be drawn.

Additional information

No response

Operating system

No response

Matplotlib Version

3.5.1

Matplotlib Backend

any

Python version

3.9.9

Jupyter version

No response

Installation

pip

Activity

  1. changed the title [-][Bug]: PolyCollection `set_offsets` should accept `[[], []]` like Line2D[/-] [+][Bug]: PolyCollection `set_offsets` does not accept `[[], []]` like Line2D[/+] on Feb 5, 2022
  2. timhoffm commented on Feb 6, 2022

    @timhoffm
    Member

    allowing you to make a line disappear by setting it's data to empty.
    If you want to make a line disappear, you should use set_visible(False). But I agree, it's reasonable to allow an artist without data.

  3. jklymak commented on Mar 29, 2022

    @jklymak
    Member

    I guess I'm mildly against this - what is the use case to have no data, but keep the artist alive?

  4. ianhi commented on Mar 29, 2022

    @ianhi
    ContributorAuthor

    For me it's when controlling the artist with a slider. You are moving some parameter around and for some values you may not plot anything. I forget the actual use case by some user of mpl-interactions ran into this. In that context they just provide a function that generates data and I call set_offsets for them it would be a decent bit of extra logic to also manage set_visible just for the case of empty data - especially when it works fine for other artists

  5. timhoffm commented on Mar 29, 2022

    @timhoffm
    Member

    "Artist without content" is a reasonable if not necessary concept. It allows us to keep track of a data set, even if we don't have values for it right now.
    This is also relevant for legend consistency and color synchronization. See #21506 for a similar case.

  6. added this to the v3.6.0 milestone on Mar 29, 2022
  7. oscargus commented on Jun 4, 2022

    @oscargus
    Member

    I'm wondering if this is (slightly) related to #1735? If so, the proposed fix in #23200 may affect the current issue in a negative(?) way.

  8. modified the milestones: v3.6.0, v3.7.0 on Aug 24, 2022
  9. pe224 commented on Apr 15, 2024

    @pe224

    I encountered a similar issue and found a workaround by investigating what is returned by

    axes.scatter([], []).get_offsets()

    It is a masked (0, 2) array with all values masked, so it can be set via

    empty_offset = np.ma.masked_array([0, 0], mask=True)
    scatter.set_offsets(empty_offset)

    I strongly agree with @ianhi and @timhoffm, empty artists are a useful concept: I build up my "ordered stack" of pre-configured scatter plots and dynamically add or remove data and want them completely removed when there is no data to plot - this can be conveniently done with the above empty_offset construct. Furthermore (have not checked it), set_visible(False) might not free the memory of the underlying arrays which might be also of concern when the data is larger.

  10. tacaswell commented on Apr 15, 2024

    @tacaswell
    Member

    I agree that supporting this would be good. I suspect that #22408 can be adopted if someone is interested in pushing on this.

  11. ianhi commented on Dec 12, 2025

    @ianhi
    ContributorAuthor

    Looking back I'm not sure I was properly thinking about the shapes because I was comparing set_data and set_offsets which are two distinct things. set_data documents taking (2, N) while set_offsets documents (N,2). This was caught by @tacaswell in #22408 (comment)

    So the correct input for an empty offset is not [[],[]] it has to be construct using numpy:

    set_offsets(np.asarray([[],[]]).T)

    or np.empty((0,2))

    I think I got bit confused by the fact that you can do set_offsets([1,1]) (shape (2,)) and it gets interpreted correctly. So I thought a natural extension was [[1,1,1], [1,1,1]] or [[],[]]. but both of those would be wrong

    I'm starting to think that the correct solution here is to raise an informative error message before failing on the indexing

    edit: which I have now updated the linked PR #22408 to do

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions