Rasterized graphics with Matplotlib to preserve plot transparencies for ApJ figures

Some of the astronomical research journals (ApJ, ApJL, others?) still require that figures be submitted in (encapsulated) postscript format. Since we’re otherwise living in the second decade of the 21st century, our figures frequently contain elements supported by the PDF format but not by PS, most notable among them variable element transparencies. This is the “alpha” parameter in Matplotlib, and I suppose “transparency” in more recent versions of IDL (IDL<=7 didn't support transparencies and was one of the main reasons I switched 4 years ago and for many other reasons happily never looked back).

Once I had carefully constructed PDF figures that I then needed to port to PS for submission to the journal I tried various image conversion options with ImageMagick/convert, always without much success. I learned recently that (of course) Matplotlib will easily allow you to do this at the plot generation stage with a trivial change to the plotting code. Example code is provided below with the key line obtained from pstjon@StackOverflow:

        import numpy as np
        import matplotlib.pyplot as plt
        
        x = np.random.normal(size=5000)
        y = np.random.normal(size=5000)
        #### Normal plot
        plt.scatter(x, y, alpha=0.05, s=40, color='black')
        plt.plot([-10,10],[-10,10], color='red', linewidth=10, alpha=0.5)
        plt.plot([-10,10],[10,-10], color='blue', linewidth=10, alpha=0.5)
        plt.xlim(-10,10); plt.ylim(-10,10)
        plt.savefig('default.pdf')  ### alphas preserved
        plt.savefig('default.eps')  ### alphas lost
        
        #### For rasterized EPS (e.g., preserve opacity)
        fig = plt.figure()
        ax = fig.add_subplot(111)
        ## This is the key.  elements with zorder < 1 will be rasterized
        ax.set_rasterization_zorder(1) 
        
        ax.text(0, 5, 'This will be rasterized', size=12, zorder=0)    
        ax.text(0, 3, 'This won\'t', size=12, zorder=1)    

        ax.scatter(x, y, alpha=0.05, s=40, color='black', zorder=0)
        ax.plot([-10,10],[-10,10], color='red', linewidth=10, alpha=0.5,
                zorder=0)
        ax.plot([-10,10],[10,-10], color='blue', linewidth=10, alpha=0.5, 
                zorder=0)
        ax.set_xlim(-10,10); ax.set_ylim(-10,10)
                 
        plt.xlim(-10,10); plt.ylim(-10,10)
        fig.savefig('raster.eps', rasterized=True)
        fig.savefig('raster300.eps', rasterized=True, dpi=300) ### for publication

The results are compared in the image below.

Matplotlib_raster.002

This was partially inspired by a recent post at Astrobetter showing how to use rasterization to reduce figure file sizes when plotting many thousands of points. In the example shown there, I think the plot is still useless as the large majority of points are in the saturated blob in the middle of the image. The Astrobetter example (along with mine above) is just a toy demonstration, but this problem does appear up frequently in the published literature. This can be cured either by pushing alpha down further or, better yet, by showing contours rather than points where the point density is high.

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s