Using on_trait_change in ipython notebook widgets - jupyter-notebook

I'm trying to use the IntSlider widget in IPython.html.widgets, and I want to call a function whenever the slider value changes. Additionally, I want to pass multiple arguments into the function. I was able to use on_trait_change() to call a function but have no idea how to pass arguments:
def somefn(parameter1, parameter2):
print (parameter1, parameter2)
slider = widgets.IntSlider(min=0,max=3,step=1)
slider.on_trait_change(somefn)

I would suggest using a partial.
from IPython.display import display
import ipywidgets as widgets
def somefn(parameter1,my_arg):
print ("parameter1: {}".format(parameter1))
print ("my_arg: {}".format(my_arg))
from functools import partial
somefn_arg_0 = partial(somefn, my_arg=0)
slider = widgets.IntSlider(min=0,max=3,step=1)
slider.observe(somefn_arg_0)
display(slider)
Note I have replaced the deprecated on_trait_change with observe.

Related

PySide2 UI Maya Find object names that contain specific names

I want to include in the argument an object name that contains a specific name from the ui file.
I have created pickers in QtDesigner and have imported them for Maya 2022.
It assigned a command to each button. But I realized I needed a huge number of commands.
It's just this scene.
from PySide2 import QtWidgets
from PySide2 import QtGui
from PySide2 import QtCore
from PySide2.QtUiTools import QUiLoader
from maya.app.general.mayaMixin import MayaQWidgetBaseMixin
import shiboken2 as shiboken
UIFILEPATH = 'D:/MAYA/pyside_pick/ui/PicsTest5.ui'
class MainWindow(MayaQWidgetBaseMixin,QtWidgets.QMainWindow):
def __init__(self,parent=None):
super(MainWindow,self).__init__(parent)
self.UI = QUiLoader().load(UIFILEPATH)
self.setWindowTitle(self.UI.windowTitle())
self.setCentralWidget(self.UI)
#PushButton
self.UI.pushButton_sphere.clicked.connect(self.PushedCmd)
#Comand
def PushedCmd(self):
bTEXT = str(self.UI.pushButton_sphere.text())
cmds.select('pSphere1')
print(bTEXT)
def main():
window = MainWindow()
window.show()
if __name__ == '__main__':
main()
If it is given an object name like above, it certainly works.
But there are commands that need to be directed only to objects containing "pushButton_".
I tried like this
button1 = self.findChild(QtWidgets.QPushButton, 'pushButton_*')
self.button1.clicked.connect(self.testPrint)
def testPrint(self):
print(self.button1)
I meant to define button1 as a QPushButton containing 'pushButton _' and print its name when clicked.
Unfortunately, I learned that asterisks can not be used as searches.
Then, I tried like this
button1 = self.findChild(QtWidgets.QPushButton, 'pushButton_sphere')
self.button1.clicked.connect(self.testPrint)
def testPrint(self):
print(self.button1)
The result was written as (PySide2.QtWidgets.QPushButton)already deleted.
This is probably rudimentary, but being Jap I couldn't find a workable solution.
Tell me how to output the object name when I press the button, please.
Also tell me if the notation is wrong.

How to use three different tkinter buttons with one command

Please house help. When using tkinter, I find it difficult to call a defined function in a button when the def is below the button. I use python 3.6.9. Example
import tkinter
window = tkinter.Tk
button = tkinter.Button(window, text="hello",command=newpage()).grid(column=0, row=0)
def newpage():
new = tkinter.toplevel()
The button does not work except I use lambda and also the lambda does not work if I define something new under the button. The new definition blocks the lambda from seeing the other def.
NB: I use the lambda like this lambda:newpage()
NB: I use python 3.6.9
Also please how can I make many tkinter buttons to use the same command (as in def)
The newpage function should really be defined before being used, just as a good programming practice if for no other reason.
The variable window is being set to tkinter.Tk instead of the object returned by tkinter.Tk().
The button is calling the function immediately because command expects a function to run, and thinks you want it to run something returned by newpage, instead remove the () command=newpage.
Toplevel is capitalized, tkinter.Toplevel().
A function can be used by any button, just assign the command to use the function:
import tkinter
def newpage():
new = tkinter.Toplevel()
window = tkinter.Tk()
button1 = tkinter.Button(window,
text="hello1",
command=newpage).grid(column=0, row=0)
button2 = tkinter.Button(window,
text="hello2",
command=newpage).grid(column=0, row=1)
button3 = tkinter.Button(window,
text="hello3",
command=newpage).grid(column=0, row=2)

ipywidgets dropdown widgets: what is the onchange event?

I can register a handler to button.on_click in ipython notebook widgets, but I don't know how to do the same for a dropdown widget
import ipywidgets as widgets
from IPython.display import display
def on_button_clicked(b):
print("Button clicked.")
button = widgets.Button(description="Click Me!")
display(button)
button.on_click(on_button_clicked)
But for
choose_task = widgets.Dropdown(
options=['Addition', 'Multiplication', 'Subtraction'],
value='Addition',
description='Task:',
)
there seems to be only
on_trait_change(...)
if I register a handler with this, can I use it to access the value of the widget?
I have seen examples with the handler and the widget belong to a subclass, and the handler can use self to introspect. But if I don't want to use a subclass, how does the handler know what widget was the target of the event.?
Between this link and the traitlet docs on github and just playing around, I finally figured this out:
w = widgets.Dropdown(
options=['Addition', 'Multiplication', 'Subtraction', 'Division'],
value='Addition',
description='Task:',
)
def on_change(change):
if change['type'] == 'change' and change['name'] == 'value':
print("changed to %s" % change['new'])
w.observe(on_change)
display(w)
Overall this looks a lot richer than the deprecated interface, but it could definitely use more examples.
You can specify the change name in observe. This makes for cleaner code, and the handler is not called for changes you don't need:
from IPython.display import display
from ipywidgets import Dropdown
def dropdown_eventhandler(change):
print(change.new)
option_list = (1, 2, 3)
dropdown = Dropdown(description="Choose one:", options=option_list)
dropdown.observe(dropdown_eventhandler, names='value')
display(dropdown)
Put it all together
Inspired on previous answers and lambda expressions I use this:
def function(option):
print(option)
w = widgets.Dropdown(
options=['None', 'Option 1', 'Option 2', 'Option 3'],
description='Option:',
disabled=False
)
w.observe(
lambda c: plot_content(c['new']) if (c['type'] == 'change' and c['name'] == 'value') else None
)
display(w)
I agree that event handling is not as thorough as would be desired: I have been filtering the events as you receive multiple events for a typical dropdown change as the index changes, the value changes, i.e., change['name'].
I am doing the following:
def on_dropdown_change(change):
if change['name'] == 'value' and (change['new'] != change['old']):
print('do something with the change')
dropdown = ipywidgets.Dropdown({options=['one','two','three'],
value='one'})
dropdown.observe(on_dropdown_change)
I believe the idea is to use trait name, e.g. value. For example:
from ipywidgets import Dropdown
def handle_change():
print type_sel.value
type_sel = Dropdown(description="Keypoint type", options=['surf', 'orb'])
type_sel.on_trait_change(handle_change, name="value")
display(type_sel)
SciPy 2015 Advanced Jupyter Video Tutorial
I had the same issue. This also begs the next question, how to interface button actions based on dropdown menu selections.
# Common Imports for Widgets
from __future__ import print_function
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
'''
Precusor:
<class 'traitlets.utils.bunch.Bunch'> It is a dictionary-like object containing:
{'name': 'value', 'old': 'what_ever_the_old_value_was', 'new': 'what_ever_the_new_value_is',
'owner': Dropdown(description='the_user_defined_label:', index=1, # I'm not sure what this is
options=()#list of options passed,
value='value_kwarg_value'), 'type': 'change'} # type: action_or_event type
For more information see:
https://traitlets.readthedocs.io/en/stable/using_traitlets.html#default-values-and-checking-type-and-value
or
https://github.com/jupyter-widgets/tutorial/blob/master/notebooks/08.00-Widget_Events.ipynb
or a long but well done SciPy talk on the use of widgets #
https://www.youtube.com/watch?v=HaSpqsKaRbo
'''
foo = ['a','b','c'] # List to use
# Function to apply to drop box object
def bar(x):
'''
I am intentionally passing what it is made of so you can see the output.
'''
print(x,'\n') # Whole object
print(x.new,'\n') # New value
# Function for the button to select user input and do work
def get_user_selection(a): # A default arg is needed here, I am guessing to pass self
# Displays the current value of dropbox1 and dropbox two
display(dropbox1.value,dropbox2.value)
# creation of a widget dropdown object called dropbox1
dropbox1 = widgets.Dropdown(
options=foo, # Object to iterate over
description='Letter:', # User defined
value=foo[1], # Default value selection
rows=len(foo), # The number of rows to display when showing the box
interactive=True, # This makes the box interactive, I believe this is true by default
);
# Drop box of k,v like pairs
dropbox2 = widgets.Dropdown(
options=[('One', 1), ('Two', 2), ('Three', 3)],
value=2,
description='Number:',
)
# Button to click
select_button = widgets.Button(
description='Click', # User defined
disabled=False
)
# Event Handlers
dropbox1.observe(bar,names='value')
dropbox2.observe(bar,names='value')
select_button.on_click(get_user_selection)
# I you need more help with commands try things like:
# interact_manual?
# display(arg.keys,arg.traits)
# print(widgets.widget_type_here.widget_function_or_attr.__doc__)
# Create a UI object to display things. There are other ways of organizing them.
ui = widgets.HBox([dropbox1,dropbox2,select_button]) # pass an array of widgets to the ui
# display the UI
display(ui)
This will display the following after a couple of clicks.

Is there a way to make an IPython Notebook output interactivly create an input and execute it?

I was wondering if I can make an output interactively run a piece of code. So if for example I had a class (parts in pseudo-code):
import numpy as np
class test(object):
def __init__():
self.a = np.random.randn(10)
print ## Interactive Output: Click me to view data array##
def show():
print a
So when I create a class instance it should output some interactive link (maybe in html) or something like that and when I click it, the show() method should be called. However, I have no idea how to achieve that.
You could use the widgets shipped with the notebook (for jupyter they are an independent package).
Something like this could do what you want (Python 3):
from IPython.html import widgets
from IPython.display import display
import numpy as np
class Test(object):
def __init__(self, arraylen):
self.a = np.random.randn(arraylen)
self.button = widgets.Button(description = 'Show')
self.button.on_click(self.show)
display(self.button)
def show(self, ev = None):
display(self.a)
self.button.disabled = True
test = Test(10)
You create a button widget when you initialise the class widgets.Button(description = 'Show')
Attach an event to it button.on_click(self.show)
And display the button display(self.button)
In the show method I included a way to disable the button functionality once the array is showed self.button.disabled = True. You can comment this line if you want to show more times the array.

How to set value of input(type="file") with QWebElement?

I'm trying to upload a photo to vk.com using QtWebKit module. The problem I'm facing is inability to properly fill input(type="file")'s value. Here's some related code I use:
def upload():
print 'uploading...'
photoInput = web.page().mainFrame().documentElement().findFirst('input[id="photos_upload_input"]')
assert photoInput, 'No input found'
photoInput.setAttribute('value', '/Users/elmigranto/Downloads/stuff.png')
print photoInput.evaluateJavaScript('return this.value;').toString()
It's reasonable to note, that filling value of file input is impossible from Javascript due to browser security policy. However, it should be possible using Qt API, more specifically, QWebElement::setAttribute() method. And that's what I did… with no effect (well, photoInput.attribute('value') returns expected result, but photoInput.evaluateJavaScript('return this.value;').toString() returns empty string, input's onchange handler is also not triggered).
Setting other attributes is no problem, for example, QWebElement::addClass() works like a charm.
Any help would be super great.Thanks.
The setAttribute method might still not work for security reasons.
But you can redefine the function QWebPage::chooseFile that should normally open the upload dialog and return the filename so that it returns a static file name without opening the dialog, and activate that upload by simulating a "return" key press on the input element.
This seems to work:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
import sys
class WebPage(QWebPage):
def __init__(self, parent = None):
super(WebPage, self).__init__(parent)
self.overrideUpload = None
def chooseFile(self, originatingFrame, oldFile):
if self.overrideUpload is None:
return super(WebPage, self).chooseFile(originatingFrame, oldFile)
result = self.overrideUpload
self.overrideUpload = None
return result
def setUploadFile(self, selector, filename):
button = self.mainFrame().documentElement().findFirst(selector)
self.overrideUpload = filename
# set the focus on the input element
button.setFocus();
# and simulate a keypress event to make it call our chooseFile method
webview.event(QKeyEvent(QEvent.KeyPress, Qt.Key_Enter, Qt.NoModifier))
def upload():
print 'uploading...'
page.setUploadFile('input[id="photos_upload_input"]',
'/Users/elmigranto/Downloads/stuff.png')
# The change seems to be asynchronous, at it isn't visible
# just after the previous call
app = QApplication(sys.argv)
webview = QWebView()
page = WebPage(webview)
webview.setPage(page)
source = '''
<form action="#">
Select a file: <input type="file" id="photos_upload_input">
<input type="submit">
</form>
'''
webview.loadFinished.connect(upload)
webview.show()
webview.setHtml(source)
sys.exit(app.exec_())

Resources