I'd like to leverage Bokeh's rich and excellent library to create plots that allows a user to select groups for plotting data within Jupyter Notebook.
I have followed the following tutorial:
http://docs.bokeh.org/en/latest/docs/gallery/slider.html
However, when combining this tutorial with the "output_notebook" module, the plots are handled both within the notebook and in a new window. I have isolated the problem to the CustomJS module, probably the callback method.
How do I toggle off plotting in a new window?
I have followed the tutorial and made the following changes:
from bokeh.io import output_notebook
output_notebook()
and in show:
show(layout, notebook_handle=True)
(Writing as an answer so the information is more prominent)
The output_file command initiates a persistent operational mode. All subsequent show commands will result in the specified file being created (or overwritten). Merely deleting a notebook cell with output_file will not turn this mode off. You must either:
explicitly call reset_output to cancel, or
restart the notebook kernel
Related
The goal:
I am writing a function that uses Qt5Agg backend within a Jupyter notebook. The rest of the notebook mostly uses inline. The function generates an interactive plot with matplotlib widgets, and I want to make it work in a separate window. The rest of the notebook produces a bunch of figures, sometimes hundreds in a single cell that have to be generated inline, for efficiency.
I have been running %matplotlib qt just before running the function and %matplotlib inline immediately after running the function. However, I don't want to bother with these two extra lines, especially because %matplotlib inline has to be run in a separate cell. It is prone to user error - the backend will get stuck in Qt5Agg if the user forgets to run the cell after.
I would like to change the backend temporarily, by adding some code within the function. This would have the added advantage of making this function more compatible. I could transfer it to other notebooks and it would work as expected, using Qt5Agg, and won't mess with whatever backend the rest of that notebook uses (inline or something else).
Please note that I am coding on Windows, but I have to make sure that the notebook works on all operating systems.
What I have tried so far:
The most obvious solution I could come up with was setting a temporary rc context with a decorator...
import matplotlib.pyplot as plt
#plt.rc_context({'backend': 'Qt5Agg'})
def function(foo):
...
return None
This sets a context for the backend, as expected, but Matplotlib doesn't use it! If I print the backend from within the function, it will tell me that it is Qt5Agg, while I'm staring at an inline plot below it. Other parameters can be effectively changed using the rc_context. I can easily change stuff like 'lines.linestyle' and the plot will reflect those changes. Only when it comes to backend, Matplotlib refuses to use the value I set.
Next I tried changing the 'backend' value in the rcParams dictionary (this would change the backend globally, not locally but I tried it anyway). It leads to a similar situation where the value is changed in the dictionary, but Matplotlib continues using the inline backend. I also tried using switch_backend and matplotlib.use and neither of them worked reliably. Besides, they are also supposed to change the backend globally, so not ideal for my use. Of all the methods I discovered so far, magic is the only way to properly change backend.
Summary:
I can't get Matplotlib to reliably change backends without using magic.
Magic sets the backend globally, not locally within the function.
I need to change the backend locally, for only one function.
Matplotlib won't use the backend from rc_context.
P.S. - This is my first post, so apologies if I haven't provided all the useful information. Let me know if you need more info.
I found the best way to switch to PyQt and back to inline is through the 'close_event' in mpl_connect. Here is an outline of what I did:
def function(foo):
#Switches to qt interactive backend
%matplotlib qt
...
fig = plt.figure(...)
...
def on_close(event):
%matplotlib inline
fig.canvas.mpl_connect('close_event', on_close) #Switches backend to inline when the figure closes
...
return None
It works perfectly on my Windows machine. I can close the figure window using the default close button, or by passing plt.close() using a Matplotlib widget. The backend switches back to inline in both cases.
I would like to delete all the plots in the plot pane with some code so I can automatically "clear" the interface. I am aware there is a button you can click that deletes them all. However, I would like to avoid having to click manually on the plot pane to delete all the plots generated in the previous runs.
Right now I am already clearing the console and the variable explorer by using (which I got from link):
try:
from IPython import get_ipython
get_ipython().magic('clear')
get_ipython().magic('reset -f')
except:
pass
Now I would like to add there something that also clears the plot pane.
(Spyder maintainer here) It is not possible to remove all plots from the Plots pane using code, sorry.
With the bokeh package, I created a graph visualization and with show(plot) the output is shown in Jupyter but also at the same time a new tab in the browser is opened with the output. I only want to plot it in a Jupyter cell without opening the plot as a new html file. Is this somehow possible?
#Booketh plot
output_file("thisisaplot.html")
show(plot)
According to the documentation, you should be able to do that by calling output_notebook() before calling show().
Note: As pointed out by #bigreddot, if you were using output_file in the kernel, changing to output_notebook may not take place right away. You will need to either call reset_output(), or restart your kernel for the change to take place.
I want to show plots in a separate window. Currently I have the IPython graphics backend set to "automatic".
When I re-run the code (or plot another figure), Spyder opens a new plot window. Is it possible to refresh the figure in the window that is already opened instead of opening a new one?
The GUI window that opens when you call plt.show() is bound to a figure. You cannot change the figure inside it. (Well, to be precise, there might be an option of obtaining a handle from the operating system and manipulating its content, but I assume this is not worth the effort.)
Re-running the code actually means that you produce a new figure since the code does not know that it's been run before.
So, exchanging the figure or reusing the window to plot a different figure is not possible.
What is possible however is to use the figure and manipulate the figure while it's open. This is done via plt.ion(). After calling this command in IPython you can adapt the figure, e.g. adding new lines to it etc.
See this example:
At IN [6] the window opens and when IN [7] is executed, the figure stays open and the content changes.
Sure, it is possible with Spyder while in the same running kernel. Try the following example using num as parameter to plt.figure(), where num will always refer to the same figure and refresh it if already opened. Also works with plt.subplots().
import matplotlib.pyplot as plt
from scipy import *
t = linspace(0, 0.1,1000)
w = rand(1)*60*2*pi
fig = plt.figure(num=10, clear=True, figsize = [10,8])
plt.plot(t,cos(w*t))
plt.plot(t,cos(w*t-2*pi/3))
plt.plot(t,cos(w*t-4*pi/3))
I'm getting the error
QPixmap: It is not safe to use pixmaps outside the GUI thread
when manually entering the following statements in Seaborn in the ipython-shell using PyDev in Eclipse:
import matplotlib.pyplot as mpl
import seaborn as sns
import pandas as pd
import numpy as np
# Turn interactive mode off:
mpl.ioff()
# Create some example Data:
df = pd.DataFrame({'A':np.random.rand(20),'B':np.random.rand(20)})
# Create seaborn PairGrid instance:
pg = sns.PairGrid(df)
At this point when I continue the last statement with a dot to e.g. chain a map()-method, like this:
pg = sns.PairGrid(df).
then Eclipse is trying to show a popup of all possible completions but that popup is immediatly getting closed and the console is getting filled with the aforementioned error, 42 lines of it to be precise.
I can continue and do this without problem:
gp = sns.PairGrid(df).map(mpl.scatter)
gp.fig.show()
And I get my plot just fine.
The same happens when doing sns.JointGrid(df.A,df.B). and sns.FacetGrid(df).
While playing around earlier I also got into situations where the console was actually killed by this error, I just can't replicate the steps that lead to this anymore.
Researching on this site it looked like it has to do with threading which I'm not using at all. Does Seaborn use it?
I want to create my plots by first creating a Grid/Figure and doing the plotting later, but this error suggests that this isn't a safe way to do things though the Seaborn doc says it's fine to do it like that:
https://seaborn.github.io/generated/seaborn.FacetGrid.html
EDIT:
When doing the same thing in Spyder I'm not getting the error but this warning when doing gp.fig.show():
C:\Anaconda2\lib\site-packages\matplotlib\figure.py:397: UserWarning:
matplotlib is currently using a non-GUI backend, so cannot show the figure
"matplotlib is currently using a non-GUI backend, "
When interactive mode is off I'm not seeing any graphic. With interactive mode on I'm still seeing the warning but get the graphic inline.
No popup in either case though. In Eclipse I'm getting both the error and the popup.
EDIT 2:
Running the whole thing as a script in Eclipse does not produce any error, only the manual entering like described above does.
I took a look at https://github.com/fabioz/Pydev/blob/master/plugins/org.python.pydev/pysrc/pydevconsole.py and the issue is that the code-completion on PyDev is being triggered in a secondary thread, not in the main (UI) thread.
I.e.: the code completion in the interactive console is not expecting that it'll touch code that'll actually interact with the gui.
For this to work, the completion command has to be queued for the main thread (as the regular commands are queued) and the thread has to wait for it to finish to then return its value.
Please report this as an issue in the PyDev tracker: https://www.brainwy.com/tracker/PyDev/ (i.e.: code-completion in the interactive console should happen in the UI thread).