2

I would like to set individual properties (zorder and label for example) for a specific element of a matplotlib.collections.PathCollection. I couldn't find a way in the documentation.

Here I jot down a user case.
Let say we have the following snippet, and we'd like to change the zorder of the red ball, bringing it to the top, by using the balls handle, which is a matplotlib.collections.PathCollection.

balls = plt.scatter([-1, 1], [0, 0], c = ['r', 'b'], s = 4e4)
plt.axis([-5, 5, -5, 5])

Overlapped balls

Does anyone have any idea about how to tweak individual paths of a PathCollection?

The alternative would be using plt.plot('o'), which actually returns a list of handles. Unfortunately the plt.plot('o') solution won't allow me to set a different colour per ball, since they would all belong to the same chart. So a for loop would be required.

The drastic solution, which I bet I'll go for, since my deadline, is going of Inkscape :/

1 Answer 1

2

Not sure if this is the best solution, but it might help you.

From what I can see, the paths in the PathCollection are always plotted in the order they are created. So in your case, the path with the x-position of -1 is created first, then the one with 1.

You can switch that order after initially plotting them, by changing the offsets, in your case using balls.set_offsets():

In [4]: balls = plt.scatter([-1, 1], [0, 0], c = ['r', 'b'], s = 4e4)
In [5]: plt.axis([-5, 5, -5, 5])

This creates the following figure:enter image description here

In [42]: print balls.get_offsets()
[[-1.  0.]
 [ 1.  0.]]

On [43]: balls.set_offsets([[1,0],[-1,0]])

Now, this has plotted the left-hand ball on top of the right-hand ball:

enter image description here

But as you can see, this has also switched the facecolors around (since we set the order of that in the call to plt.scatter as ['r','b']. There's a solution to this, which is to also switch the facecolors around:

In [46]: balls.set_facecolors(['b','r'])

enter image description here


Great, so putting that all together, we can define a function to switch the offsets and facecolors of any two arbitrary paths in the PathCollection.

import matplotlib.pyplot as plt

fig,ax = plt.subplots()
balls = ax.scatter([-3, -1, 1, 3], [0, 0, 0, 0], c = ['r', 'b', 'g', 'm'], s = 4e4)
ax.set_xlim(-6,6)
ax.set_ylim(-6,6)

plt.savefig('balls_01.png')

def switch_scatter(pathcoll,a,b):

    # Switch offsets
    offsets = pathcoll.get_offsets()[:]
    offsets[[a,b]] = offsets[[b,a]]

    # Switch facecolors
    facecolors = pathcoll.get_facecolors()
    facecolors[[a,b]] = facecolors[[b,a]]

    # Switch sizes 
    sizes = pathcoll.get_sizes() 
    sizes[[a,b]] = sizes[[b,a]] 

    # Set the new offsets, facecolors and sizes on the PathCollection
    pathcoll.set_offsets(offsets)
    pathcoll.set_facecolors(facecolors)
    pathcoll.set_sizes(sizes)

switch_scatter(balls,2,1)

plt.savefig('balls_02.png')

Heres balls_01.png:

enter image description here

And here is balls_02.png (where we switch ball 1 and ball 2 (the blue and green balls)

enter image description here


A final note: if you have other properties varying in your scatter plot (e.g. linecolor), you will also need to switch them around in the function I defined above.

Sign up to request clarification or add additional context in comments.

7 Comments

OMG! Amazing! What happened is that a small ball was hiding under a bigger one and I wanted to avoid changing the order of my data and colours, since they are used elsewhere. In line plot I did use the zorder, but here I was not able to handle the situation the same way. I'll use your solution, but I will try to understand your function after the deadline, although the explanation in English make totally sense. Thank you very much for watching my back!
Question: how did you find out about offsets? Just to understand your modus operandi.
For completenes: # Switch sizes sizes = pathcoll.get_sizes() sizes[[a,b]] = sizes[[b,a]] and then pathcoll.set_sizes(sizes).
Thanks. I'll edit that into the answer. I found offsets by just tab-completing on the balls collection to see what properties it had, and finding the one that looks right. If you look at balls.properties (I think), its a dictionary of all its properties, so you can quickly find the ones you need.
LOL, OK. I was expecting some more fancy answer, haha! NIPS 2016 deadline is in 2 hours. Let try to review this masterpiece, haha! I'm thinking to add you to the Acknowledgements section ;) Do you have a name, or will you be a "stackoverflow user"?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.