collections?

I can’t tell if I’m misusing collections here, or if there is a bug. Anyway, what I’m trying to do is keep track of a group of rectangles generated from a bar plot. Instead of letting there be a large number of artists added to the axes, I wanted to just group them into a collection and add the collection instead. As in the code below:

#!/usr/bin/env python

import numpy

import matplotlib.pyplot as plt

import matplotlib.collections

just generate some data to plot

x = numpy.linspace(0.0,2.0*numpy.pi,10)

y = numpy.sin(x)

plot

axes = plt.gca()

bars = plt.bar(x,y,color=‘red’,width=0.1)

strip out all of the newly inserted rectangles

for b in bars: b.remove()

and create a collection for plotting the rectangles instead.

coll = matplotlib.collections.PatchCollection(bars)

axes.artists.append(coll)

plt.xlim(0.0,2.0*numpy.pi)

plt.grid(True)

plt.show()

This appears to work at first blush, but if you resize the plot, you can tell that the rectangles are just fixed in their location now. I tried messing around with setting the transform for the new collection object “coll” in different ways, to no avail. Any suggestions welcome :wink:

···


Daniel Hyams
dhyams@…287…

I can’t tell if I’m misusing collections here, or if there is a bug. Anyway, what I’m trying to do is keep track of a group of rectangles generated from a bar plot. Instead of letting there be a large number of artists added to the axes, I wanted to just group them into a collection and add the collection instead. As in the code below:

#!/usr/bin/env python

import numpy

import matplotlib.pyplot as plt

import matplotlib.collections

just generate some data to plot

x = numpy.linspace(0.0,2.0*numpy.pi,10)

y = numpy.sin(x)

plot

axes = plt.gca()

bars = plt.bar(x,y,color=‘red’,width=0.1)

strip out all of the newly inserted rectangles

for b in bars: b.remove()

and create a collection for plotting the rectangles instead.

coll = matplotlib.collections.PatchCollection(bars)

axes.artists.append(coll)

plt.xlim(0.0,2.0*numpy.pi)

plt.grid(True)

plt.show()

This appears to work at first blush, but if you resize the plot, you can tell that the rectangles are just fixed in their location now. I tried messing around with setting the transform for the new collection object “coll” in different ways, to no avail. Any suggestions welcome :wink:


Daniel Hyams
dhyams@…287…

try transOffset:

coll = matplotlib.collections.PatchCollection(bars, transOffset=axes.transData)

I’ve always found this a bit clumsy, but I think it’s the standard way to do it.

-Tony

···

On Fri, Dec 9, 2011 at 2:13 PM, Daniel Hyams <dhyams@…1003…7…> wrote:

Tried, but unfortunately it did not make any difference :frowning:

···

On Fri, Dec 9, 2011 at 2:22 PM, Tony Yu <tsyu80@…287…> wrote:

On Fri, Dec 9, 2011 at 2:13 PM, Daniel Hyams <dhyams@…985…> wrote:

I can’t tell if I’m misusing collections here, or if there is a bug. Anyway, what I’m trying to do is keep track of a group of rectangles generated from a bar plot. Instead of letting there be a large number of artists added to the axes, I wanted to just group them into a collection and add the collection instead. As in the code below:

#!/usr/bin/env python

import numpy

import matplotlib.pyplot as plt

import matplotlib.collections

just generate some data to plot

x = numpy.linspace(0.0,2.0*numpy.pi,10)

y = numpy.sin(x)

plot

axes = plt.gca()

bars = plt.bar(x,y,color=‘red’,width=0.1)

strip out all of the newly inserted rectangles

for b in bars: b.remove()

and create a collection for plotting the rectangles instead.

coll = matplotlib.collections.PatchCollection(bars)

axes.artists.append(coll)

plt.xlim(0.0,2.0*numpy.pi)

plt.grid(True)

plt.show()

This appears to work at first blush, but if you resize the plot, you can tell that the rectangles are just fixed in their location now. I tried messing around with setting the transform for the new collection object “coll” in different ways, to no avail. Any suggestions welcome :wink:


Daniel Hyams
dhyams@…287…

try transOffset:

coll = matplotlib.collections.PatchCollection(bars, transOffset=axes.transData)

I’ve always found this a bit clumsy, but I think it’s the standard way to do it.

-Tony


Daniel Hyams
dhyams@…287…

Just as an interesting point… don’t know if it means anything. In v1.1.x, we now return a “BarContainer” from the bar() function. This container subclasses the tuple type, which is why you are still able to treat it like a list. Anyway, this class does a bunch of things that I wonder if it could be interfering with what you are trying to do. Probably not, but still…

Ben Root

···

On Fri, Dec 9, 2011 at 2:55 PM, Daniel Hyams <dhyams@…287…> wrote:

Tried, but unfortunately it did not make any difference :frowning:

I’m sorry, I should have stated the version. I’m using 1.0.0, which just returns a list of rectangle artists.

···

On Fri, Dec 9, 2011 at 4:08 PM, Benjamin Root <ben.root@…1304…> wrote:

On Fri, Dec 9, 2011 at 2:55 PM, Daniel Hyams <dhyams@…287…> wrote:

Tried, but unfortunately it did not make any difference :frowning:

Just as an interesting point… don’t know if it means anything. In v1.1.x, we now return a “BarContainer” from the bar() function. This container subclasses the tuple type, which is why you are still able to treat it like a list. Anyway, this class does a bunch of things that I wonder if it could be interfering with what you are trying to do. Probably not, but still…

Ben Root


Daniel Hyams
dhyams@…287…

So I think the problem is that plt.bar assigns a transform to each patch (as it should). But then when pass these patches to PatchCollection, the collection applies it’s own transform (but doesn’t ignore the patch’s transform, apparently). The solution is to clear out the transform on each patch—where “clearing” a transform translates to setting it to the IdentityTransform.

Below is code that works on my system. It sounds like it will work slightly differently on your system:

#!/usr/bin/env python
import numpy
import matplotlib.pyplot as plt
import matplotlib.collections

import matplotlib.transforms as transforms

just generate some data to plot

x = numpy.linspace(0.0,2.0*numpy.pi,10)
y = numpy.sin(x)

plot

axes = plt.gca()
bars = plt.bar(x,y,color=‘red’,width=0.1)

axes.patches = []
for p in bars.patches:
p.set_transform(transforms.IdentityTransform())

and create a collection for plotting the rectangles instead.

coll = matplotlib.collections.PatchCollection(bars.patches)

coll.set_transform(axes.transData)
axes.add_collection(coll, autolim=True)

plt.xlim(0.0,2.0*numpy.pi)
plt.grid(True)
plt.show()

···

On Fri, Dec 9, 2011 at 4:11 PM, Daniel Hyams <dhyams@…1003…7…> wrote:

I’m sorry, I should have stated the version. I’m using 1.0.0, which just returns a list of rectangle artists.

On Fri, Dec 9, 2011 at 4:08 PM, Benjamin Root <ben.root@…1304…> wrote:

On Fri, Dec 9, 2011 at 2:55 PM, Daniel Hyams <dhyams@…287…> wrote:

Tried, but unfortunately it did not make any difference :frowning:

Just as an interesting point… don’t know if it means anything. In v1.1.x, we now return a “BarContainer” from the bar() function. This container subclasses the tuple type, which is why you are still able to treat it like a list. Anyway, this class does a bunch of things that I wonder if it could be interfering with what you are trying to do. Probably not, but still…

Ben Root


Daniel Hyams
dhyams@…287…

P.S. you don’t need the call to set_transform that I accidentally added.

···

On Fri, Dec 9, 2011 at 5:23 PM, Tony Yu <tsyu80@…287…> wrote:

On Fri, Dec 9, 2011 at 4:11 PM, Daniel Hyams <dhyams@…287…> wrote:

I’m sorry, I should have stated the version. I’m using 1.0.0, which just returns a list of rectangle artists.

On Fri, Dec 9, 2011 at 4:08 PM, Benjamin Root <ben.root@…1304…> wrote:

On Fri, Dec 9, 2011 at 2:55 PM, Daniel Hyams <dhyams@…287…> wrote:

Tried, but unfortunately it did not make any difference :frowning:

Just as an interesting point… don’t know if it means anything. In v1.1.x, we now return a “BarContainer” from the bar() function. This container subclasses the tuple type, which is why you are still able to treat it like a list. Anyway, this class does a bunch of things that I wonder if it could be interfering with what you are trying to do. Probably not, but still…

Ben Root


Daniel Hyams
dhyams@…287…

So I think the problem is that plt.bar assigns a transform to each patch (as it should). But then when pass these patches to PatchCollection, the collection applies it’s own transform (but doesn’t ignore the patch’s transform, apparently). The solution is to clear out the transform on each patch—where “clearing” a transform translates to setting it to the IdentityTransform.

Below is code that works on my system. It sounds like it will work slightly differently on your system:

#!/usr/bin/env python
import numpy
import matplotlib.pyplot as plt
import matplotlib.collections

import matplotlib.transforms as transforms

just generate some data to plot

x = numpy.linspace(0.0,2.0*numpy.pi,10)
y = numpy.sin(x)

plot

axes = plt.gca()
bars = plt.bar(x,y,color=‘red’,width=0.1)

axes.patches = []
for p in bars.patches:
p.set_transform(transforms.IdentityTransform())

and create a collection for plotting the rectangles instead.

coll = matplotlib.collections.PatchCollection(bars.patches)

coll.set_transform(axes.transData)
axes.add_collection(coll, autolim=True)

plt.xlim(0.0,2.0*numpy.pi)
plt.grid(True)
plt.show()

Thanks so much Tony…that does indeed work. I’m not sure if I understand exactly why, but I’ll continue to bang my head on it for a while :wink:

The set_transform() call is needed if you throw the collection into the axes.artists list, but not if axes.add_collection() is used to (ahem) add the collection.

···

On Fri, Dec 9, 2011 at 5:27 PM, Tony Yu <tsyu80@…287…> wrote:

On Fri, Dec 9, 2011 at 5:23 PM, Tony Yu <tsyu80@…287…> wrote:

On Fri, Dec 9, 2011 at 4:11 PM, Daniel Hyams <dhyams@…287…> wrote:

I’m sorry, I should have stated the version. I’m using 1.0.0, which just returns a list of rectangle artists.

On Fri, Dec 9, 2011 at 4:08 PM, Benjamin Root <ben.root@…1304…> wrote:

On Fri, Dec 9, 2011 at 2:55 PM, Daniel Hyams <dhyams@…287…> wrote:

Tried, but unfortunately it did not make any difference :frowning:

Just as an interesting point… don’t know if it means anything. In v1.1.x, we now return a “BarContainer” from the bar() function. This container subclasses the tuple type, which is why you are still able to treat it like a list. Anyway, this class does a bunch of things that I wonder if it could be interfering with what you are trying to do. Probably not, but still…

Ben Root


Daniel Hyams
dhyams@…287…

So I think the problem is that plt.bar assigns a transform to each patch (as it should). But then when pass these patches to PatchCollection, the collection applies it’s own transform (but doesn’t ignore the patch’s transform, apparently). The solution is to clear out the transform on each patch—where “clearing” a transform translates to setting it to the IdentityTransform.

Below is code that works on my system. It sounds like it will work slightly differently on your system:

#!/usr/bin/env python
import numpy
import matplotlib.pyplot as plt
import matplotlib.collections

import matplotlib.transforms as transforms

just generate some data to plot

x = numpy.linspace(0.0,2.0*numpy.pi,10)
y = numpy.sin(x)

plot

axes = plt.gca()
bars = plt.bar(x,y,color=‘red’,width=0.1)

axes.patches = []
for p in bars.patches:
p.set_transform(transforms.IdentityTransform())

and create a collection for plotting the rectangles instead.

coll = matplotlib.collections.PatchCollection(bars.patches)

coll.set_transform(axes.transData)
axes.add_collection(coll, autolim=True)

plt.xlim(0.0,2.0*numpy.pi)
plt.grid(True)
plt.show()

P.S. you don’t need the call to set_transform that I accidentally added.


Daniel Hyams
dhyams@…287…