Download SVG of plot from `%matplotlib widget` in Jupyter? - python

Say, I have a code like this in a Jupyter notebook (like in Controlling order of display in ipywidgets Vbox (when matplotlib widget is used)?):
import IPython.display
from IPython.display import display
from ipywidgets import widgets, Layout
%matplotlib widget
import matplotlib as mpl
import matplotlib.pyplot as plt
widget_out = widgets.Output(layout=Layout(width='100%'))
with widget_out:
widget_out.clear_output(wait=True)
plt.ioff() # "turn off interactive mode so figure doesn't show"
fig = plt.figure(figsize=(10,1), dpi=90)
ax = fig.add_subplot(111)
ax.plot([0,1,2], [0,1,2])
plt.ion() # "figure still doesn't show"
display(fig.canvas) # "It's the canvas attribute that is the interactive widget, not the figure"
myvbox = widgets.VBox([
widget_out,
],)
display(myvbox)
It results with a rendering like this:
Now, when I click the "Download plot" button, I immediately get a download dialog for a "Figure 1.png" file:
..., and there is no obvious option I could change, so I could obtain a different format - and here I'd want .svg.
When I use the usual Matplotlib from Python on dekstop however, and I click the "Save the figure" button there, there is actually a picker for file formats:
... and .svg is there.
Is there a way to persuade %matplotlib widget inside Jupyter to "save as" .svg (or other vector format), instead of .png?

Related

IPython interactive widget is not updating plotly when downloaded as html

I'm using Jupyter Notebook and trying to create an interactive plot. I really like how simple the ipywidgets.interactive is to use and having the ability to lay things out in VBox or HBox. The problem I'm having is once I download as html the ipywidgets.interactive is not updating my plot.
Here is what I have:
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
import plotly.graph_objs as go
import plotly.offline as py
import numpy as np
from IPython.display import display
py.init_notebook_mode()
xs = np.linspace(0,6,100)
ys = np.sin(xs)
scatter = go.Scatter(
x = xs,
y = ys
)
data = [scatter]
layout = go.Layout(title='test')
fig = go.FigureWidget(data=data, layout=layout)
slider = widgets.FloatRangeSlider(
min=1,
max=6,
step=.1,
description='desc'
)
def update_b(b):
fig.data[0].y = np.sin(xs+b)
vb = widgets.VBox((fig, interactive(update_b, b=(1, 6, .1))))
vb.layout.align_items='center'
# This displays it and allows it to be interactive, but only when I have it as .ipynb,
# not when I download as html
display(vb)
The way I am saving as html is:
1. Widgets > Save Notebook Widget State
2. From cmd: jupyter nbconvert --to html test_plot.ipynb
I have also done the following to enable the widget extension:
jupyter nbextension enable --py widgetsnbextension
Enabling notebook extension jupyter-js-widgets/extension...
- Validating: ok
After everything this is what I get:
The thing is the slider is movable but it does not update the graph. The graph is also able to be manipulated through zoom, etc. like normal with plotly. This leads me to believe there is something wrong with the way I've used interactive.
Any ideas?
Unfortunately this does not work this way, the function that links the slider with the plot is written in python and executes in the python kernel, so when you convert to a static html this function does not exist anymore.
I am not aware of some kind of python to javascript translator that allows these kind of functions to run without a python kernel, although plotly's Dash seems to be doing something in this line (see this issue). If you can put up a server you can use Voila or something similar to make the notebook look like a web page.
I'm not using plotly, however, try adding some line magic, like "widget" which makes the graph interactive...
%matplotlib widget
%matplotlib widget
from ipywidgets import *
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
line, = ax.plot(x, np.sin(x))
def update(w = 1.0):
line.set_ydata(np.sin(w * x))
fig.canvas.draw()
interact(update);
screenshot of notebook

Jupyter Notebook: duplicated scatter plot using when using ipywidgets

I'm trying to control the display of a scatter plot with a checkbox. When I built it using the interact function it worked as expected. The plot was shown or hidden based on the value in the checkbox.
import matplotlib.pyplot as plt
from ipywidgets import interact, widgets
%matplotlib inline
def on_change(Display):
if Display == True:
plt.scatter(x,y)
plt.show()
return Display
interact(on_change, Display=False);
When I tried to do the same thing using the observe function every time I clicked on the checkbox I get an additional plot displayed below. What do I need to do to get it to redraw the same plot so it works like the example above?
I suppose something in the interact example is clearing the display but it's not clear how to do this manually.
import matplotlib.pyplot as plt
from ipywidgets import interact, widgets
%matplotlib inline
x = [1,2,3,4,5,6,7,8]
y = [5,2,4,2,1,4,5,2]
def on_change(change):
if change['new'] == True:
scat = plt.scatter(x,y)
plt.show()
cb = widgets.Checkbox(False, description = "Display")
cb.observe(on_change, names='value')
display(cb)
A couple of alterations I made to your example to hopefully demonstrate what you want. I have taken a more object-oriented route, not sure if you specifically wanted to avoid it but it helps achieve your desired outcome, it seems like you are moving towards a simple GUI here.
1) Include an Output widget (out) - basically a cell output which you can display like a normal widget. You can use a context manager block (with out:) when you want to print to that specific output widget. You can also clear the widget with out.clear_output()
2) Use the object oriented interface in matplotlib rather than using plt. I find this easier to control which plots are displayed and in which location at the right times.
temporarily suspend the interactive matplotlib with plt.ioff()
Create your figure and axis with fig, ax = plt.subplots(). NB figures can have multiple axes/subplots but we only need one.
'plot' the scatter data to your axis using ax.scatter(x,y), but this won't cause it to appear.
Explicitly display the figure with display(fig).
I'm assuming you want your figure to be replotted each time you check the box, so I have included it in the observe function. If your figure doesn't change, it would make sense to move it outside of the loop.
import matplotlib.pyplot as plt
from ipywidgets import interact, widgets
%matplotlib inline
out = widgets.Output()
x = [1,2,3,4,5,6,7,8]
y = [5,2,4,2,1,4,5,2]
def on_change(change):
if change['new'] == True:
with out:
plt.ioff()
fig,ax = plt.subplots()
ax.scatter(x,y)
display(fig)
else:
out.clear_output()
cb = widgets.Checkbox(False, description = "Display")
cb.observe(on_change, names='value')
display(cb)
display(out)

jupyter matplotlib interactive exit

I have plotted an interactive figure, run the cell, and now all my keyboard presses are being captured by the interactive plot. How do I exist this without the mouse?
Shift-enter sort of works, but it seems to require there be a cell below the plot.
I think matplotlib recommends ctrl-w but as I am in a web browser (Jupyter) that would just close my tab.
The plot is within the cell.
%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
fig,ax = plt.subplots(1,1)
x = np.linspace(0, 1, 100)
y = np.random.random(size=(100, 1))
ax.plot(x, y)
If you run this, you can't then use j,k to move up and down cells until you exit the interactive plot.
This is just a code snippet, in the actual code I am updating the plot from within a loop which is why I'm using interactive mode.
You can add another short-key to close the plot. This can be accomplished via the rcParams.
So let's say you want to close the plot by pressing q.
%matplotlib notebook
import matplotlib.pyplot as plt
plt.rcParams["keymap.quit"] = "ctrl+w", "cmd+w", "q"
plt.plot([1,3,2])
Now pressing q will exit the interactive plot, such that you can navigate as usual through the notebook. E.g. to then get to the next cell, which would already be active, just press Enter.
Eventually you would probably want to change your matplotlib rc file with this option not to have to type it in every time you start a notebook.

Cursor location and pixel value in a Jupyter notebook inline image

I am using Python 2.7.x with a Jupyter Notebook, matplotlib and %pylab backend with the inline flag
%pylab inline
to print images below active cells. I would like to be able to move my cursor over an image and know it's location and pixel value An example could be:
(x,y,val) = (123,285,230)
but I am not particular about any of the specifics of this example.
The %matplotlib inline backend displays the plot outputs as png images. It may be possible to write some JavaScript for the Jupyter notebook to obtain the color and pixel on mouse over an image in the cell output.
However it may be much easier to just use the %matplotlib notebook backend, which keeps the matplotlib figure alive when plotting it to the output and therefore the usual built-in mouseover functionality is readily available.
Note the picker in the lower right corner of the image, which displays x,y and the value of the current pixel.
To expand on ImportanceOfBeingErnest's answer, you can use mpl_connect to provide a callback on your clicks and ipywidgets to show an output of your callback. If needed, you can break up the code in different cells.
%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
import ipywidgets as wdg # Using the ipython notebook widgets
# Create a random image
a = np.random.poisson(size=(12,15))
fig = plt.figure()
plt.imshow(a)
# Create and display textarea widget
txt = wdg.Textarea(
value='',
placeholder='',
description='event:',
disabled=False
)
display(txt)
# Define a callback function that will update the textarea
def onclick(event):
txt.value = str(event) # Dynamically update the text box above
# Create an hard reference to the callback not to be cleared by the garbage collector
ka = fig.canvas.mpl_connect('button_press_event', onclick)

set IPython Notebook inline plots background not transparent

In IPython Notebook 3, when I use the Inline matplotlib backend, the png figures in the browser have a transparent background.
How do I set it to white instead?
Minimal example:
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot([1,2])
Right click and save the image, the image has a transparent background, I would like it to be white instead.
Update
Tried to set figure.facecolor in matplotlibrc but it still displays a transparent png:
import matplotlib
print("facecolor before:")
print(matplotlib.rcParams["figure.facecolor"])
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot([1,2])
print("facecolor after:")
print(matplotlib.rcParams["figure.facecolor"])
This code gives as output:
facecolor before:
1.0
facecolor after:
(1, 1, 1, 0)
Assuming the area that was transparent is everything surrounding the ax (subplot) you can try this:
%matplotlib inline
import matplotlib.pyplot as plt
fig, ax = plt.subplots(facecolor='w')
ax.plot([1,2])
If you want to have white background in figures permanently you need to modify you matplotlibrc file (located in your home folder under .matplotlib\) changing these parameters:
figure.facecolor = 1
But you can always save you figure automatically with any background you want (independent from what it was when the figure was created) by passing facecolor:
fig.savefig('filename.png', facecolor='w', transparent=False)
Another option, instead of setting facecolor, is to use the seaborn package.
Just run:
import seaborn as sns
it automatically sets the plot background and also gives better default colors for matplotlib.

Categories