Dash open tkinter file select dialog on click button - plotly-dash

I am trying to open a file dialog to select some local files. Apparently, Dash does not have this option build in, so I try to do it with tkinter. I find the Dash syntax very confusing with all these strange dependencies. When I run the example below, the file dialog opens as soon as I start the script, but not when I click the button. I desire the opposite behavior. The file selector dialog should open when I click the button and not when after starting the script.
from tkinter import Tk, filedialog
...
### Load files
#app.callback(
Output('B_add-files', 'value'),
[Input('B_add-files', 'n_clicks')],
[State('files-check', 'value')] )
def select_files(n_clicks, options):
if n_clicks is not None:
root = Tk()
root.withdraw()
root.call('wm', 'attributes', '.', '-topmost', True)
if 'by-dir' not in options:
files = filedialog.askopenfilename(multiple=True)
files = [abspath(i) for i in files]
for i in files:
assert isfile(i)
else:
dir_ = filedialog.askdirectory()
if isinstance(dir_ , tuple):
dir_ = []
if len(dir_) != 0:
files = glob(join(dir_, join('**', '*.mzXML')), recursive=True)
else:
files = []
if len(files) != 0:
mint.files += files
root.destroy()
return str(n_clicks)
This code now works most of the time. Only, if I click on the button multiple times, sometime the server stops and I get the error:
Tcl_AsyncDelete: async handler deleted by the wrong thread

Perhaps you’re looking for the Upload component... https://dash.plot.ly/dash-core-components/upload
If not, then your Input dependency should be on the “n_clicks” attribute of your button, rather than on “children”: https://dash.plot.ly/dash-core-components/button

Related

Not able to click on the button using Selenium

<button class="css-obkt16-button" type="button"><span class="css-1mhnkuh">Download CSV</span></button>
I am trying to click on the highlighted button 'Download CSV' having the above HTML code and save the csv file at some particular location, but I am not able to do so. The file is getting downloaded in Downloads folder.
My python code:
def scrape_data():
DRIVER_PATH = r"C:\chrome\chromedriver.exe"
driver = webdriver.Chrome(DRIVER_PATH)
driver.get('Link to the dashboard')
time.sleep(20)
buttons = driver.find_element(By.XPATH,"//button/span[text()='Download CSV']")
time.sleep(5)
driver.execute_script("arguments[0].click();", buttons)
driver.quit()
So please suggest a way to search via the button text) and save the file to a particular location??
To download the file on specific location you can try like blow.
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_experimental_option("prefs", {
"download.default_directory": r"C:\Data_Files\output_files"
})
s = Service('C:\\BrowserDrivers\\chromedriver.exe')
driver = webdriver.Chrome(service=s, options=options)
You should not use hardcoded sleeps like time.sleep(20). WebDriverWait expected_conditions should be used instead.
Adding a sleep between getting element and clicking it doesn't help in most cases.
Clicking element with JavaScript should be never used until you really have no alternative.
This should work in case the button you trying to click is inside the visible screen area and the locator is unique.
def scrape_data():
DRIVER_PATH = r"C:\chrome\chromedriver.exe"
driver = webdriver.Chrome(DRIVER_PATH)
wait = WebDriverWait(driver, 30)
driver.get('Link to the dashboard')
wait.until(EC.element_to_be_clickable((By.XPATH, "//button[contains(.,'Download CSV')]"))).click()

Selenium - How to automatically Download PDF Files of Web Page if there is no Download Button?

1.) I'am trying to Download the Article PDF Files from multiple web pages to a local folder on the computer. But there is now "Download PDF" button on the web pages. What would be the Quickest and Best way to do this with Selenium ?
2.) One way I have thought of is to use the Keyboard Keys for Print, "Control"- "P", but inside Selenium, none of the Keyboard Keys are working when i run the program. The Code is below,
from selenium import webdriver
import chromedriver_binary # Adds chromedriver binary to path
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
import time
driver = webdriver.Chrome()
driver.maximize_window() # Makes Full Screen of the Window Browser
time.sleep(4)
url = 'https://finance.yahoo.com/news/why-warren-buffett-doesnt-buy 152303112.html'
driver.get(url)
time.sleep(10)
a = ActionChains(driver)
a.key_down(Keys.CONTROL).send_keys('P').key_up(Keys.CONTROL).perform()
You can do that by using ChromeOptions() and have a setting id, origin etc.
Also you can give savefile.default_directory to save the PDF file.
Code:
import time
from selenium import webdriver
import json
Options = webdriver.ChromeOptions()
settings = {
"recentDestinations": [{
"id": "Save as PDF",
"origin": "local",
"account": "",
}],
"selectedDestinationId": "Save as PDF",
"version": 2
}
prefs = {'printing.print_preview_sticky_settings.appState': json.dumps(settings), 'savefile.default_directory': 'C:\\Users\\****\\path\\'}
Options.add_experimental_option('prefs', prefs)
Options.add_argument('--kiosk-printing')
driver_path = r'C:\\Users\\***\\***\\chromedriver.exe'
driver = webdriver.Chrome(options=Options, executable_path=driver_path)
driver.maximize_window() # Makes Full Screen of the Window Browser
time.sleep(4)
url = 'https://finance.yahoo.com/'
driver.get(url)
time.sleep(2)
driver.execute_script('window.print();')
Output:
You should see a PDF file in the directory like this:
Update:
driver_path = r'C:\\Users\\***\***\\chromedriver.exe'
driver = webdriver.Chrome(options=Options, executable_path=driver_path)

Sending a plotly graph over flask

Right now I have a code that uses plotly to create a figure
def show_city_frequency(number_of_city = 10):
plot_1 = go.Histogram(
x=dataset[dataset.city.isin(city_count[:number_of_city].index.values)]['city'],
showlegend=False)
## Creating the grid for all the above plots
fig = tls.make_subplots(rows=1, cols=1)
fig.append_trace(plot_1,1,1)
fig['layout'].update(showlegend=True, title="Frequency of cities in the dataset ")
return plot(fig)
I want to incorporate this into a flask function and send it to an html template as a bytes io object using send_file. I was able to do this for a matplotlib just using:
img = io.BytesIO()
plt.plot(x,y, label='Fees Paid')
plt.savefig(img, format='png')
img.seek(0)
return send_file(img, mimetype='image/png')
I've read that I can do basically the same thing except using:
img = plotly.io.to_image(fig, format='png')
img.seek(0)
return send_file(img, mimetype='image/png')
but I can't seem to find where to download plotly.io. I've read that plotly offline doesn't work for Ubuntu so I am wondering if that is what my issue is as well. I am also open to new suggestions of how to send this image dynamically to my html code.

savewidget from htmlwidget in R , cannot save html file in another folder

I have a map leaflet that I want to save in an html file in a specific folder.
I am using Windows 7.
I tried the following :
library(htmlwidgets)
saveWidget(map_leaflet, file="ressources/test.html")
library(htmlwidgets)
saveWidget(map_leaflet, file="ressources\\test.html")
library(htmlwidgets)
path_name <- file.path("ressources", "test.html", fsep="\\")
saveWidget(map_leaflet, file=path_name)
library(htmlwidgets)
path_name <- paste("ressources", "test.html", sep="/")
saveWidget(map_leaflet, file=path_name)
As an error message, depending on the Rstudio session, I either have
1) Error in setwd(dir) : cannot change working directory
2) Cannot find path
When I only save like this :
library(htmlwidgets)
saveWidget(map_leaflet, file="test.html")
It works perfectly.
Thank you in advance for your help.
Agreed.
here is a workaround:
f<-"ressources\\test.html"
saveWidget(map_leaflet,file.path(normalizePath(dirname(f)),basename(f)))
The issues appear to be that saveWidget does not work with relative pathnames and normalizePath does not work for paths to files that done exist yet.
I would call this a bug in saveWidget.
edit:
I have contribute what I think is an even better workaround to an existing open issue
I use the with_dir function in the withr package to do this. I also put it in a wrapper function:
save_leaflet <- function(plot, file, overwrite = FALSE){
# save the file if it doesn't already exist or if overwrite == TRUE
if( !file.exists(file) | overwrite ){
withr::with_dir(new = dirname(file),
code = htmlwidgets::saveWidget(plot,
file = basename(file)))
} else {
print("File already exists and 'overwrite' == FALSE. Nothing saved to file.")
}
}

Python + Selenium + PhantomJS render to PDF - multiple files

I am trying to addapt the code found in
Python + Selenium + PhantomJS render to PDF
so I instead of saving one web page as a pdf file, I can iterate over a list of urls and save each one with a specific name (from another list).
count = 0
while count < length:
def execute(script, args):
driver.execute('executePhantomScript', {'script': script, 'args' : args })
driver = webdriver.PhantomJS('phantomjs')
# hack while the python interface lags
driver.command_executor._commands['executePhantomScript'] = ('POST', '/session/$sessionId/phantom/execute')
driver.get(urls[count])
# set page format
# inside the execution script, webpage is "this"
pageFormat = '''this.paperSize = {format: "A4", orientation: "portrait" };'''
execute(pageFormat, [])
# render current page
render = '''this.render("test.pdf")'''
execute(render, [])
count+=1
I tested modifying
render = '''this.render("test.pdf")'''
to
render = '''this.render(names[count]+".pdf")'''
so as to include the each name in the list using count but have not been successful.
Also tried:
dest = file_user[count]+".pdf"
render = '''this.render(dest)'''
execute(render, [])
But did not work either.
I greatly appreciate a suggestion for the appropriate syntax.
It must be very simple but I am a noobie.
Use string formatting:
render = 'this.render("{file_name}.pdf")'.format(file_name=names[count])