I've written a python module and would like to make some of the functions available via a jupyter notebook. For this I would like to visualise (plot) the functions. The notebook should be interactive, i.e. the user can change inputs and gets the corresponding result / plot back.
I've tried to make a use case work as I've never used jupyter before. I followed this. Here is the code from their site:
%matplotlib inline
from ipywidgets import interact
import matplotlib.pyplot as plt
import numpy as np
def f(m, b):
plt.figure(2)
x = np.linspace(-10, 10, num=1000)
plt.plot(x, m * x + b)
plt.ylim(-5, 5)
plt.show()
interactive_plot = interactive(f, m=(-2.0, 2.0), b=(-3, 3, 0.5))
output = interactive_plot.children[-1]
output.layout.height = '350px'
interactive_plot
locally everything is working fine. As soon as I upload it to github and want to show it on nbviewer (can be found here) the interactive sliders don't work. What am I doing wrong?
Is there a restriction for this on the python version?
Related
I have a python program (not a notebook, a python file) where I produce several plots that show up one after the other. The program looks something like this:
import numpy as np
import matplotlib.pyplot as plt
functions = [np.sin, np.cos, np.abs, np.square]
x = np.linspace(-np.pi, np.pi, 100)
for func in functions:
plt.plot(x, func(x))
plt.show()
When I run the program in vscode I have to close one plot before the next one opens. The windows with the plots open at different locations every time and it would be more convenient if the X button was at the same place every time so i can click through them more easily. Is there a way to do this?
I solved it like this:
import numpy as np
import matplotlib.pyplot as plt
from pylab import get_current_fig_manager
functions = [np.sin, np.cos, np.abs, np.square]
x = np.linspace(-np.pi, np.pi, 100)
for func in functions:
thismanager = get_current_fig_manager()
thismanager.window.wm_geometry("+500+0")
plt.plot(x, func(x))
plt.show()
Like on this webpage: https://pyquestions.com/how-do-you-set-the-absolute-position-of-figure-windows-with-matplotlib
or as answered here: How do you set the absolute position of figure windows with matplotlib?.
I thought it was a vscode issue but everything is done by matplotlib. If anyone knows a more permanent solution, please let me know, as setting this for every plot is quite annoying.
I want to draw a line in a Jupyter notebook, which can be moved using an ipywidget slider. I also want to have the mouse coordinates displayed, for which I'm using %matplotlib notebook. Here is what I have so far :
%matplotlib notebook
from ipywidgets import interact
fig, ax = plt.subplots()
#interact(n=(-200, 0))
def show(n):
# fig.clear() #doesn't show anything
y = -n+x
ax.plot(x, y)
plt.show()
When moving the line using the slider, the plot doesn't refresh, all previous positions of the line
remain visible:
I tried to refresh using fig.clear(), but then noting shows.
How can I solve this?
I have an extensive answer about this here: Matplotlib figure is not updating with ipywidgets slider
but the short of my recommendations are:
use ipympl %matplotlib ipympl instead of notebook as this will play nicer with ipywidgets
Use mpl-interactions to handle making plots controlled by sliders.
It will do the optimal thing of using set_data for you rather than clearing and replotting the lines.
It also interprets the shorthand for numbers in a way that (I think) makes more sense when making plots (e.g. using linspace instead of arange) see https://mpl-interactions.readthedocs.io/en/stable/comparison.html for more details.
So for your example I recommend doing:
install libraries
pip install ipympl mpl-interactions
%matplotlib ipympl
from ipywidgets import interact
import matplotlib.pyplot as plt
from mpl_interactions import ipyplot as iplt
x = np.linspace(0,100)
fig, ax = plt.subplots()
def y(x, n):
return x - n
ctrls = iplt.plot(x, y, n=(-200,0))
it got a bit longer because I added the imports you left out of your question and also defined x.
Which gives you this:
That said if you don't want to use those I think what you want is ax.cla() I think when you do fig.clear you are also removing the axes which is why nothing shows up.
%matplotlib notebook
from ipywidgets import interact
fig, ax = plt.subplots()
#interact(n=(-200, 0))
def show(n):
y = -n+x
ax.cla()
ax.plot(x, y)
plt.show()
According to
https://www.geeksforgeeks.org/matplotlib-pyplot-ginput-in-python/ the ginput function in Python is given by the following code:
%matplotlib widget
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(10)
plt.plot(t, np.sin(t))
plt.title('matplotlib.pyplot.ginput()\
function Example', fontweight ="bold")
print("After 3 clicks :")
x = plt.ginput(3)
print(x)
plt.show()
The only modification for jupyterlab that I inserted is the magic function
%matplotlib widget
at the beginning of the script. However, I do not get ginput() to work in Jupyterlab. It does not yield any errors, just no Figure appears, where I could click with the mouse. The output of ginput() accordingly is empty. In other Python IDE's, it works flawlessly (e.g. Thonny).
Did anybody get the ginput() function to work in Jupyterlab?
So, I've been using R Markdown extensively lastly, and I'm pretty satisfied with what it can do.
However, I'm having a problem with python plots. I have a chunk of python code where I plot multiple figures in python.
When I do that with R, RStudio will display all the plots generated in this chunk side by side inline.
Unfortunately, when doing the same with a chunk of python code, RStudio opens a new Window where it displays the plot, then the code execution is halted until I close that window, then it plots the next figure, I have to close it again, etc etc.
Is there a possibility to force RStudio to put the figures inline, and then continue code execution?
Thanks for your help in advance!
To expand on my earlier comment, I will elaborate with a complete answer. When using matplotlib, the plots are rendered using Qt, which is why you are getting popup windows.
If we use fig.savefig instead of pyplot.show and then pyplot.close we can avoid the popup windows. Here is a minimal example:
---
output: html_document
---
## Python *pyplot*
```{python pyplot, echo=FALSE}
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)
fig, ax = plt.subplots()
ax.plot(t, s)
ax.set(xlabel='time (s)', ylabel='voltage (mV)',
title='About as simple as it gets, folks')
ax.grid()
fig.savefig("pyplot.png")
plt.close(fig)
```
```{r, echo=FALSE}
knitr::include_graphics("pyplot.png")
```
Which produces the following without any process interruption:
Source: matplotlib.org
N.B. According the the release notes for RStudio v1.2.679-1 Preview, this version will show matplotlib plots emitted by Python chunks.
Update
Using the latest preview release mentioned above, updating the chunk to use pyplot.show will now display inline as desired.
```{python pyplot, echo=FALSE}
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)
fig, ax = plt.subplots()
ax.plot(t, s)
ax.set(xlabel='time (s)', ylabel='voltage (mV)',
title='About as simple as it gets, folks')
ax.grid()
plt.show()
```
For Anaconda users
If you use Anaconda as your python distribution, you may experience a problem where Qt is not found from RStudio due to problem with missing path/environment variable.
The error will appear similar to:
This application failed to start because it could not find or load the Qt platform plugin "windows" in "", Reinstalling the application may fix this problem.
A quick fix is to add the following to a python chunk to setup an environment variable.
import os
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = '/path/to/Anaconda3/Library/plugins/platforms'
Replacing /path/to with the relevant location to your Anaconda distribution.
I am wondering if there is a way to change the pixel density/resolution of sympy plots. For example, let's consider the simple code snippet below:
import sympy as syp
x = syp.Symbol('x')
miles_to_km = x * 1.609344
miles_to_km.evalf()
graph = syp.plot(miles_to_km, show=False)
graph.save('./figures/miles_to_km.png')
graph.show()
Notes:
When I tried using graph.savefig, I got an AttributeError: 'Plot' object has no attribute 'saveimage' I stumbled upon the saveimage method in some online resource, and it sounded like that this was the common approach -- I guess the API changed?
graph.save('./figures/miles_to_km.png', dpi=300) produces a type error: TypeError: save() got an unexpected keyword argument 'dpi'
Using the dpi attribute in plot does not throw any error but doesn't affect the image quality either: graph = syp.plot(miles_to_km, dpi=300, show=False)
I also tried using the matplotlib backend:
plt.figure()
graph = syp.plot(miles_to_km, show=False)
#graph.save('./figures/miles_to_km.png')
plt.savefig('./figures/miles_to_km.png')
graph.show()
where plt = matplotlib.pyplot. However, the canvas is blank. Also relevant info may be that I am running it in an IPython notebook with %matplotlib inline enabled.
I am using SymPy v. 0.7.6
the backend workaround below shows the plot in the IPython notebook, but it also produces a white canvas (as png)
graph = syp.plot(miles_to_km, show=False)
backend = graph.backend(graph)
backend.fig.savefig('ch01_2.png', dpi=300)
backend.show()
EDIT and Solution:
Thanks to Cody Piersall's answer the issue is now resolved. I updated to IPython 4.0 (Jupyter notebook) and plotted it as follows
graph = syp.plot(miles_to_km, show=False)
backend = graph.backend(graph)
backend.process_series()
backend.fig.savefig('miles_to_km.png', dpi=300)
backend.show()
This problem has been fixed, you can now simply use this:
graph = sympy.plot(f, show = False)
graph.save('fig.png')
Unfortunately, it doesn't seem to allow for the selection of a dpi.
Assuming you are using the matplotlib backend, which is the default if you have matplotlib installed, you just have to import matplotlib.pyplot and use pyplot.savefig.
This works because sympy uses matplotlib to do its plotting, and since matplotlib is stateful, it knows which plot you're working with.
Here is your example, but using savefig to save to a png.
import sympy as syp
x = syp.Symbol('x')
miles_to_km = x * 1.609344
miles_to_km.evalf()
graph = syp.plot(miles_to_km, show=False)
# Does not work in IPython Notebook, but works in a script.
import matplotlib.pyplot as plt
plt.savefig('./figures/miles_to_km.png', dpi=300)
If you are in an IPython notebook, the above will not work, but you can still save them with a specified dpi. You just have to be a little tricky about it.
# works in IPython Notebook
backend = graph.backend(graph)
ackend.fig.savefig('300.png', dpi=300)
backend.fig.savefig('20.png', dpi=20)