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 > |