Ask Your Question

Can I convert a GraphicsArray object to a Graphics object?

asked 2011-01-15 04:03:30 -0600

niles gravatar image

updated 2011-01-18 06:19:35 -0600

This is related to the Plot titles question about adding titles to plots. I'd like to add a title--or any descriptive text--to an image created as a GraphicsArray object, but a GraphicsArray is not a Graphics object, so the easy idea of adding a text graphic at the bottom or top doesn't work. Moreover, other things one might want to to with a GraphicsArray image also don't work. Looking at the source code for GraphicsArray, it seems that the ._render() function is doing all the hard work, and creates (but doesn't return) a matplotlib Figure object. Try as I might, I can't see how to get a Graphics object out.

(Note: I have been able to successfully use convert to add text outside of sage, as mentioned in response to the "Plot titles" question, but I'd like an internal way to do it, and I think this would be a generally useful thing to do anyway.)

Here's an extended example:

A = [plot(sin(t+k*pi/4),(-pi,pi)) for k in range(8)]

results in

array of sine plots

I would be content (for now) to add a text graphics object to this image, but trying

graphics_array(A,3,3) + text('hello world',(0,0), axes=False)

results in a TypeError.

Now one can add the text graphic to the end of the list of objects for the array, but this has a couple of problems:

A = [plot(sin(t+k*pi/4),(-pi,pi)) for k in range(8)] + [text('hello world',(0,0), axes=False)]

graphics array including text object

Note that:

  • axes=False in the text object has no effect -- one can turn off axes for all of the graphics in the array, but not for just one
  • it would be nice if the text were centered, spanning the width of the image (especially for a long caption, which might be wider than the individual images in the array)
  • placement of the text frame is awkward if there are 9 images to start with . . . I guess I could prepend the text object to the array . . .

UPDATE: There are now two tickets for issues here:

#10656: GraphicsArray() should be a Graphics() object, or have functionality to return one

#10657: options for items in a GraphicsArray() should be set independently

edit retag flag offensive close merge delete


Wow, I can't even count how many legitimate bugs you are reporting in this post. (You'll also note that updating the documentation for this is the primary thing keeping from reaching 100% coverage - always a bad sign.)

kcrisman gravatar imagekcrisman ( 2011-01-15 13:52:38 -0600 )edit

2 answers

Sort by ยป oldest newest most voted

answered 2011-01-15 14:03:59 -0600

kcrisman gravatar image

I hate to say this, but the answer is not what you want.

sage: var('t')
sage: A = [plot(sin(t+k*pi/4),(-pi,pi)) for k in range(8)]
sage: G = graphics_array(A,3,3)
sage: G[3]
sage: type(G[3])
<class 'sage.plot.plot.Graphics'>

Which only answers the question in the title, which is not the question you want answered - namely, how to make the whole array a Graphics object.

This can certainly be done in theory - see lots-o-plots on the matplotlib site - but we haven't wrapped it. And we don't (quite) have the backward conversion of a mpl object to a Sage Graphics object done (though see Trac 5128. So what I would say to really answer your question is: Do it in straight matplotlib.

And open a few tickets governing some of the behavior you noticed - and maybe a separate one to just refactor the GraphicsArray code completely and make it a useful object in the sense you want (not that it's not very useful already, of course!). This is clearly because of the fact that this class is only really intended for plotting, not the sort of abstract behavior you are mentioning. As far as I can tell, the tip at this blog doesn't work for your case of the Hello World axes.

edit flag offensive delete link more


thanks for the catch -- I've fixed the title to be a little more accurate now :) Thanks for the pointers too . . . both Graphics and GraphicsArray are pretty tough for me to understand, but matplotlib is even tougher! Anyway, I'll organize my thoughts and then open some tickets.

niles gravatar imageniles ( 2011-01-15 16:05:02 -0600 )edit

oh, it seems like #5128 will give me essentially what I want though

niles gravatar imageniles ( 2011-01-15 16:11:43 -0600 )edit

Yes, as I noted. Feel free to make that ready for inclusion :)

kcrisman gravatar imagekcrisman ( 2011-01-17 05:28:34 -0600 )edit

answered 2011-01-15 04:18:33 -0600

niles gravatar image

A partial solution (I couldn't stop thinking about this even after I posted the question):

  1. get the Figure object from GraphicsArray._render(): I did this by adding an optional keyword argument return_figure=False to the method, which returns the figure when True

  2. Figure.suptitle() adds a title

  3. Figure.savefig() saves the resulting image

I'd still like to know how to really get a Graphics object, now either from GraphicsArray or from a matplotlib Figure.

edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools


Asked: 2011-01-15 04:03:30 -0600

Seen: 597 times

Last updated: Jan 18 '11