From: Tony S Yu <tonyyu@MIT.EDU>  20090618 23:24:57

I'd like to plot a collection and scale the size of the collection elements in relation to the data. My guess is that I need to use the data transformation (ax.transData) since I would like the size of the collection elements altered when zooming in/out. Unfortunately, my attempt has led to weird results: the collection offsets are shifted from the desired coordinates when using ax.transData. Weirder still: the collection elements move *relative to the data coordinates* when panning the figure. I suspect that setting the collection transform to ax.transData is somehow applying some part of the transform twice. Does anyone know what I'm doing wrong here and how I can fix this? Thanks! Tony Attached is a toy example of what I'm trying to do. The radii of the circles are plotted correctly, but notice the x, y coordinates don't match the circle centers in the plot. Also, try panning the plot and watch as the circles move relative to the tick marks. >>> import matplotlib.pyplot as plt >>> import matplotlib.transforms as transforms >>> import numpy as np >>> fig = plt.figure() >>> ax = fig.add_subplot(111) >>> x = [0.25, 0.75, 0.25, 0.75] >>> y = [0.25, 0.25, 0.75, 0.75] >>> r = 0.1 * np.ones(4) >>> col = plt.scatter(x, y, np.pi*r**2) >>> pts2pixels = transforms.Affine2D().scale(72.0/fig.dpi) >>> col.set_transform(pts2pixels + ax.transData) >>> plt.axis('equal') >>> plt.show() 
From: JaeJoon Lee <lee.joon@gm...>  20090622 18:57:42

Tony, My understanding is that (which might be wrong) drawing collections involves (at least) 2 transforms. The first transform is (mostly) for scaling, and the second transform is for offset. And this seems to be true for PolygonCollection (which scatter creates) as far as I can see. set_transform() method sets the transform for scaling, which means that (0,0) should transform to (0,0). Otherwise the polygon is not drawn where you intended. And, obviously transData does NOT, which I think is the root of the problem. Unfortunately, the current PolygonCollection class does not seem to have any support for what you want. On the other hand, it seems that EllipseCollection lets you specify the ellipse size in data coordinate. The easiest solution I can think of is doing some monkey patching. import matplotlib.pyplot as plt import matplotlib.transforms as transforms import numpy as np fig = plt.figure() ax = fig.add_subplot(111) x = [0.25, 0.75, 0.25, 0.75] y = [0.25, 0.25, 0.75, 0.75] r = 0.1 * np.ones(4) col = plt.scatter(x, y, np.pi*r**2) from matplotlib.collections import RegularPolyCollection class RegularPolyCollection2(RegularPolyCollection): def get_transform(self): ax = self.axes sc_x = ax.bbox.width / ax.viewLim.width sc_y = ax.bbox.height / ax.viewLim.height return transforms.Affine2D().scale(sc_x, sc_y) col.__class__ = RegularPolyCollection2 plt.axis('equal') plt.show() Alternatively, you may modify your code to use EllipseCollection (if what you want are just cricles). I hope this solution fits your need. Regards, JJ On Thu, Jun 18, 2009 at 7:24 PM, Tony S Yu<tonyyu@...> wrote: > I'd like to plot a collection and scale the size of the collection > elements in relation to the data. My guess is that I need to use the > data transformation (ax.transData) since I would like the size of the > collection elements altered when zooming in/out. > > Unfortunately, my attempt has led to weird results: the collection > offsets are shifted from the desired coordinates when using > ax.transData. Weirder still: the collection elements move *relative to > the data coordinates* when panning the figure. > > I suspect that setting the collection transform to ax.transData is > somehow applying some part of the transform twice. Does anyone know > what I'm doing wrong here and how I can fix this? > > Thanks! > Tony > > Attached is a toy example of what I'm trying to do. The radii of the > circles are plotted correctly, but notice the x, y coordinates don't > match the circle centers in the plot. Also, try panning the plot and > watch as the circles move relative to the tick marks. > > > >>> import matplotlib.pyplot as plt > >>> import matplotlib.transforms as transforms > >>> import numpy as np > >>> fig = plt.figure() > >>> ax = fig.add_subplot(111) > >>> x = [0.25, 0.75, 0.25, 0.75] > >>> y = [0.25, 0.25, 0.75, 0.75] > >>> r = 0.1 * np.ones(4) > >>> col = plt.scatter(x, y, np.pi*r**2) > >>> pts2pixels = transforms.Affine2D().scale(72.0/fig.dpi) > >>> col.set_transform(pts2pixels + ax.transData) > >>> plt.axis('equal') > >>> plt.show() > >  > Crystal Reports  New Free Runtime and 30 Day Trial > Check out the new simplified licensing option that enables unlimited > royaltyfree distribution of the report engine for externally facing > server and web deployment. > http://p.sf.net/sfu/businessobjects > _______________________________________________ > Matplotlibusers mailing list > Matplotlibusers@... > https://lists.sourceforge.net/lists/listinfo/matplotlibusers > 
From: Tony S Yu <tonyyu@MIT.EDU>  20090623 03:29:32

On Jun 22, 2009, at 2:57 PM, JaeJoon Lee wrote: > The easiest solution I can think of is doing some monkey patching. > > > import matplotlib.pyplot as plt > import matplotlib.transforms as transforms > import numpy as np > fig = plt.figure() > ax = fig.add_subplot(111) > x = [0.25, 0.75, 0.25, 0.75] > y = [0.25, 0.25, 0.75, 0.75] > r = 0.1 * np.ones(4) > col = plt.scatter(x, y, np.pi*r**2) > > > from matplotlib.collections import RegularPolyCollection > class RegularPolyCollection2(RegularPolyCollection): > def get_transform(self): > ax = self.axes > > sc_x = ax.bbox.width / ax.viewLim.width > sc_y = ax.bbox.height / ax.viewLim.height > > return transforms.Affine2D().scale(sc_x, sc_y) > > col.__class__ = RegularPolyCollection2 > > plt.axis('equal') > plt.show() Thanks JaeJoon! This is exactly what I was looking for. Tony 