|
From: Eric F. <ef...@ha...> - 2011-02-15 19:17:21
|
On 02/15/2011 08:50 AM, Benjamin Root wrote:
> On Tue, Feb 15, 2011 at 12:19 PM, Benjamin Root <ben...@ou...
> <mailto:ben...@ou...>> wrote:
>
> On Tue, Feb 15, 2011 at 11:54 AM, Eric Firing <ef...@ha...
> <mailto:ef...@ha...>> wrote:
>
> On 02/15/2011 07:40 AM, Benjamin Root wrote:
> > I have come across a little inconsistency that was unexpected
> in the
> > matplotlib API. The following is perfectly valid:
> >
> > import matplotlib.pyplot as plt
> > plt.plot([], [])
> > plt.show()
> >
> >
> > However, this is not valid:
> >
> > import matplotlib.pyplot as plt
> > plt.scatter([], [])
> > plt.show()
> >
> >
> > The immediate issue that comes up in scatter is that it
> attempts to find
> > min/max of the input data for the purpose of autoscaling
> (this can
> > probably be done better by just using set_xmargin(0.05) and
> > set_ymargin(0.05)). This can easily be bypassed with an if
> statement.
> > However, then we discover that polygon collection do not like
> having
> > empty offsets, which leads to a failure in the affine
> transformation.
> >
> > So, the question is, is this a bug or a feature? I
> personally believe
> > that empty data is a perfectly valid scenario and given that
> other
> > matplotlib functions handle it gracefully, we should make the
> > collections object more friendly to empty data.
>
> I agree; a call with empty data should simply not plot anything.
>
> Eric
>
>
> Digging further, it appears that the problem is in _path.cpp for
> _path_module::affine_transform() which explicitly checks for an
> empty vertices array and throws an exception if it is empty.
>
> So, do we want to make _path.cpp empty-friendly or should we just
> make empty collections objects just avoid doing anything that
> requires doing an affine transform?
>
> Ben Root
>
>
>
> Ok, some more digging deepens the mystery. While an empty-friendly
> _path.cpp would be nice, it appears that the collections and axes
> objects are already doing all it can to avoid doing transforms for empty
> collections.
>
> However, it appears that the supposedly empty collection object from
> scatter([], []) is not really empty. Its self._paths member contains a
> list of unit_circle() from Path. This is also the case for
> EllipseCollection. Meanwhile, LineCollection and PatchCollection
> initializes their self._paths in accordance to their given data.
One way to solve the problem would be to start each draw() method with a
short-circuit return in case there is nothing to draw. It would be
needed only for classes for which empty self._paths is not a valid test.
So for CircleCollection it would be:
@allow_rasterization
def draw(self, renderer):
# sizes is the area of the circle circumscribing the polygon
# in points^2
if len(self._sizes) == 0:
return
self._transforms = [
transforms.Affine2D().scale(
(np.sqrt(x) * self.figure.dpi / 72.0) / np.sqrt(np.pi))
for x in self._sizes]
return Collection.draw(self, renderer)
(Collection.draw returns nothing, so there is no inconsistency in the
return value.)
Alternatively, it looks like maybe an empty self._transforms could be
used in a short-circuit test at the start of Collection.draw.
Eric
>
> Ben Root
>
|