imshow in subplot with interactive mode - python

I cannot get matshow() or imshow() to actually display the plot when both of the following conditions are true: (1) interactive mode is on: import matplotlib.pyplot as plot; plot.ion(), and (2) I am trying to use matshow on a specific subplot: fig = plot.figure(); ax = fig.add_subplot(111); ax.matshow([[1,2],[3,0]]).
Using plot.matshow([[1,2],[3,0]]) (note: no explicit axes) works find in interactive mode, but will always create a new figure window with a single axes object. The above code with the subplot also works fine without interactive mode using plot.show(), and will put the image on the correct axes.
More oddly, the above code with the subplot will show the image if I interact with the figure, such as by using the zoom tool and clicking randomly in the figure window (there is no visible axes object, but I just click somewhere in the middle of the figure window).
Any ideas what might be causing this, how I could fix it, or how I could get around it to use matshow or imshow on a specified subplot (the end use case is to have more than 1 subplot in the figure)? This occurs in python (2.7.6) and ipython (1.1.1)

This may have something to do with this documentation:
Display an array as a matrix in a new figure window.
However, you may as well use imshow with suitable arguments:
import matplotlib.pyplot as plt
plt.imshow(mat, interpolation='nearest', origin='upper', aspect='equal')
This should do the same thing while being a bit less odd. This is actually exactly what matshow does internally. It just adds a few tick markers to the image.
Also, by having a look at the source (or closely reading the help string), you may try to do:
plt.matshow(mat, fignum=0)
This should force it use current axis, which it picks by using gca.
In addition to this, there is ax.matshow which you used, as well. Actually plt.matshow is a very thin wrapper around ax.matshow, mostly to create the new image.
If you still have problems with matshow or imshow in subplots, please make a minimal complete example for us to try! Here is something I tried in the interactive shell (IPython):
figure()
ax = subplot(121)
ax2 = subplot(122)
ax.matshow(random.random((20,30)))
ax2.plot(linspace(-1,1,100), linspace(-1,1,100)**2)
draw()
(Could the problem be a missing draw?)
What I got:

Related

Visualizing Python interactive plots outside of Jupyter

I am making some small tests in Jupyter. The user should see two plots, one on the left and one on the right. Than after clicking somewhere on the left plot something on the right plot should happen. For example here a click on the left plot will produce a red dot on the right plot in the same place:
%matplotlib notebook
def onclick(event):
ax.clear()
ax2.clear()
ax.set_xlim(0,10)
ax.set_ylim(0,10)
ax2.set_xlim(0,10)
ax2.set_ylim(0,10)
ax2.plot([event.xdata],[event.ydata],'o',color='red')
ax.figure.canvas.draw_idle()
ax2.figure.canvas.draw_idle()
fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax.set_xlim(0,10)
ax.set_ylim(0,10)
ax2.set_xlim(0,10)
ax2.set_ylim(0,10)
cid = fig.canvas.mpl_connect('button_press_event',onclick)
This works, but the visualization in Jupyter is not the best. Is there a way to have this kind of interactive plots working outside of a Jupyter notebook ? Maybe in a window with varying dimensions ? As an example, how would one proceed with the example above ?
You can use plotly and export your plots to html file:
https://plotly.com/python/interactive-html-export/
I think I found a possible simple answer to my needs. Simply put the code in the question in a python script, remove the 'magic' command and insert at the end:
plt.show(block=True)
This way matplotlib will just use a different backend than notebook or inline in Jupiter and plot the figure in a separate window. This window is compatible with the interactive commands from matplotlib. I am not sure about widget compatibility though I will try and update the answer.
Update: I do not think ipywidgets can be used with plt.show() since these are not plotted in an axes, but there are some widgets within matplotlib (matplotlib.widgets) that can be used. Though, the resulting speed in my case is not satisfactory so I would avoid combining matplotlib widgets with matplotlib event catching.

Spyder plots not allowing enough user control

I am running python (3.8) via spyder (4.1.4) on a Windows laptop. I need to plot multiple series on a single graph, then do the usual things like adjusting axis limits, positioning the legend, etc. Spyder will not let me do all of this in one single plot.
For instance, the following produces two different plots:
plt.plot(seriesa,'o')
plt.plot(seriesb,'o')
and so does this:
fig = plt.figure()
ax = fig.add_subplot()
ax.plot(seriesa,'o')
ax.plot(seriesb,'o')
I can get both plots in one graph by doing the entire thing in one command:
fig = plt.figure() ; ax = fig.add_subplot() ; ax.plot(seriesa,'o') ; ax.plot(seriesb,'o')
(which seems like a hack to me, but I'll do whatever works). But then I need to adjust the y axis limits, and the command
ax.set_ylim((0,2000))
has no effect on the plot. And the command
plt.ylim((0,2000))
opens up an entirely new plot.
I tried inline plotting too (unchecking the "Mute inline plotting" menu item), with no improvement.
How do I get the control I need with my plots?
In case anyone is interested, the solution is, before doing any plotting, issue the IPython "magic command":
In [1]: %matplotlib auto
This puts spyder in a state where plots are by default placed in independent windows, as when python is run in a regular shell. Could not find this in spyder documentation. Found it in a similar stack overflow question here.

What is the meaning of colorbar.solids in Pyplot?

I am creating contour plots with matplotlib/pyplot and trying to print out a customized colorbar as well. I am also attempting to have the colorbar be printed in a completely separate image file from the plot.
sub_fig = plt.figure()
sub_ax = plt.axes()
sub_ax.axis("off")
#cs2 is a contourf object
sep_cb = plt.colorbar(cs2, cax=sub_ax)#, cax = new_figure.legend, ax=new_figure.legend, orientation="vertical")
sep_cb.shrink=0.5
sep_cb.fraction=.1
sep_cb.drawedges=True
# ~sep_cb.solids.set_edgecolor("white")
plt.savefig("colorbar_"+str(ii)+".png")
plt.clf()
So I am referring to the documentation here: https://matplotlib.org/api/_as_gen/matplotlib.pyplot.colorbar.html but I find that changing the settings does not change the appearance of my colorbar. What I want is actually to make it pretty small, and have the sections separated by some whitespace, with the values/ labels to the right. I can't shrink it, or make the values appear. No matter what, it appears like this:
colorbar
However, if I enable that sep_cb.solids line, I get some lines between the sections. But the only reason I even know about this is because of this section:
It is known that some vector graphics viewer (svg and pdf) renders white gaps between segments of the colorbar. This is due to bugs in the viewers not matplotlib. As a workaround the colorbar can be rendered with overlapping segments:
cbar = colorbar()
cbar.solids.set_edgecolor("face")
draw()
It seems that colorbar.solids can be used to set some options on the plot, but I cannot find any documentation on that directly, I don't even see it mentioned elsewhere on the page. Is this some basic pyplot thing I have managed to overlook? Any help would be appreciated, thank you.

Placing the legend outside the plot

I want to position the legend outside the drawing box. I do not find a clean way to do this. The main problem is having everything fit on the file saved. The only thing I have been able to figure out is this code:
#! /usr/bin/python
import matplotlib
# matplotlib.use('pdf')
from matplotlib.pyplot import *
subplot(111)
plot([1,2,3], label="test1")
l=legend(bbox_to_anchor=(1.05, 1), loc=2,borderaxespad=0)
tight_layout(rect=(0,0,0.8,1))
savefig('test.pdf')
There are a couple of caveats:
The tight_layout seems to be incompatible with matplotlib.use('pdf')
The 0.8 in the tight_layout has been found by trials and errors. If I replace label="test" by label="this is a very very long test", the legend will once again get out of the border of the file. I would like that to be adjusted automatically. I have not been able to retrieve the size of the legend. l.get_frame().get_width() seems to always return 1.0.
The tight_layout changes the size of the plot. What I would like to achieve is: specify the size of the plot in cm (or in inches). Placing the legend outside the plot. Having a file with the correct size in order that everything fits in, including the legend; without having to resort to trial and errors.
You can look at the answer to this question by Joe Kington.
The answer describes most of the options you can play around with regarding placement of legends.

How do I let my matplotlib plot go beyond the axes?

I have to translate an image plotting script from matlab to matplotlib/pylab, and I'm trying to achieve the same effect as the matlab image below:
As you can see, the z order of the plots seem to be higher than the z order of the grid, so the markers are not hidden by the axes. However, I can't figure out a way to do the same with my matplotlib image:
I'm wondering if it is possible to get the same display without having to increase the limits of the y axis.
To get the marker to show beyond the axes you can turn the clipping off. This can be done using the keyword argument in the plot command clip_on=False.
For example:
import matplotlib.pyplot as plt
plt.plot(range(5), range(5), 'ro', markersize=20, clip_on=False, zorder=100)
plt.show()
This is a complete example of how to use the zorder kwarg: http://matplotlib.sourceforge.net/examples/pylab_examples/zorder_demo.html
Note that a higher z-order equates to a graph-element being more in the foreground.
For your second question, have a look at the figsize kwarg to instances of the Figure class: http://matplotlib.sourceforge.net/api/figure_api.html?highlight=figsize#matplotlib.figure.Figure
If you run into issues, please post some of your code and we'll be able to give more-detailed recommendations. Best of luck.
If you're plotting the lines one after the other, just change the order of the plotting calls and that would fix the z order.

Categories

Resources