[Matplotlib-users] Composing image from hex tiles using RegularPolyCollection

2014-04-25 Thread Tom Grydeland
Hi all,

I will explain what I’m trying to achieve first, then the approaches I’ve 
attempted so far, with results.

I have data on a 2D grid which I want to present as an image — a la 
pyplot.imshow() — except that the grid is hexagonal, not rectangular.  The grid 
can be represented in multiple ways, I use a regular 2D array with the 
convention that the lower left hex is (0,0), x increases to the right (crossing 
vertical hex boundaries) and y increases upwards slanting to the right.

Ideally, I’d also be able to have a colorbar.

I’m giving my routines three input vectors: x, y and c.  X and y are initially 
integers, then transformed to centerpoint coordinates using
 x, y = x+.5*y, y*np.cos(np.pi/6)
while c is used to look up values in a colormap.

I first tried to adapt ‘scatter_demo2.py’ to my needs.  Unfortunately, the 
pyplot.scatter routine fails when given ‘c’ or ’s’ keywords, as has been 
reported elsewhere by somebody else:
   
http://stackoverflow.com/questions/20524888/attributeerror-numpy-ndarray-object-has-no-attribute-get-matrix

I’ve dug around in the code for a bit without finding out how this arises.  It 
seems to me it has to do with how transforms are being handed around and at 
what point their representation is changed from objects to pure matrices.  This 
backend appears to expect to see objects only, but is handed matrices instead.  
I’ve hacked my way around that one in backends/backend_macosx.py by changing 
lines around 79-80 from
   master_transform = master_transform.get_matrix()
   all_transforms = [t.get_matrix() for t in all_transforms]
to
   try:
   master_transform = master_transform.get_matrix()
   except AttributeError: pass
   try:
   all_transforms = [t.get_matrix() for t in all_transforms]
   except AttributeError: pass
(which is a dirty hack, but I don’t know how to do it right)

Now I can run the scatter_demo2 script, and I can obviously have it produce 
hexes at uniform size, but the size of the hexagons are set independently of 
the axes.  Good for symbols used to mark arbitrary coordinates, not so good 
when I try to cover the plane without gaps.

Next, I’ve tried creating the patches one by one, essentially this:

   r = 1./np.sqrt(3)
   for xy, cc in zip(zip(x, y), c):
   hexp = mpl.patches.RegularPolygon(xy, 6, radius=r, facecolor=cc, 
edgecolor=’none')
   ax.add_patch(hexp)
   ax.autoscale_view()
   ax.figure.canvas.draw()

This works as I want it to, but becomes unbearably slow when the number of 
hexes grows beyond a few thousand.

Given that RegularPolygon can do the trick, it seems likely that 
RegularPolyCollection should also be able to?

This is what I tried:

   ax = gca()
   collection = RegularPolyCollection(
   6, # a pentagon
   rotation=(np.pi/7,),
   sizes=(.5/np.sqrt(3),),
   facecolors = cc,
   edgecolors = None,
   linewidths = (1,),
   offsets = zip(xx,yy),
   transOffset = ax.transData,
   )
   #collection.set_transform(ax.transData)
   ax.add_collection(collection, autolim=True)

   ax.autoscale_view()
   ax.figure.canvas.draw()

This produces dots of minute sizes at the desired coordinates.  I can tweak the 
size to make them bigger, but they don’t scale with the axes, as for the 
scatter_demo script used initially.  Digging in the docs, I found a reference 
to the set_transform() method of Artists, so I tried setting that to 
ax.transData (the line commented out in the above snippet), and voila! I have 
hexagons covering the plane again.  Strangely enough, they’re not in the right 
place anymore (and the locations change when zooming in or out), the sizes 
aren’t _quite_ right, the autoscaling of axes appear to believe the patches are 
where I wanted them to be, not where they appear on the plot, results are very 
different if saving to a figure instead of drawing to a figure window, etc.

Is there a way I can make RegularPolyCollection patches transform with axes 
coordinates in the same way that RegularPolygon patches do?

Am I barking up the wrong tree, is there another, blindingly obvious, way I 
should be doing this?

The observant reader will also notice the strange rotation keyword given to 
RegularPolyCollection.  This keyword is ignored in the macosx backend, and I 
have been unable to find out why.

Thank you for all tips and pointers

--Tom Grydeland


--
Start Your Social Network Today - Download eXo Platform
Build your Enterprise Intranet with eXo Platform Software
Java Based Open Source Intranet - Social, Extensible, Cloud Ready
Get Started Now And Turn Your Intranet Into A Collaboration Platform
http://p.sf.net/sfu/ExoPlatform
___
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users


Re: [Matplotlib-users] Composing image from hex tiles using RegularPolyCollection

2014-04-25 Thread Eric Firing
On 2014/04/24 11:40 PM, Tom Grydeland wrote:
 Hi all,

 I will explain what I’m trying to achieve first, then the approaches I’ve 
 attempted so far, with results.

 I have data on a 2D grid which I want to present as an image — a la 
 pyplot.imshow() — except that the grid is hexagonal, not rectangular.  The 
 grid can be represented in multiple ways, I use a regular 2D array with the 
 convention that the lower left hex is (0,0), x increases to the right 
 (crossing vertical hex boundaries) and y increases upwards slanting to the 
 right.


Tom,

Have you considered adapting the code from the Axes.hexbin() method?

Ideally, the hexbin method might be split into two parts, one for the 
calculation and another for the plotting.

Eric

 Ideally, I’d also be able to have a colorbar.

 I’m giving my routines three input vectors: x, y and c.  X and y are 
 initially integers, then transformed to centerpoint coordinates using
   x, y = x+.5*y, y*np.cos(np.pi/6)
 while c is used to look up values in a colormap.

 I first tried to adapt ‘scatter_demo2.py’ to my needs.  Unfortunately, the 
 pyplot.scatter routine fails when given ‘c’ or ’s’ keywords, as has been 
 reported elsewhere by somebody else:
 
 http://stackoverflow.com/questions/20524888/attributeerror-numpy-ndarray-object-has-no-attribute-get-matrix

 I’ve dug around in the code for a bit without finding out how this arises.  
 It seems to me it has to do with how transforms are being handed around and 
 at what point their representation is changed from objects to pure matrices.  
 This backend appears to expect to see objects only, but is handed matrices 
 instead.  I’ve hacked my way around that one in backends/backend_macosx.py by 
 changing lines around 79-80 from
 master_transform = master_transform.get_matrix()
 all_transforms = [t.get_matrix() for t in all_transforms]
 to
 try:
 master_transform = master_transform.get_matrix()
 except AttributeError: pass
 try:
 all_transforms = [t.get_matrix() for t in all_transforms]
 except AttributeError: pass
 (which is a dirty hack, but I don’t know how to do it right)

 Now I can run the scatter_demo2 script, and I can obviously have it produce 
 hexes at uniform size, but the size of the hexagons are set independently of 
 the axes.  Good for symbols used to mark arbitrary coordinates, not so good 
 when I try to cover the plane without gaps.

 Next, I’ve tried creating the patches one by one, essentially this:

 r = 1./np.sqrt(3)
 for xy, cc in zip(zip(x, y), c):
 hexp = mpl.patches.RegularPolygon(xy, 6, radius=r, facecolor=cc, 
 edgecolor=’none')
 ax.add_patch(hexp)
 ax.autoscale_view()
 ax.figure.canvas.draw()

 This works as I want it to, but becomes unbearably slow when the number of 
 hexes grows beyond a few thousand.

 Given that RegularPolygon can do the trick, it seems likely that 
 RegularPolyCollection should also be able to?

 This is what I tried:

 ax = gca()
 collection = RegularPolyCollection(
 6, # a pentagon
 rotation=(np.pi/7,),
 sizes=(.5/np.sqrt(3),),
 facecolors = cc,
 edgecolors = None,
 linewidths = (1,),
 offsets = zip(xx,yy),
 transOffset = ax.transData,
 )
 #collection.set_transform(ax.transData)
 ax.add_collection(collection, autolim=True)

 ax.autoscale_view()
 ax.figure.canvas.draw()

 This produces dots of minute sizes at the desired coordinates.  I can tweak 
 the size to make them bigger, but they don’t scale with the axes, as for the 
 scatter_demo script used initially.  Digging in the docs, I found a reference 
 to the set_transform() method of Artists, so I tried setting that to 
 ax.transData (the line commented out in the above snippet), and voila! I have 
 hexagons covering the plane again.  Strangely enough, they’re not in the 
 right place anymore (and the locations change when zooming in or out), the 
 sizes aren’t _quite_ right, the autoscaling of axes appear to believe the 
 patches are where I wanted them to be, not where they appear on the plot, 
 results are very different if saving to a figure instead of drawing to a 
 figure window, etc.

 Is there a way I can make RegularPolyCollection patches transform with axes 
 coordinates in the same way that RegularPolygon patches do?

 Am I barking up the wrong tree, is there another, blindingly obvious, way I 
 should be doing this?

 The observant reader will also notice the strange rotation keyword given to 
 RegularPolyCollection.  This keyword is ignored in the macosx backend, and I 
 have been unable to find out why.

 Thank you for all tips and pointers

 --Tom Grydeland


 --
 Start Your Social Network Today - Download eXo Platform
 Build your Enterprise Intranet with eXo Platform Software
 Java