I have a JavaScript script (open_hist_w_user.js) spawns a python process and passes data to a python script (create_histogram.py). The Python script creates a histogram using the Matplotlib library and displays it. The problem is that even after calling plt.close('all'), the plot window does not close.
Code:
*javascript; open_hisr_w_user.js*
/**
* This script is used to spawn a python process that generates a histogram for the specified username.
*
* #param {string} username - The username for which the histogram is being generated.
*
* #returns {ChildProcess} - The spawned python process.
*/
const { spawn } = require('child_process');
const username = 'some_username';
const pythonProcess = spawn('python', ['./create_histogram.py', username]);
python;create_histogram.py
import matplotlib.pyplot as plt
import sys
import time
def create_histogram(username):
"""
This function creates a histogram of data, with a specified number of bins and range, and displays it.
Parameters
----------
username : str
The username for which the histogram is being generated.
Returns
-------
None
"""
plt.close('all') # close any previous plot windows
# plot the histogram
plt.clf() # clear the previous plot
plt.hist([1, 2, 3, 4, 5], bins=3, range=(0, 5))
plt.xlabel('Total')
plt.ylabel('Frequency')
plt.title(f'Histogram of Total Column for {username}')
plt.show() # show the plot
time.sleep(5) # wait for 5 seconds
plt.close('all') # close the plot window
if __name__ == "__main__":
username = sys.argv[1]
create_histogram(username)
I tried using plt.close('all') to close the plot window, but it did not work. I expected the plot window to close after some delay after the histogram was created. Before you ask why am I not just using a javascript script,I tried porting my code a few days ago using plotly and df3, but couldn't get it working; so here we are passing data through the console.
Expected Result:
insert image of closed window here
Actual Result:
Try this:
*javascript; open_hisr_w_user.js*
/**
* This script is used to spawn a python process that generates a histogram for the specified username.
*
* #param {string} username - The username for which the histogram is being generated.
*
* #returns {ChildProcess} - The spawned python process.
*/
const spawn = require('child_process').spawn;
const username = 'some_username';
const pythonProcess = spawn('python', ['./create_histogram.py', username], {
detached: true,
stdio: ['ignore']
});
pythonProcess.unref();
Related
Problem:
My Plotly Dash app (python) has a clientside callback (javascript) which prompts the user to select a folder, then saves a file in a subfolder within that folder. Chrome asks for permission to read and write to the folder, which is fine, but I want the user to only have to give permission once. Unfortunately the permissions, which should persist until the tab closes, disappear often. Two "repeatable cases" are:
when the user clicks a simple button ~15 times very fast, previously accepted permissions will disappear (plotting a figure also does this in my real application)
downloading a file within a few seconds of reloading the page results in the permissions automatically going away within about 5 seconds
I can see the permissions (file and pen icon) disappear at the right of the chrome url banner.
What I've tried:
testing with Ublock Origin on/off (and removed from chrome) to see if the extension interfered (got idea from the only somewhat similar question I've come across: window.confirm disappears without interaction in Chrome)
turning debug mode off
using Edge instead of chrome (basically the same behavior was observed)
adding more computation to Test button to find repeatable case, but still needed to click it a lot to remove permissions (triggering callbacks / updating Dash components seems to be the issue, not server resources)
Example python script (dash app) to show permissions disappearing:
import dash
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
from dash import html
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div([
dbc.Button(id="model-export-button", children="Export Model"),
dbc.Label(id="test-label1", children="Click to download"),
html.Br(),
dbc.Button(id="test-button", children="Test button"),
dbc.Label(id="test-label2", children="Button not clicked")
])
# Chrome web API used for downloading: https://web.dev/file-system-access/
app.clientside_callback(
"""
async function(n_clicks) {
// Select directory to download
const directoryHandle = await window.showDirectoryPicker({id: 'save-dir', startIn: 'downloads'});
// Create sub-folder in that directory
const newDirectoryHandle = await directoryHandle.getDirectoryHandle("test-folder-name", {create: true});
// Download files to sub-folder
const fileHandle = await newDirectoryHandle.getFileHandle("test-file-name.txt", {create: true});
const writable = await fileHandle.createWritable();
await writable.write("Hello world.");
await writable.close();
// Create status message
const event = new Date(Date.now());
const msg = "File(s) saved successfully at " + event.toLocaleTimeString();
return msg;
}
""",
Output('test-label1', 'children'),
Input('model-export-button', 'n_clicks'),
prevent_initial_call=True
)
#app.callback(
Output('test-label2', 'children'),
Input('test-button', 'n_clicks'),
prevent_initial_call=True
)
def test_button_function(n):
return "Button has been clicked " + str(n) + " times"
if __name__ == "__main__":
app.run_server(debug=False)
This is now possible! In your code, replace the line…
await window.showDirectoryPicker({id: 'save-dir', startIn: 'downloads'});
…with…
await window.showDirectoryPicker({
id: 'save-dir',
startIn: 'downloads',
mode: 'readwrite', // This is new!
});
I am trying to print in python the messages from the web console using a callback on a onConsoleMessage event. Pepper (Edit: version 1.6) is running naoqi 2.5.5.5. I've modified the executeJS example as a test. The problem is I keep getting null for the message in the callback. Is it a bug that has been fixed in a newer version of naoqi ? I've had a look at the release notes but I didn't find anything.
Here is the code I am using:
#! /usr/bin/env python
# -*- encoding: UTF-8 -*-
"""Example: Use executeJS Method"""
import qi
import argparse
import sys
import time
import signal
def signal_handler(signal, frame):
print('Bye!')
sys.exit(0)
def main(session):
"""
This example uses the executeJS method.
To Test ALTabletService, you need to run the script ON the robot.
"""
# Get the service ALTabletService.
try:
tabletService = session.service("ALTabletService")
# Display a local web page located in boot-config/html folder
# The ip of the robot from the tablet is 198.18.0.1
tabletService.showWebview("http://198.18.0.1/apps/boot-config/preloading_dialog.html")
time.sleep(3)
# Javascript script for displaying a prompt
# ALTabletBinding is a javascript binding inject in the web page displayed on the tablet
script = """
console.log('A test message');
"""
# Don't forget to disconnect the signal at the end
signalID = 0
# function called when the signal onJSEvent is triggered
# by the javascript function ALTabletBinding.raiseEvent(name)
def callback(message):
print "[callback] received : ", message
# attach the callback function to onJSEvent signal
signalID = tabletService.onConsoleMessage.connect(callback)
# inject and execute the javascript in the current web page displayed
tabletService.executeJS(script)
print("Waiting for Ctrl+C to disconnect")
signal.pause()
except Exception, e:
print "Error was: ", e
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--ip", type=str, default="127.0.0.1",
help="Robot IP address. On robot or Local Naoqi: use '127.0.0.1'.")
parser.add_argument("--port", type=int, default=9559,
help="Naoqi port number")
args = parser.parse_args()
session = qi.Session()
try:
session.connect("tcp://" + args.ip + ":" + str(args.port))
except RuntimeError:
print ("Can't connect to Naoqi at ip \"" + args.ip + "\" on port " + str(args.port) +".\n"
"Please check your script arguments. Run with -h option for help.")
sys.exit(1)
main(session)
Output:
python onConsoleMessage.py --ip=192.168.1.20
[W] 1515665783.618190 30615 qi.path.sdklayout: No Application was created, trying to deduce paths
Waiting for Ctrl+C to disconnect
[callback] received : null
Did someone face the same issue?
Thanks
I have the same issue. You can easily reproduce it by opening two ssh consoles on the robot, and on the first one executing
qicli watch ALTabletService.onConsoleMessage
and on the second
qicli call ALTabletService.showWebview
qicli call ALTabletService.executeJS "console.log('hello')"
... and instead of "hello", you will see "null" appear in your first console.
HOWEVER - if your goal is to effectively test your webpage, what I usually do is just open the page on my computer and use the chrome console (you can set chrome up to act as if the page was a tablet of the right size, 1280x800); you can do this while still connecting the page to Pepper, as if it was on her tablet, using the method described here. This is enough for 99% of the case; the remaining 1% is things where Pepper's tablet is actually different from Chrome.
I have a script that needs to be running 24/7, so I have been running it using pm2. However, I also would like to be able to occasionally check on the script. Before running it as a daemon I set it to read the stdin, but for daemons this does not work. Is there a simple way to do this and run a daemon process?
I understand that this is pretty contradictory to the nature of daemons, but I need the script to run continuously and have limited user input.
It can be done by using process.spawn, the following example is taken from the book: Professional Node.js
Create a file named plus_one.js:
// unpause the stdin stream
process.stdin.resume();
process.stdin.on('data', function(data) {
var number;
try {
// parse the input data into a number
number = parseInt(data.toString(), 10);
// increment by one
number += 1;
// output the number
process.stdout.write(number + "\n");
} catch(err) {
process.stderr.write(err.message + "\n");
}
});
You can run this simple program by calling:
$ node plus_one.js
create a file named plus_one_test.js:
var spawn = require('child_process').spawn;
// Spawn the child with a node process executing the plus_one app var
child = spawn('node', ['plus_one.js']);
// Call this function every 1 second (1000 milliseconds):
setInterval(function() {
// Create a random number smaller than 10.000
var number = Math.floor(Math.random() * 10000);
// Send that number to the child process:
child.stdin.write(number + "\n");
// Get the response from the child process and print it:
child.stdout.once('data', function(data) {
console.log('child replied to ' + number + ' with: ' + data);
});
}, 1000);
child.stderr.on('data', function(data) {
process.stdout.write(data);
});
Here you launch the +1 app as a child process on lines 1 to 4.
Then you use the setInterval function to do the following every second:
Create a random natural number smaller than 10,000. Send that number as a string to the child process. Wait for the child process to reply with a string.
Edited because I had the DLL built wrong:
I have built a DLL, and if I do a dumpbin /exports command on the DLL I see the following:
Dump of file stun_driver.dll
File Type: DLL
Section contains the following exports for stun_driver.dll
00000000 characteristics
546E6C63 time date stamp Thu Nov 20 17:34:11 2014
0.00 version
1 ordinal base
4 number of functions
4 number of names
ordinal hint RVA name
1 0 00001005 OPENSSL_Applink = #ILT+0(_OPENSSL_Applink)
2 1 00001320 launch_stun = #ILT+795(_launch_stun)
3 2 000011D6 stop_stun = #ILT+465(_stop_stun)
4 3 00001078 test_print = #ILT+115(_test_print)
Summary
1A000 .data
2000 .idata
46000 .rdata
F000 .reloc
135000 .text
My code for executing the "test_print" function, is as follows:
/* import js-ctypes */
Cu.import("resource://gre/modules/ctypes.jsm")
var stun_driver = ctypes.open("C:\\stun_driver.dll");
const test_print = stun_driver.declare("test_print", ctypes.default_abi, ctypes.int32_t);
.
.
.//in a button
test_print();
So my question is, if my test_print() is doing a printf("Hello World"), where does that text go? It doesn't seem to be getting logged to my browser console, or to the dos console i am running "cfx run" from.
If you start Firefox from a terminal window, you should see the output there.
what should be right way to click on a javascript generated link on a regular time interval using python and selenium bindings? should it be using a thread?
as i would need to continue to process the input data, i need to refresh/reset a timer to continue to receive data, clicking on this given link to do this refresh (and this link is html directly generated by javascript).
best regards
You don't need thread to do this.
Use javascript function setInterval to continuously click the link.
For example:
import time
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('http://jsfiddle.net/falsetru/4UxgK/show/')
# Click the link every 3000 ms.
driver.execute_script('''
// argument passed from Python can be accessed by `arguments` array.
var link = arguments[0];
var timer = setInterval(function() {
link.click();
}, 3000);
''', driver.find_element_by_id('activity'))
while True:
data = driver.find_element_by_id('counter').text
print(data)
time.sleep(1)
NOTE
If you get error like follow, upgrade selenium to recent version. I experienced following error with Firefox 23.0 + selenium 2.32.0. Error was gone with selenium 2.35.0.
Traceback (most recent call last):
File "t2.py", line 12, in <module>
print driver.execute_script('''return 1 + 2;''')
File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 397, in execute_script
{'script': script, 'args':converted_args})['value']
File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 165, in execute
self.error_handler.check_response(response)
File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/errorhandler.py", line 158, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: u'waiting for evaluate.js load failed' ; Stacktrace:
at r (file:///tmp/tmpm1sJhH/extensions/fxdriver#googlecode.com/components/driver_component.js:8360)
at fxdriver.Timer.prototype.runWhenTrue/g (file:///tmp/tmpm1sJhH/extensions/fxdriver#googlecode.com/components/driver_component.js:392)
at fxdriver.Timer.prototype.setTimeout/<.notify (file:///tmp/tmpm1sJhH/extensions/fxdriver#googlecode.com/components/driver_component.js:386)
Alternative: using thread
import threading
import time
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('http://jsfiddle.net/falsetru/4UxgK/show/')
def click_loop(link, interval):
while True:
link.click()
time.sleep(interval)
link = driver.find_element_by_id('activity')
threading.Thread(target=click_loop, args=(link, 3)).start()
while True:
data = driver.find_element_by_id('counter').text
print(data)
time.sleep(1)