ipywidgets interact: set the framerate? - python

I have an ipywidgets.interact slider bar on a long-ish running process. This creates a situation where, when I move the slider bar, several values get buffered and I sit and wait for a while for the output to "catch up" to the point to which I've moved the slider bar. I'd like to set the number of values that get buffered when I use the slider bar.
Example:
from ipywidgets import interact
import matplotlib.pyplot as plt
import cv2
from skimage import io
image = io.imread('https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikipedia-logo-v2.png')
#interact
def edges(low=100, high=150, aperture=3):
plt.imshow(cv2.Canny(image, low, high, apertureSize=aperture))
Try moving the slider around and watch the image continue updating for a while after you stop. I'm on a laptop, so your mileage may vary if you have a beast of a machine.
How can I set the "framerate" to the interact function?

The continuous_update setting is what you want to disable for the sliders. However, I'm not 100% sure you can use it with the simple decorator approach though? Did you try this:
from ipywidgets import interact
import matplotlib.pyplot as plt
import cv2
from skimage import io
image = io.imread('https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikipedia-logo-v2.png')
#interact(continuous_update=False)
def edges(low=100, high=150, aperture=3):
plt.imshow(cv2.Canny(image, low, high, apertureSize=aperture))
I tried it and it works without saying there is an issue with the #interact(continuous_update=False) line. However, I'm not seeing it be slow without it, and so it is hard to test it is having the desired effect.
It is available for your sliders for sure if you define them yourself and not use the #interact route to handle giving you the sliders automatically.

Related

Displaying Dash plot without using Web

I have a large dataset of around 500 parquet files with about 42 million samples.
In order to read those files I'm using Dask which does a great job.
In order to display them, I downsampled the Dask DataFrame in the most basic way (something like dd[::200]) and plotted it using Plotly.
So far everything works great.
Now, I had like to have an interactive figure on one side but I don't want it to open a web tab/to use jupyter/anything of this kind. I just want it to create a figure as matplotlib does.
In order to do so, I found a great solution that uses QWebEngineView:
plotly: how to make a standalone plot in a window?
My simplified code looks something like this:
import dask.dataframe as dd
import time
import plotly.graph_objects as go
def show_in_window(fig):
import sys, os
import plotly.offline
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication
plotly.offline.plot(fig, filename='temp.html', auto_open=False)
app = QApplication(sys.argv)
web = QWebEngineView()
file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "temp.html"))
web.load(QUrl.fromLocalFile(file_path))
web.show()
sys.exit(app.exec_())
def create_plot(df,x_param,y_param):
fig.add_trace(go.Scattergl(x = df[x_param] , y = df[y_param], mode ='markers'))
fig = go.Figure()
ddf = dd.read_parquet("results_parq/*.parquet")
create_data_for_plot(ddf,'t','reg',1)
fig.update_layout(showlegend=False)
show_in_window(fig)
QUESTION:
Since the dataset is large and I want to use a smarter downsample method, I would like to use a library called plotly-resampler (https://predict-idlab.github.io/plotly-resampler/getting_started.html#how-to-use) which dynamically changes the amount of samples based on the zooming level. However, it uses Dash.
I thought to do something like:
fig = FigureResampler(go.Figure())
ddf = dd.read_parquet("results_parq/*.parquet")
create_data_for_plot(ddf,'t','reg',1)
show_in_window(fig)
This creates a plot with the smart resample but it does not change its resampling when the zoom changes (it basically stuck on its initial sampling).
Is there any solution that might give me a Dash figure in a separate window instead of a tab and yet to have the functionalities of Dash?
Thank you
I believe you could store it in a local file, then use the code
import webbrowser
new = 2 # open in a new window, if possible
// open an HTML file on my own (Windows) computer
url = "file://d/testdata.html"
webbrowser.open(url,new=new)
to open it in a new window

How to use multiple themes for multiple matplotlib imports

I am importing multiple matplotlib as names within my python program and would like to use different styles for different plots.
However when i change the style for one plot (say : dark_background) it changes the style for all other plots as well.
suggestions shall be appreciated
Current import is something like this :
import matplotlib.pyplot as plt_surfacegt
import matplotlib.pyplot as plt_mascon
import matplotlib.pyplot as plt_gravmod
import matplotlib.pyplot as plt_realtime
plt_realtime.style.use('dark_background')
it should only change the theme for plt_realtime to dark however all others are changed to dark as well.!
I cannot exactly explain why this wouldn't work, but it seems to me a crazy idea to achieve your desired result.
Instead, I think you should use matplotlib's context manager to change the style sheet on a per-plot basis. Something like (from the link):
with plt.style.context('dark_background'):
plt.plot(np.sin(np.linspace(0, 2 * np.pi)), 'r-o')
plt.show()

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)

Close pyplot figure using the keyboard on Mac OS X

Is there a way to close a pyplot figure in OS X using the keyboard (as far as I can see you can only close it by clicking the window close button)?
I tried many key combinations like command-Q, command-W, and similar, but none of them appear to work on my system.
I also tried this code posted here:
#!/usr/bin/env python
import matplotlib.pyplot as plt
plt.plot(range(10))
def quit_figure(event):
if event.key == 'q':
plt.close(event.canvas.figure)
cid = plt.gcf().canvas.mpl_connect('key_press_event', quit_figure)
plt.show()
However, the above doesn't work on OS X either. I tried adding print statements to quit_figure, but it seems like it's never called.
I'm trying this on the latest public OS X, matplotlib version 1.1.1, and the standard Python that comes with OS X (2.7.3). Any ideas on how to fix this? It's very annoying to have to reach for the mouse every time.
This is definitely a bug in the default OS X backend used by pyplot. Adding the following two lines at the top of the file switches to a different backend that works for me, if this helps anyone else.
import matplotlib
matplotlib.use('TKAgg')
I got around this by replacing
plt.show()
with
plt.show(block=False)
input("Hit Enter To Close")
plt.close()
A hack at its best, but I hope that helps someone
use interactive mode:
import matplotlib.pyplot as plt
# Enable interactive mode:
plt.ion()
# Make your plot: No need to call plt.show() in interactive mode
plt.plot(range(10))
# Close the active plot:
plt.close()
# Plots can also be closed via plt.close('all') to close all open plots or
# plt.close(figure_name) for named figures.
Checkout the "What is interactive mode?" section in this documentation
Interactive mode can be turned off at any point with plt.ioff()
When you have focus in the matplotlib window, the official keyboard shortcut is ctrl-W by this:
http://matplotlib.org/1.2.1/users/navigation_toolbar.html
As this is a very un-Mac way to do things, it is actually cmd-W. Not so easy to guess, is it?
If you are using an interactive shell, you can also close the window programmatically. See:
When to use cla(), clf() or close() for clearing a plot in matplotlib?
So, if you use pylab or equivalent (everything in the same namespace), it is just close(fig). If you are loading the libraries manually, you need to take close from the right namespace, for example:
import matplotlib.pyplot as plt
fig = plt.figure()
plt.plot([0,1,2],[0,1,0],'r')
fig.show()
plt.close(fig)
The only catch here is that there is no such thing as fig.close even though one would expect. On the other hand, you can use plt.close('all') to regain your desktop.

Python - matplotlib.pyplot.imshow won't work in a if//while

I'm trying to display an image (a N*P numpy array) in a while loop with imshow but it doesn't seem to work.
When I just use "plt.imshow(image,cmap='gray')" with no indent it works perfectly.
However, when I try to use it from a while loop like
continue=True
while continue:
plt.imshow(image,cmap='gray')
continue=input()
or
i=0
while i<10:
plt.imshow(image,cmap='gray')
i+=1
the pyplot window just freeze and python crash (same problem with a if).
I don't understand why it does this, does anybody here knows? Thanks alot in advance :)
EDIT : I try to use it like this in my program
import matplotlib.pyplot as plt
import numpy as np
import PIL.Image as im
image=np.array(im.open("Blabla.jpg").convert('L')).astype(np.float32)
plt.imshow(image,cmap='gray') #This works -> ONLY when there is not a while after
keepGoin = True #But this doesn't
while keepGoin:
plt.imshow(image,cmap='gray')
keepGoin=input()
EDIT 2 :
I made a mistake : it seems that imshow pauses when a while//if is used, even if the while loop is right after the imshow. And when the while loop ends, an image is finally displayed. Maybe using this kind of loop simply pauses the process ?
So I tried to use a secondary function aiming to display the image "out" of the while but it doesn't work either, the result is the same : the pyplot window freeze during the while loop, and the image is displayed right after the loop ends.
EDIT 3 :
So after some more tries, I am pretty sure the problem is not calling imshow from a while but the fact that the loop pauses the execution of pyplot, even if it is called BEFORE the loop (If I call imshow and then use a loop, the pyplot window freeze until the loop ends)
According to some new research I've made, plt.pause could help me but I've an error when I try this.
Here are some observations which might help you debug. The code and statements below only apply to Python 2.x.
Using the code below, you would have to type the word True or False on the console from which you started the program, for it to not crash after the first showing, because input() expects some sort of input and throws EOF if you do not give it anything.
import matplotlib.pyplot as plt
import numpy as np
import PIL.Image as im
image=np.array(im.open("Blabla.jpg").convert('L')).astype(np.float32)
plt.ion()
plt.imshow(image,cmap='gray')
keepGoin = True #But this doesn't
while keepGoin:
plt.imshow(image,cmap='gray')
keepGoin=input()
If you change it to raw_input, it is more forgiving in terms of not crashing with EOF but will still terminate unless you give it some input. However, changing the loop to be independent of the input paused it for me until I pushed Enter on the terminal.
while True:
plt.imshow(image,cmap='gray')
raw_input()
If you are using a Spider the easier way is configure to show the image in console because in the console the image not freeze.
To configure the spider to show the image on console:
preferences -> python console -> graphics -> output graphic -> here: choice inline instead of automatic

Categories