How can I make a matplotlib pdf without a clipping bounding box? - python

My usual workflow is to generate a plot using matplotlib, save the plot as a pdf using savefig(), and then open the plot in Adobe Illustrator to do final tweaking. Every pdf created by matplotlib has a clipping mask around the border of the content. I find it quite annoying to always release the clipping mask and then delete the clipping bounding box before I begin adjusting my pdf. Is there some way to eliminate this clipping behavior?
To make this more concrete, here is an example,
import matplotlib.pylab as plt
fig = plt.figure(figsize = (5,5))
ax = plt.subplot(111)
ax.plot([0,1], [0,1])
plt.savefig('Test.pdf')
which creates a pdf with a clipping mask around the outside edges, even though there is nothing to clip.
I noticed that I can set fig.set_clip_on=False, but it does not do anything. In fact, if I set fig.set_clip_on=False and directly afterwards query fig.get_clip_on, it returns True.
Any suggestions to get rid of the clipping bbox?

Related

Image artefacts when using cyclic colormaps for periodic data

I am currently trying to visualize the phase of an electromagnetic field which is 2pi-periodic. To visualize that e.g. 1.9 pi is almost the same as 0, I am using a cyclic colormap (twilight). However, when I plot my images, there are always lines at the sections where the phase jumps from (almost) 2pi to 0. When you zoom in on these lines, these artefacts vanish.
Here is a simple script and example images that demonstrate this issue.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-3,3,501)
x,y = np.meshgrid(x,x)
data = x**2+y**2
data = np.mod(data, 2)
plt.set_cmap('twilight')
plt.imshow(data)
plt.show()
I tested it with "twilight_shifted" and "hsv" as well and got the same issue. The problem also occurs after saving the image via plt.savefig(). I also tried other image formats like svg but it did not change anything.
As suggested in this answer you can set the image interpolation to "nearest", e.g.,
plt.imshow(data, interpolation="nearest")
See here for a discussion of image antialiasing effects with different interpolation methods.

Controlling resolution of full domain pcolormesh cells

I'm not sure whether this is a Cartopy or Matplotlib question, so I apologize if this would have been better suited for Matplotlib.
I am transitioning from NCL (NCAR Command Language https://www.ncl.ucar.edu/) to Python. Previously, I was using NCL to contour with a method of "CellFill" (https://www.ncl.ucar.edu/Document/Graphics/Resources/cn.shtml#cnFillMode). In Python, I am using pcolormesh to render a gridded dataset with a horizontal grid spacing of 3-km. In NCL, regardless of whether I am plotting the full domain or an area zoom, the resolution of the resulting image appears to be consistent using a PNG output. In Python however, if I use pcolormesh with an area zoom it looks identical to my NCL plot but if I try and plot the full domain, it looks different.
I've traced this down to the figure resolution. At the full domain view in Python, however I have my figure settings configured causes the 3-km cells in certain areas to become "blurred together" making it appear as if the entire region is a certain contour value when in actuality there are areas with no values in between.
Here is a CONUS example of pcolormesh:
And here is a full CONUS version from NCL:
There are several areas of note, but one obvious area is the NM/AZ region. If I zoom in very closely in both Python and NCL in this region, the resulting images look identical. But at the CONUS view it looks like there's much more shading in this area than there actually should be in the Python version.
crs = ccrs.PlateCarree() # Lat/Lon
fig = plt.figure(1, figsize=(15, 15))
ax.add_feature(cfeature.COASTLINE.with_scale('50m'), linewidth=BORDERWIDTH,edgecolor=BORDERCOLOR)
ax.add_feature(cfeature.STATES, linewidth=BORDERWIDTH,edgecolor=BORDERCOLOR)
ax.add_feature(cfeature.BORDERS, linewidth=BORDERWIDTH,edgecolor=BORDERCOLOR)
ax1 = plt.subplot(111,projection=crs)
norm = BoundaryNorm(LEVELS,ncolors=plt.get_cmap('plasma').N,clip=False)
cf1 = ax1.pcolormesh(diffsum.lon0,diffsum.lat0,diffsum,cmap='plasma',transform=ccrs.PlateCarree(),norm=norm)
plt.savefig('testing%s.png' % (DSTRING))
Note that if I manually increase the DPI used in the resulting image to something rediculous like 1000, or increase the figure size to 100x100 inches, it also looks OK but the resulting image is so gigantic it makes it cumbersome to view on the screen.
Is there something I am missing about pcolormesh that I should be doing to help better adapt the resolution of the cells being shaded with respect to the resolution of the actual figure itself?

Vector graphics + matplotlib pcolorfast

To keep it short: Is there a way to export plots created with methods like
pcolorfast which basically draw pixels as "real" vector graphics?
I tried to do just that using savefig and saving to a PDF but what would happen is that the plot was actually a vector graphic but the parts drawn by pcolorfast(so basically, what is inside the axes) something like a bitmap. - I checked this using Inkscape.
This resulted in really low resolution plots even though the arrays drawn with pcolorfast where about 3000x4000. I achieved higher resolution by increasing the dpi when exporting, but I'd really appreciate a conversion to a real vector graphic.
Edit: I updated my original code by the piece of code below that should serve to illustrate what exactly I am doing. I tried to involucrate the rasterized tip, but it has had no effect. I still end up with a supersmall PDF-file where the plots are acually raster images (png). I am going to provide you with the data I used and the resulting PDF.
http://www.megafileupload.com/k5ku/test_array1.txt
http://www.megafileupload.com/k5kv/test_array2.txt
http://www.megafileupload.com/k5kw/test.pdf
import numpy as np
import matplotlib.pyplot as plt
arr1= np.loadtxt("test_array1.txt")
arr2= np.loadtxt("test_array2.txt")
fig, (ax1, ax2)=plt.subplots(1, 2)
ax1.set_rasterized(False)
ax1.pcolorfast(arr1)
ax2.pcolorfast(arr2, rasterized=False)
plt.show()
fig.set_rasterized(False)
fig.savefig("test.pdf")

Editing Image using Python

I have to edit few image files using python. I have to open each image file, add few points at particular location & save the new edited image file(For fd my post-processing work).
Problem I am facing is:
1) I could not resize my plot axis. My plot axis should be 0-1 on both x &y with out any loss in image quality.
2) I could not save the edited image file, only the original file is getting saved.
This is what I tried:
im = Image.open('vortex.png')
implot = plt.plot(im)
fig, ax= plt.subplots()
myaximage = ax.imshow(im, aspect='auto', extent=(0,1,0,1),
alpha=0.5, origin='upper',
zorder=-2)
plt.implot([0.5], [0.5])
plt.show()
im.save("new","png")
Besides some small problems with your code, it seems you're basing your work on a wrong assumption: that you can turn a image into a matplotlib plot.
An image is simply a collection of pixels. While your brain interprets it as a plot, with a axis, and maybe a grid, you can't expect the computer to do so. You can't manipulate a collection of pixels as if it were a plot - it isn't.
You need to forget about matplotlib and use the image editing resourses of PIL.
Not sure about the axis change, but the saving of the file, see this post:
Python Imaging Library save function syntax
From the PIL Handbook:
im.save(outfile, options...)
im.save(outfile, format, options...)
Simplest case:
im.save('my_image.png')

Saving images in Python at a very high quality

How can I save Python plots at very high quality?
That is, when I keep zooming in on the object saved in a PDF file, why isn't there any blurring?
Also, what would be the best mode to save it in?
png, eps? Or some other? I can't do pdf, because there is a hidden number that happens that mess with Latexmk compilation.
If you are using Matplotlib and are trying to get good figures in a LaTeX document, save as an EPS. Specifically, try something like this after running the commands to plot the image:
plt.savefig('destination_path.eps', format='eps')
I have found that EPS files work best and the dpi parameter is what really makes them look good in a document.
To specify the orientation of the figure before saving, simply call the following before the plt.savefig call, but after creating the plot (assuming you have plotted using an axes with the name ax):
ax.view_init(elev=elevation_angle, azim=azimuthal_angle)
Where elevation_angle is a number (in degrees) specifying the polar angle (down from vertical z axis) and the azimuthal_angle specifies the azimuthal angle (around the z axis).
I find that it is easiest to determine these values by first plotting the image and then rotating it and watching the current values of the angles appear towards the bottom of the window just below the actual plot. Keep in mind that the x, y, z, positions appear by default, but they are replaced with the two angles when you start to click+drag+rotate the image.
Just to add my results, also using Matplotlib.
.eps made all my text bold and removed transparency. .svg gave me high-resolution pictures that actually looked like my graph.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
# Do the plot code
fig.savefig('myimage.svg', format='svg', dpi=1200)
I used 1200 dpi because a lot of scientific journals require images in 1200 / 600 / 300 dpi, depending on what the image is of. Convert to desired dpi and format in GIMP or Inkscape.
Obviously the dpi doesn't matter since .svg are vector graphics and have "infinite resolution".
You can save to a figure that is 1920x1080 (or 1080p) using:
fig = plt.figure(figsize=(19.20,10.80))
You can also go much higher or lower. The above solutions work well for printing, but these days you want the created image to go into a PNG/JPG or appear in a wide screen format.
Okay, I found spencerlyon2's answer working. However, in case anybody would find himself/herself not knowing what to do with that one line, I had to do it this way:
beingsaved = plt.figure()
# Some scatter plots
plt.scatter(X_1_x, X_1_y)
plt.scatter(X_2_x, X_2_y)
beingsaved.savefig('destination_path.eps', format='eps', dpi=1000)
In case you are working with seaborn plots, instead of Matplotlib, you can save a .png image like this:
Let's suppose you have a matrix object (either Pandas or NumPy), and you want to take a heatmap:
import seaborn as sb
image = sb.heatmap(matrix) # This gets you the heatmap
image.figure.savefig("C:/Your/Path/ ... /your_image.png") # This saves it
This code is compatible with the latest version of Seaborn. Other code around Stack Overflow worked only for previous versions.
Another way I like is this. I set the size of the next image as follows:
plt.subplots(figsize=(15,15))
And then later I plot the output in the console, from which I can copy-paste it where I want. (Since Seaborn is built on top of Matplotlib, there will not be any problem.)

Categories

Resources