imagegraphicssage

Is it possible to use Image as a Graphics object?


We can use PIL.Image or sage.repl.image in Sagemath. Can we mix bitmap (non-vector) images with Sagemath Graphics objects (such as circle, text, plot, list_plot, etc)? For example, if I have 2 bitmap images and 4 plots, how can we use graphics_array to display them as tiles in 2 rows and 3 columns?

In other words, for example, how can we add bitmap images and graphics such as list_plot to the same Graphics object? Another example is when I want to superimpose some plots and text on a bitmap image.


Solution

  • This is a fleshed out version of my comment. The idea is to actually boil everything down to matplotlib. Further configuration would then follow as with typical matplotlib configuration (which is to say that you can do anything you could possibly want, but it's not necessarily easy or straightforward).

    To make this example, I took two separate png files with SO logos, converted them to bitmaps using imagemagick, and then used these as my sample bitmaps.

    # This is almost all pure python, except for the two circles
    # which require this to run in sage.
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import PIL.Image
    
    # Sage things - not base python
    c1 = circle([1, 1], 2)
    c2 = circle([2, 1], 1, edgecolor='red')
    
    img1 = PIL.Image.open("soicon.bmp")
    img2 = PIL.Image.open("soicon2.bmp")
    
    fig, axs = plt.subplots(nrows=2, ncols=2)
    fig.set_size_inches(5, 5)
    c1.matplotlib(sub=axs[0][0])  # have c1 draw itself there
    axs[0][1].imshow(img1)        # or whatever plot you want on each axis
    axs[1][0].imshow(img2)        # etc
    c2.matplotlib(sub=axs[1][1])  # have c2 draw itself there
    
    fig.tight_layout()  # just a suggestion
    fig.savefig("combined.png")
    

    To make this a complete example, I also made two very simple sage plots, each of a single circle (one blue, one red). Then I made a 2x2 set of images.

    The output is the following.

    An ugly 2x2 grid of images

    Customizing the axes and spacing and all that can be done as with typical matplotlib.subplots subplots. I wouldn't say that it's easy, but it's a very common task and there are lots of similar questions about that on SO. But it is possible to, for example, not display axes for the two imshow bitmaps or to have the axis labels for the blue circle be terrible.