In MNE with Python, I would like to keep the interactive plotting window open once the calling def is executed completely.
However, this is not achievable via the following code:
def get_plot():
sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = os.path.join(sample_data_folder, 'MEG', 'sample',
'sample_audvis_raw.fif')
raw = mne.io.read_raw_fif(sample_data_raw_file)
raw.plot()
get_plot()
Such that, once the get_plot() is completed, the plot window is automatically closed.
Also, I am on Windows 10 with PyCharm 2020.1.3.
May I know how to handle this issue?
To get the interactive plot in PyCharm. The Show plots in tool window first need to be disabled.
Disable Settings | Tools | Python Scientific | Show plots in tool
window
Then, matplotlib.use('TkAgg') should allowed to create an interactive plot window.
MNE plot() is based on matplotlib. See the source file plot_raw. Based from the OP, matplotlib equip with block parameter you can pass to plt.show(). This allow the plot to be open even after the function is successfully invoke.
Apparently, mne group have include this parameter as well.
So, the above objective can be achieved simply by setting plot(block=True)
Then, the full code is
import mne
import matplotlib
matplotlib.use('TkAgg')
def get_plot():
sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = os.path.join(sample_data_folder, 'MEG', 'sample',
'sample_audvis_raw.fif')
raw = mne.io.read_raw_fif(sample_data_raw_file)
raw.plot(block=True)
get_plot()
Related
I wish to have an interactive map that you can click where, once clicked, a SkewT and Hodograph will be plotted showing the information for that location. I have thus created a class where I add all the necessary informations using the metpy library and I am able to successfully create these graphs:
SkewT and Hodograph plotted
The problem comes when I'm trying to import the classes I've created to generate these plots into jupyterlab. Since the code to actually make these plots is quite cumbersome, I'd rather
keep the code in a separate file and import my SoundingGraphs class, but it's not working. The graphs never get plotted inside a cell, they instead appear in the logs as a Warning and as an Info and I have no idea why:
Graphs appearing inside logs
Tried to use plt.show() inside my file, tried returning plt to then use plt.show() inside a cell of the notebook, tried using %matplotlib widget, %matplotlib notebook and %matplotlib inline, tried changing jupyterlab versions, none of these changed anything.
I have found one solution that I disliked, but that does work, which is rather than doing a plt.show(), to instead do this inside my class:
buffer = BytesIO()
plt.savefig(buffer, format='png')
return buffer
And in the notebook I would do:
image = Image()
display(image)
def on_generate_button_clicked(b):
buffer = SoundingGraphs(infos)
buffer.seek(0)
image.value=buffer.read()
image.format='png'
generate_button.on_click(on_generate_button_clicked)
I don't quite like this approach because further down the line I would like to add interactivity to my plots, like show values of plot when hovered and things like that, thus I don't just want to show an image. So I'd like to know if it is indeed possible to plt.show() a plot created inside another file in a cell.
Using:
Python 3.6.9
jupyterlab==3.2.9
jupyterlab-pygments==0.1.2
jupyterlab-server==2.10.3
jupyterlab-widgets==1.1.0
ipykernel==5.5.6
ipyleaflet==0.14.0
ipympl==0.8.8
ipython==7.16.3
ipython-genutils==0.2.0
ipywidgets==7.7.0
matplotlib==3.3.4
Thanks!
Yes, it is possible after all!
%matplotlib widget needs to be used at the start of the notebook and since the class method will be called from another function (on a button.on_click event), it is possible to use the #out.capture() decorator above it so that the plt.show() gets displayed. It's also possible to make the figure a class attribute to be able to have more control.
So here's a bit of working code if someone would like to replicate:
Notebook
%matplotlib widget
from ipywidgets import Button, Output
from myfile import MyClass
out = Output()
example_button = Button(
description='Example',
disabled=False,
button_style='',
tooltip='Click me'
)
#out.capture()
def on_example_button_clicked(b):
example_button.disabled = True
myclass = MyClass()
myclass.create_plot()
out.clear_output(wait=True)
display(myclass.fig.canvas)
example_button.disabled = False
example_button.on_click(on_example_button_clicked)
display(example_button)
display(out)
myfile.py
import matplotlib.pyplot as plt
class MyClass():
def __init__(self):
plt.ioff() # otherwise it'll also show inside logs
plt.clf()
self.fig = plt.figure()
def create_plot(self):
plt.plot([1, 2, 3, 4])
plt.ylabel('some numbers')
I'm new to Bokeh and Python, and this is my first Stack Overflow question as well.
I'm using Bokeh to plot trajectory profiles of particles diffusing in the brain, but have it be animated. I have been able to successfully create a program that plots the points, but once all the points are plotted, it stops. I want to be able to loop the animation so that once all the points are plotted, it clears itself and starts over.
I am still very unfamiliar with coding terms, and I wasn't able to find something that could do this. I thought I was on the right track with importing using the reset function inside an if statement, but it doesn't seem to work. I have looked at the following as well for reference:
How to animate a circle using bokeh
Here is my code so far plotting a random trajectory:
import numpy as np
from bokeh.plotting import figure, show, gridplot, vplot, hplot, curdoc
from bokeh.io import output_notebook
from bokeh.client import push_session
from bokeh.core.state import State as new
# This is where the actual coding begins.
b = np.random.rand(300, 3)
xlist = b[:, 1]
ylist = b[:, 2]
# create a plot and style its properties. Change chart title here.
p = figure(title='PEG_PLGA15k_F68_R2_P81', title_text_font_size='13pt',
x_range=(min(xlist), max(xlist)), y_range=(min(ylist), max(ylist)),)
# add a text renderer to out plot (no data yet)
r = p.line(x=[], y=[], line_width=3, color='navy')
session = push_session(curdoc())
i = 0
ds = r.data_source
# create a callback that will add a number in a random location
def callback():
global i
ds.data['x'].append(xlist[i])
ds.data['y'].append(ylist[i])
ds.trigger('data', ds.data, ds.data)
if i < xlist.shape[0] - 1:
i = i + 1
else:
new.reset()
# Adds a new data point every 67 ms. Change at user's discretion.
curdoc().add_periodic_callback(callback, 67)
session.show()
session.loop_until_closed()
If all you want is to restart the animation once you reach some condition (like "all points have been plotted") you can just reset the DataSource. So, for instance, on your example you should have:
else:
i = 0
ds.data['x'] = []
ds.data['y'] = []
instead of:
else:
new.reset()
and that should do the trick. Just use your datasource... State is a more general component that should be used on different level and not to manage plot glyphs and datasources.
A couple of quick notes here:
On your question you've mentioned a link to the 0.10 version documentation but from your code I can tell you are not using a newer version (0.11.x). Always be sure to use the right docs for the version of Bokeh you are using since there might be a few changes between one version and another before the project reach 1.0.
You don't need to call ds.trigger('data', ds.data, ds.data) since bokeh property system will automatically detect your changes to the datasource fields inside your callback
You are designing/running your script as a bokeh script that uses a client session to the server (so you'll have a running instance of bokeh server somewhere and your script communicates with it). I'd suggest you to consider running your code as a Bokeh App instead, so your session and your code run inside the bokeh server instance. You can see more details about the difference at the bokeh server section on the official docs.
When plotting with Python ggplot, every single plot command causes a GUI pane to be displayed and suspend execution ("interactive plotting"). But I want to:
avoid/ turn off this GUI and save the plot object some where in runtime (I will be displaying it in some other C# forms control).
find a Python equivalent to dev.off() command in R language which turns off the GUI for plotting.
Example:
print ggplot(data, aes('Age', 'Weight')) + geom_point(colour='steelblue')
When I execute this, it opens up a new GUI (like below) displaying the plot.
You can do the following, which returns a matplotlib figure:
g = ggplot(...) + geom_xxx(...)
fig = g.draw()
ggplots __repr__() method (what is called by print(g) is basically self.draw() then use matplotlibs plt.show() to show the plot...
You can also use ggsave(g) to save the plot somewhere.
Since plotting is triggered by __repr__ method the obvious approach is to avoid situations when it is called. Since you want to use this plot in some other place there is no reason to call print or even executing statements which will be discarded like this:
ggplot(data, aes('Age', 'Weight')) + geom_point(colour='steelblue')
Instead you can simply assign it to the variable
p = ggplot(data, aes('Age', 'Weight')) + geom_point(colour='steelblue')
what is exactly the same thing one would do in R. Using graphic device to redirect output and discarding it doesn't really make sense.
If for some reason that's not enough you switch to non-interactive matplotlib backend:
import matplotlib
matplotlib.use('Agg')
from ggplot import *
ggplot(aes(x='date', y='beef'), data=meat)
<ggplot: (...)>
In the past I was able to do simple animations with matplotlib with a for loop, but this hasn't worked for some time now.
The standard answer is that you have to turn interactive mode on and/or force a redraw with matplotlib.pyplot.draw(). Here is my minimal working example:
import numpy as np
import matplotlib
matplotlib.use('Qt4Agg')
import matplotlib.pyplot as mplot
mplot.ion()
fig = mplot.figure(1)
ax = fig.add_subplot(111)
for ii in np.arange(0,10):
x = 200*np.random.rand(30)
ax.plot(x)
mplot.draw()
filename = ("img_%d.png" % ii)
mplot.savefig(filename)
When I run this in Interactive Python Editor, I get one figure at the very end with all the plots in it (this also happens with mplot.show())
When I run this in IPython 3.1 (with Python 3.3.5) from the command line, I get nothing at all.
The mplot.savefig(filename) line does seem to work, as the images are generated.
(It's possible this is a bug in the Qt4 backend.)
Try deleting the line matplotlib.use('Qt4Agg'). Works for me. Also works with matplotlib.use('TkAgg'). So it is a backend problem. There is another way to do animations.
I am using scipy-cluster to generate a hierarchical clustering on some data. As a final step of the application, I call the dendrogram function to plot the clustering. I am running on Mac OS X Snow Leopard using the built-in Python 2.6.1 and this matplotlib package. The program runs fine, but at the end the Rocket Ship icon (as I understand, this is the launcher for GUI applications in python) shows up and vanishes immediately without doing anything. Nothing is shown. If I add a 'raw_input' after the call, it just bounces up and down in the dock forever. If I run a simple sample application for matplotlib from the terminal it runs fine. Does anyone have any experiences on this?
I had the same issue on Ubuntu 10.04.
In order to get graphics to display from ipython interactive console, start it with "-pylab" switch, which enables the interactive use of matplotlib:
ipython -pylab
To get your graphics to display during the execution of a standalone script, use matplotlib.pyplot.show call. Here's an example from hcluster homepage, the first and last line are the significant bits here:
from matplotlib.pyplot import show
from hcluster import pdist, linkage, dendrogram
import numpy
from numpy.random import rand
X = rand(10,100)
X[0:5,:] *= 2
Y = pdist(X)
Z = linkage(Y)
dendrogram(Z)
show()
Invoking ipython with "-pylab" switch didn't make a difference for me.
(System: Fedora 13)
Though not ideal, my solution was to explicitly write the resulting figure as a file.
For example:
...
dendrogram(Z)
pylab.savefig( "temp.png" )
Hope this helps anyone who is running into the same issue.
Amendment: Be careful about simply using copy-and-paste with the hcluster package's brief tutorial, notably in that if you call pylab.savefig() after several types of dendrogram drawing shown in the tutorial, i.e.
distMat = # whatever distance matrix you have
dendrogram( linkage( distMat ) )
pylab.savefig( "exampleDendrogram.png" )
dendrogram( linkage( distMat, method="complete" ) ) #instead of default "single"
pylab.savefig( "exampleDendrogram.png" )
Then exampleDendrogram.png will contain both the single-linkage dendrogram and the complete-linkage dendrogram in the same figure, and they will likely cross-cross and look like a mess.
If you're as stupid as me, you'll spend 30-180 minutes in confusion about how to properly use hcluster, when it's actually just a matter of resetting matplotlib between dendrogram calls:
distMat = # whatever distance matrix you have
dendrogram( linkage( distMat ) )
pylab.savefig( "exampleDendrogram1.png" )
pylab.cla()
dendrogram( linkage( distMat, method="complete" ) ) #instead of default "single"
pylab.savefig( "exampleDendrogram2.png" )
Now, the resulting dendrogram image files will look like what you expected them to look like.
I have been facing the same problem. You can use one of the below methods
Use plt.show() :
use plt.show() after dedogram, this will show the plot
using plt.show
Use %matplotlib inline intially in jupyter notebook. this will show the plot after execution.
Using matplotlib inline