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.
Related
Is there any way to get ginput() to work to plot inline interactive plots in jupter lab/notebook?
For example; something like:
pts = plt.ginput(2, show_clicks=True)
for p in pts:
plot_trajectory(ax, p[1], p[0], 0.1, 25000)
plt.show()
Would be used to let the user click two points on the plot that are then used as starting points for the trajectories plotted by another function. I've managed to get it working using the qt matplotlib magic but this cannot be integrated with inline plots and wigets. Is there any way to do this?
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.
I am facing the following problem: I need two interactive plots to work at the same time on Jupyter, however they are interfering. When I rotate the cell of the first, the second plot stops being interactive and becomes "inline". Other times one of the plots looks like this:
The expected result was something like this
I imagine the problem is in the implementation I made. As you can see below, I use plt.something to put things in the figure (both for plot 1 and plot 2).
I'm using the %matplotlib notebook environment and tried to implement using fig1, ax1 = plt.subplots(). I would like to know if it is possible to do this type of implementation, where there is no conflict between plots? Maybe I am using matplotlib badly, so I would like some suggestions.
I'm using a dark theme on Jupyter Notebook and I find that when I make a plot using matplotlib, the plot looks like this:
So it is very hard to read the tick labels, as it seems that although the plot background is white, the background in this part is transparent.
I'm aware that this can be fixed on a plot by plot basis by using the following lines of code:
fig = plt.figure()
fig.patch.set_facecolor('white')
sns.scatterplot(train.X, train.y)
But is there a way to set a global property of matplotlib so that I don't need to do this each time?
Easiest I can think of:
sns.set()
sns.scatterplot(df.x,df.y)
Output:
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: