matplotlib shows different figure than saves from the show() window - python

I plot rather complex data with matplotlib's imshow(), so I prefer to first visually inspect if it is all right, before saving. So I usually call plt.show(), see if it is fine, and then manually save it with a GUI dialog in the show() window. And everything was always fine, but recently I started getting a weird thing. When I save the figure I get a very wrong picture, though it looks perfectly fine in the matplotlib's interactive window.
If I zoom to a specific location and then save what I see, I get a fine figure.
So, this is the correct one (a small area of the picture, saved with zooming first):
And this one is a zoom into approximately the same area of the figure, after I saved it all:
For some reason pixels in the second one are much bigger! That is vary bad for me - as you can see, it looses a lot of details in there.
Unfortunately, my code is quite complicated and I wasn't able to reproduce it with some randomly generated data. This problem appeared after I started to plot two triangles of the picture separately: I read my two huge data files with np.loadtxt(), get np.triu(data1) and np.tril(data2), mask zeroes, NAs, -inf and +inf and then plot them on the same axes with plt.imshow(data, interpolation='none', origin='lower', extent=extent). I do lot's of other different things to make it nicer, but I guess it doesn't matter, because it all worked like a charm before.
Please, let me know, if you need to know anything else specific from my code, that could be relevant to this problem.

When you save a figure in png/jpg you are forced to rasterize it, convert it to a finite number of pixels. If you want to keep the full resolution, you have a few options:
Use a very high dpi parameter, like 900. Saving the plot will be slow, and many image viewers will take some time to open it, but the information is there and you can always crop it.
Save the image data, the exact numbers you used to make the plot. Whenever you need to inspect it, load it in Matplotlib in interactive mode, navigate to your desired corner, and save it.
Use SVG: it is a vector graphics format, so you are not limited to pixels.
Here is how to use SVG:
import matplotlib
matplotlib.use('SVG')
import matplotlib.pyplot as plt
# Generate the image
plt.imshow(image, interpolation='none')
plt.savefig('output_image')
Edit:
To save a true SVG you need to use the SVG backend from the beginning, which is unfortunately, incompatible with interactive mode. Some backends, like GTKCairo seem to allow both, but the result is still rasterized, not a true SVG.
This may be a bug in matplotlib, at least, to the best of my knowledge, it is not documented.

Related

How to buffer pyplot plots

TL;DR: I want to do something like
cache.append(fig.save_lines)
....
cache.load_into(fig)
I'm writing a (QML) front-end for a pyplot-like and matplotlib based MCMC sample visualisation library, and hit a small roadblock. I want to be able to produce and cache figures in the background, so that when the user moves some sliders, the plots aren't re-generated (they are complex and expensive to re-compute) but just brought in from the cache.
In order to do that I need to be able to do the plotting (but not the rendering) offline and then simply change the contents of a canvas. Effectively I want to do something like cache the
line = plt.plot(x,y)
object, but for multiple subplots.
The library produces very complex plots so I can't keep track of the line2D objects and use those.
My attempt at a solution: render to a pixmap with the correct DPI and use that. Issues arise if I resize the canvas, and not want to re-scale the Pixmaps. I've had situations where the wonderful SO community came up with much better solutions than what I had in mind, so if anyone has experience and/or ideas for how to get this behaviour, I'd be very much obliged!

Matplotlib rendering bar graph incorrectly

OK, I've got some data that I'm plotting with matplotlib in python 3.x (it's basically just a csv file with x and y data)
The graph plots fine, except that it ends up with weird bands in it where the spacing between the bars seems to have broken down:
I know it's not a problem with the data because I ran a test in excel, and got interesting patterns there as well (though in different places)
Please can anybody tell me whether 1) this is something that is already known about, and 2) there is a way of correcting it?
This is a problem of stamping in raster images like bmp or png. The structure you want to show (in this case vertical lines) shows features the size of which are on the same order of magnitude than the raster grid (the pixels of the image). This will inevitably lead to distotions.
The option you have is to increase dpi, such that the lines have more pixels to be placed on.

Matplotlib fill_between() plot not always displayed in a pdf

I often use fill_between() to represent the error on my time series plots and save them as pdf files (using plt.savefig()) which I then insert into either PowerPoint presentations, or MS Word files. I've personally never had any issues in seeing the plots. However, recently, a couple of instances occurred where others could not see the specific plots generated by the fill_between() function. The other plots in the figure were visible without issue.
I wonder if anybody else has had this issue, and any possible solution for this. Would saving as a .png file ensure that the shaded regions always show up?
Thanks
EDIT: The persons who cannot see the shaded regions due to fill_between() are anonymous reviewers of my research paper, hence its not possible to go communicate with them to investigate if the problem is in their systems or mine. Rather, my question is more generic and not situation-specific. Once a plot is saved (in this case, as a pdf), I didn't expect it to change.
An example of fill_between() in my code:
def plot(ts,err,Label,col,sty):
plt.plot(ts.index,ts,col,linestyle=sty,linewidth=2, label=Label)
plt.fill_between(ts.index,ts-err, ts+err
, alpha=0.15, edgecolor=col, facecolor=col)
plot(dataTs,err(dataTs),'label','k','-')
plt.savefig('../Figures/test.pdf', bbox_inches='tight')
Output plot:
The machine and the OS that I use: Macbook Pro, macOS Sierra.

Save figure parameters after interactive tweaking

I often find myself using matplotlib to quickly display data, then later going back and tweaking my plotting code to make pretty figures. In this process, I often use the interactive plot window to adjust things like spacing, zooming, cropping, etc. While I can easily save the resulting figure to an image file, what I really want is to save the sequence of function calls/parameters that produced it.
Note that I don't particularly care to open the same figure again (as in Saving interactive Matplotlib figures). Even something as simple as being able to print the various properties of the figure and axes would be useful.
While I don't have the answer to your specific question, I'd generally suggest using the Ipython Notebook for these things (and much more!)
Make sure you have %pylab inline in one cell.
When you plot, it will display it in the notebook itself. Then within your cell, just keep experimenting until you have it right (use Ctrl-Enter in the cell). Now the cell will have all the statements you need (and no more!)
The difference between the command line interpreter and the notebook is that the former all statements you typed which leads to a lot of clutter. With the notebook you can edit the line in place.
A similar question here
has an answer I just posted here.
The gist: use MatPlotLib's picklable figure object to save the figure object to a file. See the aforementioned answer for a full example.
Here's a shortened example:
fig, ax = matplotlib.pyplot.subplots()
# plot some stuff
import pickle
pickle.dump( fig, open('SaveToFile.pickle', 'wb') )
This does indeed save all plotting tweaks, even those made by the GUI subplot-adjuster. Unpickling via pickle.load() still allows you to interact via CLI or GUI.

Python plotting: How can I make matplotlib.pyplot stop forcing the style of my markers?

I am trying to plot a bunch of data points (many thousands) in Python using matplotlib so I need each marker to be very small and precise. How do I get the smallest most simple marker possible? I use this command to plot my data:
matplotlib.pyplot( x , y ,'.',markersize=0.1,linewidth=None,markerfacecolor='black')
Then I can look at it either with pl.show() and then save it. Or directly use plt.savefig('filename.ps') in the code to save it. The problem is this: when I use pl.show() to view the file in the GUI it looks great with small tiny black marks, however when I save from the show() GUI to a file or use directly savefig and then view the ps I created it looks different! Each marker has gained a little blue halo around it (as if it started at each point to connect them with the default blue lines, but did not) and the style is all wrong. Why does it change the style when saved? How do I stop python from forcing the style of the markers? And yes I have looked at some alternative packages like CairoPlot, but I want to keep using matplotlib for now.
Update: It turns out that the save to PNG first makes the colors turn out okay, but it forces a conversion of the image when I want to save it again as a .ps later (for inclusion in a PDF) and then I lose quality. How do I preserve the vector nature of the file and get the right formatting?
For nice-looking vectorized output, don't use the '.' marker style. Use e.g. 'o' (circle) or 's' (square) (see help(plot) for the options) and set the markersize keyword argument to something suitably small, e.g.:
plot(x, y, 'ko', markersize=2)
savefig('foo.ps')
That '.' (point) produces less nice results could be construed as a bug in matplotlib, but then, what should "point" mean in a vector graphic format?
Have you tried the ',' point shape? It creates "pixels" (small dots, instead of shapes).
You can play with the markersize option as well, with this shape?
If you haven't, you should try saving in a rasterizing engine -- save it to a PNG file and see if that fixes it. If you need a vector plot, try saving to PDF and converting with an external utility. I've also had problems before with the PS engine that were resolved by saving with the Agg or PDF engines and converting externally.

Categories