I am working with a matplotlib-based routine that returns a figure and, as separate objects, the axes that it contains. Is there any way, that I can display these things and edit them (annotate, change some font sizes, things like that)? "fig.show()" doesn't work, just returns an error. Thanks.
Figures need a canvas to draw on.
Try fig.draw()
Related
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!
From https://plot.ly/python/line-and-scatter/#line-and-scatter-plots
I would like to create a plot just like this, but I'd like to style the labels to the right differently (from the image where image, lines+markers and lines are).
I've added textfont=dict(color='black'), to the go.Scatter line does nothing. I've added a Layout object with font=dict(color='black'),, does nothing. And I've added similar to XAxis and YAxis without anything changing there, either.
For my use I'll be plotting really light colours (yellows, and green), which are fine for the dot, but really bad for the text. I'll also have longer text for the label, but plot.ly just converts it to ellipses, and I haven't been able to figure a way to prevent that, and just show all the text.
I was trying to run the following code at the moment:
imgplot = plt.imshow(dose_data, extent = [0,4,0,6], aspect = 'auto')
On the console, I typed the following input:
In[38]:imgplot
Out[38]: <matplotlib.image.AxesImage at 0x123ebd198>
And the output made me wonder what the object is. After consulting the documentation, it seems like an AxesImage object (AxesImage Documentation). However I was wondering how to use the object stored in imgplot. At the moment I can neither see what it is, nor save it to an image.
P.S. I know how to show an image and how to save an image. I was just wondering how this object could be useful and what it actually is (like, is it an image object? an array? or some other weird type of object?)
As you have already found out, the return type of plt.imshow() is a matplotlib.image.AxesImage. The object img you get when calling img = plt.imshow() is an instance of that class.
In general, you do not have to care about this object, since it's bound to an axes and most of what you want to do, like showing a figure or saving it, does not require any control over that AxesImage itself.
Like with any other object, it may be useful for getting access to some of its properties for later use. e.g. img.cmap returns the colormap of the imgage, img.get_extent() provides you with the image extent.
There are two applications coming to my mind, where the AxesImage is frequently used:
Updating the image data: If you want to change the image data without producing a new plot, you may use
img.set_data(data)
This may be useful when working with user interactions or with animations.
Creating a colorbar: When creating a colorbar in a plot with several images, it may not be obvious for which image this colorbar should be created, thus
plt.colorbar(img, cax=cax) sets the colorbar of the image img to the axes cax.
For further details, you would probably need to refine your question, asking more specifically about some property, application, potential use etc.
If you wish to use the object nature of plot objects, proceed by first initiating a figure and axes object.
figure, axes = plt.subplots()
# or:
figure = plt.figure()
axes = figure.add_subplot(111)
Then you can plot using the axes object. The axes object lets you manipulate most things you can see in the plot.
axes.imshow(...)
Or save figures
figure.savefig('file.png')
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.
I'm relatively new to python and am developing a pyqt GUI. I want to provide a checkbox option to show/hide a plot's legend. Is there a way to hide a legend?
I've tried using pyplot's '_nolegend_' and it appears to work on select legend entries but it creates a ValueError if applied to all entries.
I can brute force the legend to hide by clearing and redrawing the whole plot but... it's a terrible thing to do, especially with large data sets.
Appreciate any help with this.
Here's something you can try on the command line:
plot([3,1,4,1],label='foo')
lgd=legend()
# when you want it to be invisible:
lgd.set_visible(False)
draw()
# when you want it to be visible:
lgd.set_visible(True)
draw()
In a GUI program it's best to avoid pyplot and use the object-oriented API, i.e., ax.legend and canvas.draw.