I am trying to get output from my ipywidgets widgets in Microsoft Azure Notebooks running Jupyter Notebooks in Python 3.6. However, it does not return new values when I get them. This also applies to the event handlers/interact never being called for other widgets.
I have tried putting in different initial values, using different types of widgets (Text, Textarea, Checkbox, Button, ToggleButton). I have tried getting the w.value, ipywidgets.interact, w.observe, and w.on_click on Buttons.
A test that I did:
import time
import ipywidgets as widgets
from IPython.display import display
w = widgets.Text(disabled=False)
display(w)
while True:
print(w.value)
time.sleep(1)
I expect that when I enter something into the Text field, that it will output that text, but instead it continues printing out what it started with. There are no errors. So, for the above example, regardless of what I input into the resultant Text field, all that is printed is empty lines.
The problem is that communication between widgets and the Python
kernel is asynchronous and confusing.
time.sleep(...) in the cell only blocks the Python interpreter and does
not allow the widget Javascript implementation to send the changed value to the Python
kernel (because the Python kernel is blocked and not doing anything).
If you create the widget and then modify the widget text entry and then evaluate
w.value in the next cell interactively you will see the changed value.
See further discussion here (look for "async"):
https://github.com/AaronWatters/jp_proxy_widget/blob/master/notebooks/Tutorial.ipynb
In general if you want to force the Python interpreter to see some value sent from the Javascript widget implementation the Javascript side must call back to the Python interpreter in some way and the Python interpreter cannot be blocked by sleep or any other such mechanism.
This code doesn't work as intended in a normal notebook server, so probably won't work in Azure either. I suspect you need a thread process to read from the updated widget. Try this and see if you get anything printing in Azure Notebooks as you change the text field.
import time
import ipywidgets as widgets
from IPython.display import display
w = widgets.Text(disabled=False)
display(w)
def print_text(widget):
print(widget['new'])
w.observe(print_text, names='value')
Related
In Jupyter Lab when the ipywidgets.IntSlider object is selected I can use the arrow keys to change its value interactively. Is it possible to select the IntSlider widget (or any widget) by running some code so that I don't have to click on it to be able to interact with it? Please see sample code below.
Use-case: I'm using some functionalities to set the value of an IntSlider. It would be nice to be able to interact with it using the arrow keys right after the value change without having to click on it.
import ipywidgets as w
w_int = w.IntSlider(
value=7,
min=0,
max=10,
)
display(w_int)
# How can I select widget w_int at this point?
Good question. Unfortunately I don't think is currently possible.
The technical limitation is that there can be arbitrary number of views of the same widget displayed. So you could easily do:
display(w_int)
display(w_int)
display(w_int)
in which case there is no obvious way of ipywidgets to know which one you want to focus on.
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).
I am automating the creation of a new product with a Python script and have run into a problem with the interactive events getting stuck at the "Part Number" dialog. This does not occur when creating a new part, just a new product. Here is the applicable portion of the script (CATIA is open):
import win32com.client.dynamic
CATIA = win32com.client.Dispatch("CATIA.Application")
catDocs = CATIA.Documents
# Create a new product
newProductDoc = catDocs.Add("Product")
# "Part Number" window appears, requesting a name for the product
# Interactive processes will not proceed
newProduct = newProductDoc.Product
newProductSet = newProduct.Products
newPart = newProductSet.AddNewComponent("Part", "dummyPart")
...
The problem is that I am developing a small tool for others to use and it is not very useful if it hangs up.
Clicking on "Cancel" gets rid of the dialog box, but no interactive actions occur afterwards. Clicking on "Ok" resolves the problem, but it would be preferable for the script to be able to prepare the product as a final result without interaction in order to restrict user error and improve ease of use.
I know that I can create a product and manipulate it (i.e. add parts, add new products, etc.), then successfully save it. So the processes are being executed, they just aren't being displayed anymore. I just can't seem to find a way to get past the "Part Number" dialog box. I even tried naming it programmatically, which worked but didn't kill the dialog box.
Opening an existing product works very well, and any scripting processes can continue without problems. However, programmatically creating the product, saving, and closing causes CATIA to lock up... so the option of saving and re-opening as an existing product is out the window.
I also referenced the v5Automation.chm, but I couldn't find a way of interacting with dialog boxes.
I also tried .Update() on the new product and it's parts. Some other assurances were CATIA.Visible = True and CATIA.RefreshDisplay = True.
Disclaimer: I know that VBA can be used and does not pose this problem. I am looking for a solution to this problem using Python (2 or 3, doesn't matter).
This post is old but since I found this page when having the same issue I figured I'll add my solution. I've found a handful of methods in CATIA that behave this way - works fine in CATIA VBA but not through the COM interface. The best solution I've found is to write a mini VBA function in a string and then call it in CATIA through Python. Here is an example:
import random
import win32com.client
CATIA = win32com.client.GetActiveObject('CATIA.Application')
CATVBALanguage = 1
# This should work, but CATIA leaves up the dialog window and it can affect
# the rest of the code execution
# NewProductDocument = CATIA.Documents.Add('Product')
# Instead, write the code in VBA and then have CATIA execute it. You can
# pass in arguments and capture the results as demonstrated below.
CREATE_PRODUCT_VBA_CODE = '''
Public Function create_product(part_number as CATBSTR) as Document
Set create_product = CATIA.Documents.Add("Product")
create_product.Product.PartNumber = part_number
End Function
'''
PART_NUMBER = 'test_product_{}'.format(random.randint(1, 100))
NewProductDocument = CATIA.SystemService.Evaluate(
CREATE_PRODUCT_VBA_CODE, # String with the VBA code to execute
CATVBALanguage, # 1 to indicate this string is VBA code
'create_product', # VBA function to call and return result from
[PART_NUMBER] # Array of arguments, in order for VBA function
)
# Can still interact with this returned object as if we had created it
print(NewProductDocument.Product.PartNumber)
The only way I have found, so far, to circumvent this problem is to create a template product (in this case, just an empty product) and do a catDocs.NewFrom(<templateProductPath>) and add the product structure as necessary.
I was trying to replicate your issue, but I dind't encounter it. Products just created fine using incremental default names.
Then I thought it was something related to Settings since the dialog is simlar to the one that optionally pops up when addin a new part.
I discovered that I had the option Infrastructure > Product Infrastructure > Product structure > Part Number: Manual input unchecked.
I don't know how this was related to using VBA or not, but checking it created the issue and unchecking it removed the issue, while still sending the same command from Python.
I'm writing a program in curses and sometimes happens that if I leave the program opened and I use other terminal tabs for a while, when I go using the program again it seems like it has refreshed something and something has disappeared... I cannot show pics or screenshots because I haven't understood yet well when and how it happens... Is there a way to prevent or fix this?
screen.getch reads from stdscr, and if it refreshes (due to any change on the screen), will overwrite boxes. You could change that to box.getch, as I did in scroll page by page or line by line using python curses
The manual page for getch says
If the window is not a pad, and it has been moved or modified since the last call to wrefresh, wrefresh will be called before another character is read.
In your sample program you used
screen.keypad( 1 )
which only applies to reading from the standard screen. If you read from the box window, you should set the keypad flag on that:
box.keypad( 1 )
The manual page for keypad says
The default value for keypad is FALSE
that is, it is the default for each window.
A curses program with multiple windows can choose to read from different windows at different times. There is only one input buffer for each screen, but the side-effect of refreshing the current window makes it simpler to manage updates to the windows. (For complicated window stacking order, you would use the panel library rather than rely upon this side-effect).
Does anyone have any ideas on how to use the Mac’s built-in dictation tool to create strings to be used by Python?
To launch a dictation, you have to double-press the Fn key inside any text editor. If this is the case, is there a way to combine the keystroke command with the input command? Something like:
Step 1: Simulate a keystroke to double-press the Fn key, launching the Dictation tool, and then
Step 2. Creating a variable by using the speech-to-text content as part of the input function, i.e. text_string = input(“Start dictation: “)
In this thread (Can I use OS X 10.8's speech recognition/dictation without a GUI?) a user suggests he figured it out with CGEventCreateKeyboardEvent(src, 0x3F, true), but there is no code.
Any ideas? Code samples would be appreciated.
UPDATE: Thanks to the suggestions below, I've imported AppScript. I'm trying the code to work along these lines, with no success:
from appscript import app, its
se = app('System Events')
proc = app.processes[its.frontmost == True]
mi = proc.menu_bars[1].menu_bar_items['Edit'].menus[1].menu_items['Start Dictation']
user_voice_text = input(mi.click())
print(user_voice_text)
Any ideas on how I can turn on the dictation tool to be input for a string?
UPDATE 2:
Here is a simple example of the program I'm trying to create:
Ideally i want to launch the program, and then have it ask me: "what is 1 + 1?"
Then I want the program to turn on the dictation tool, and I want the program to record my voice, with me answering "two".
The dictation-to-text function will then pass the string value = "two" to my program, and an if statement is then used to say back "correct" or "incorrect".
Im trying to pass commands to the program without ever typing on the keyboard.
First, FnFn dictation is a feature of the NSText (or maybe NSTextView?) Cocoa control. If you've got one of those, the dictated text gets inserted into that control. (It also uses that control's existing text for context.) From the point of view of the app using an NSTextView, if you just create a standard Edit menu, the Start Dictation item gets added to the end, with FnFn as a shortcut, and anything that gets dictated appears as input, just like input typed on a keyboard, or pasted or dragged with the mouse, or via any other input method.
So, if you don't have a GUI app, enabling dictation is going to be pointless, because you have no way to get the input.
If you do have a GUI app, the simplest thing to do is just get the menu item via NSMenu, and click the item.
You're almost certainly using some kind of GUI library, like PyQt or Tkinter, which has its own way of accessing your app's menu. But if not, you can do it directly through Cocoa (using PyObjC—which comes with Apple's pre-installed Python, but which you'll have to pip install if you're using a third-party Python):
import AppKit
mb = AppKit.NSApp.mainMenu()
edit = mb.itemWithTitle_('Edit').submenu()
sd = edit.indexOfItemWithTitle_('Start Dictation')
edit.performActionForItemAtIndex_(sd)
But if you're writing a console program that runs in the terminal (whether Terminal.app or an alternative like iTerm), the app you're running under has its own text widget and Edit menu, and you can parasitically use its menu instead.
The problem is that you don't have permission to just control other apps unless the user allows it. In older versions of OS X, this was done just by turning on "assistive scripting for accessibility" globally. As of 10.10, there's an Accessibility anchor in the Privacy tab of the Security & Privacy pane of System Preferences that has a list of apps that have permissions. Fortunately, if you're not on the list, the first time you try to use accessibility features, it'll pop up a dialog, and if the user clicks on it, it'll launch System Preferences, reveal that anchor, add your app to the list with the checkbox disabled, and scroll it into view, so all the user has to do is click the checkbox.
The AppleScript to do this is:
tell application "System Events"
click (menu item "Start Dictation" of menu of menu bar item "Edit"
of menu bar of (first process whose frontmost is true))
end tell
The "right" way to do the equivalent in Python is via ScriptingBridge, which you can access via PyObjC… but it's a lot easier to use the third-party library appscript:
from appscript import app, its
se = app('System Events')
proc = app.processes[its.frontmost == True]
mi = proc.menu_bars[1].menu_bar_items['Edit'].menus[1].menu_items['Start Dictation']
mi.click()
If you really want to send the Fn key twice, the APIs for generating and sending keyboard events are part of Quartz Events Services, which (even though it's a CoreFoundation C API, not a Cocoa ObjC API) is also wrapped by PyObjC. The documentation can be a bit tricky to understand, but basically, the idea is that you create an event of the appropriate type, then either post it to a specific application, an event tap, or a tap location. So, you can create and send a system-wide key-down Fn-key event like this:
evt = Quartz.CGEventCreateKeyboardEvent(None, 63, True)
Quartz.CGEventPost(Quartz.kCGSessionEventTap, evt)
To send a key-up event, just change that True to False.