For an article I am generating plots of deformed finite element meshes, which I visualize using matplotlib's polycollection. The images are saved as pdf.
Problems arise for high density meshes, for which the naive approach results in files that are too large and rendering too intensive to be practical.
For these meshes it really makes no sense to plot each element as a polygon; it could easily be rasterized, as is done when saving the image as jpg or png. However, for print I would like to hold on to a sharp frame, labels, and annotations.
Does anyone know if it is possible to achieve this kind of hybrid rasterization in matplotlib?
I can think of solutions involving imshow, and bypassing polycollection, but I would much prefer to use matplotlib's built-in components.
Thanks for your advice.
Just pass the rasterized=True keyword to your collection constructor. Example:
col = collections.PolyCollection(<arguments>, rasterized=True)
This allows a selective rasterization of that element only (e.g., if you did a normal plot on top of it, it would be vectorized by default). Most commands like plot or imshow can also take the rasterized keyword. If one wants to rasterize the whole figure (including labels and annotations), this would do it:
fig = plt.figure()
a = fig.add_subplot(1,1,1, rasterized=True)
(But this is not what you want, as stated in the question.)
Related
I have been using Cartopy to plot data using 'equal' aspect, resulting in all manner of non-square Axes sizes. These usually look OK in Jupyter notebooks, but when saving the images (or when doing more complicated operations like adding colorbars), the resulting Figures are often huge, with a lot of blank space around the Axes plotting area. They also look bad when using %matplotlib widget. An example is provided below.
It seems that the figure in this case is too big in at least one dimension. I would like to remove that extra space in the final output figure, without shrinking the size of the plotting area itself.
I know that I can adjust the figure size itself with .set_figwidth and .set_figheight, as well as setting figsize= upon creation. But I don't know how to figure out the correct dimensions to shrink the figure without shrinking the axes, and I haven't seen any way to do this automatically. What's the correct solution? I would like to avoid manually editing my images after creating them!
I have a set of PDF that I need to plot for a certain section of the PDF domain. However, when I plot my lines on a 3d plot I get tails for each PDF,
Is there a clean way to not plot the tails that happen outside my plot limits? I know I can change the data to NaNs to achieve the same effect but I want to do this in matplotlib. Here is my current workaround code,
`# trim the data
y = np.ones(PDF_x.shape)*PDF_x
y[y>95]= np.nan
y[y<75]= np.nan
# plot the data
fig = plt.figure()
ax = fig.gca(projection='3d')
for i in range(PDF_capacity.shape[1]):
ax.plot(life[i]*np.ones((PDF_x.shape)),y,PDF_capacity[:,i], label='parametric curve')
# set the axis limits
ax.set_ylim(75,95)
# add axis labels
ax.set_xlabel('charge cycles to failure point of 75% capacity')
ax.set_ylabel('capacity at 100 charge cycles')
ax.set_zlabel('probability')`
After trimming I can make the following plot,
Masking the data with nan in the way you're doing it is a good and practical solution.
Since matplotlib 3D plots are projections into 2D space, it would be hard to implement automatic clipping. While I do think it would be possible, I'm not convinced that it's worth the effort. First, because you would need to treat different kinds of plots differently, second, because at least in some cases it would probably turn out that masking the data is still the best choice. Now, doing a complex subclassing of the plotting objects just to do the same thing that can be manually done in one or two lines is probably overkill.
My clear recommendation would therefore be to use the solution you already have. Especially since it does not seem to have any drawbacks so far.
I often find myself needing to create heatmap-style visualizations in Python with matplotlib. Matplotlib provides several functions which apparently do the same thing. pcolormesh is recommended instead of pcolor but what is the difference (from a practical point of view as a data plotter) between imshow and pcolormesh? What are the pros/cons of using one over the other? In what scenarios would one or the other be a clear winner?
Fundamentally, imshow assumes that all data elements in your array are to be rendered at the same size, whereas pcolormesh/pcolor associates elements of the data array with rectangular elements whose size may vary over the rectangular grid.
If your mesh elements are uniform, then imshow with interpolation set to "nearest" will look very similar to the default pcolormesh display (without the optional X and Y args). The obvious differences are that the imshow y-axis will be inverted (w.r.t. pcolormesh) and the aspect ratio is maintained, although those characteristics can be altered to look like the pcolormesh output as well.
From a practical point of view, pcolormesh is more convenient if you want to visualize the data array as cells, particularly when the rectangular mesh is non-uniform or when you want to plot the boundaries/edges of the cells. Otherwise, imshow is more convenient if you have a fixed cell size, want to maintain aspect ratio, want control over pixel interpolation, or want to specify RGB values directly.
I am writing a bunch of scripts and functions for processing astronomical data. I have a set of galaxies, for which I want to plot some different properties in a 3-panel plot. I have an example of the layout here:
Now, this is not a problem. But sometimes, I want to create this plot just for a single galaxy. In other cases, I want to make a larger plot consisting of subplots that each are made up of the three+pane structure, like this mockup:
For the sake of modularity and reusability of my code, I would like to do something to the effect of just letting my function return a matplotlib.figure.Figure object and then let the caller - function or interactive session - decide whether to show() or savefig the object or embed it in a larger figure. But I cannot seem to find any hints of this in the documentation or elsewhere, it doesn't seem to be something people do that often.
Any suggestions as to what would be the best road to take? I have speculated whether using axes_grid would be the solution, but it doesn't seem quite clean and caller-agnostic to me. Any suggestions?
The best solution is to separate the figure layout logic from the plotting logic. Write your plotting code something like this:
def three_panel_plot(data, ploting_args, ax1, ax2, ax3):
# what you do to plot
So now the code that turns data -> images takes as arguments the data and where it should plot that data too.
If you want to do just one, it's easy, if you want to do a 3x3 grid, you just need to generate the layout and then loop over the axes sets + data.
The way you are suggesting (returning an object out of your plotting routine) would be very hard in matplotlib, the internals are too connected.
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.)