How can I redirect/show the console output (including outputs I print inside the program) so it would appear inside a Dash app (On the screen the user sees)?
I didn't find a way for Dash to read the console output directly, so I used a workaround using a text file.
Here is a sample code which prints the last 20 lines of the console output to an Iframe (as to keep the line breaks, which do not show in other text/div components):
import dash_core_components as dcc
import dash_html_components as html
import dash
import sys
f = open('out.txt', 'w')
f.close()
app = dash.Dash()
app.layout = html.Div([
dcc.Interval(id='interval1', interval=1 * 1000,
n_intervals=0),
dcc.Interval(id='interval2', interval=5 * 1000,
n_intervals=0),
html.H1(id='div-out', children=''),
html.Iframe(id='console-out',srcDoc='',style={'width':
'100%','height':400})
])
#app.callback(dash.dependencies.Output('div-out',
'children'),
[dash.dependencies.Input('interval1', 'n_intervals')])
def update_interval(n):
orig_stdout = sys.stdout
f = open('out.txt', 'a')
sys.stdout = f
print 'Intervals Passed: ' + str(n)
sys.stdout = orig_stdout
f.close()
return 'Intervals Passed: ' + str(n)
#app.callback(dash.dependencies.Output('console-out',
'srcDoc'),
[dash.dependencies.Input('interval2', 'n_intervals')])
def update_output(n):
file = open('out.txt', 'r')
data=''
lines = file.readlines()
if lines.__len__()<=20:
last_lines=lines
else:
last_lines = lines[-20:]
for line in last_lines:
data=data+line + '<BR>'
file.close()
return data
app.run_server(debug=False, port=8050)
Create a custom LoggerHandler, and use dcc.Interval for refreshing.
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash
import logging
class DashLoggerHandler(logging.StreamHandler):
def __init__(self):
logging.StreamHandler.__init__(self)
self.queue = []
def emit(self, record):
msg = self.format(record)
self.queue.append(msg)
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
dashLoggerHandler = DashLoggerHandler()
logger.addHandler(dashLoggerHandler)
app = dash.Dash()
app.layout = html.Div([
dcc.Interval(id='interval1', interval=5 * 1000, n_intervals=0),
html.H1(id='div-out', children='Log'),
html.Iframe(id='console-out',srcDoc='',style={'width': '100%','height':400})
])
#app.callback(
Output('console-out', 'srcDoc'),
Input('interval1', 'n_intervals'))
def update_output(n):
return ('\n'.join(dashLoggerHandler.queue)).replace('\n', '<BR>')
app.run_server(debug=False, port=8050)
One possible way to do this is supply it as input to Dash Core Component Text Area's value property. This should work if its a string.
Related
I have an app with multiple pages, controlled from this index, in a new page I want to insert a dash table and assign some interactivity using callbacks. Take a basic dash table example (https://dash.plotly.com/datatable) and insert it into my app, but the callback doesn't get executed. The only thing that changes when inserting into my app, is the way I create the app.layout, which is created from a function.
The table is created but the callback doesn't trigger.
Index.py
import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
from homepage import Homepage
from resumen_comunal import Resumen_Comunal
from dash_main_table import main_Table
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.FLATLY])
app.config.suppress_callback_exceptions = True
app.layout = html.Div([
dcc.Location(id = 'url', refresh = False),
html.Div(id = 'page-content')
])
#app.callback(dash.dependencies.Output('page-content', 'children'),
[dash.dependencies.Input('url', 'pathname')])
def display_page(pathname):
if pathname == '/Cobertura_CV':
return Resumen_Comunal()
if pathname == '/Gestion_CV':
return main_Table()
else:
return Homepage()
if __name__ == '__main__':
app.run_server(debug=False)
dash_table.py
import dash
from dash import Dash, dash_table, dcc, html
from dash.dependencies import Input, Output
import pandas as pd
import dash_bootstrap_components as dbc
from navbar import Navbar
nav = Navbar()
app = dash.Dash(__name__, external_stylesheets = [dbc.themes.FLATLY])
df = pd.read_csv('https://git.io/Juf1t')
body = dbc.Container([
dbc.Label('Click a cell in the table:'),
dash_table.DataTable(df.to_dict('records'),[{"name": i, "id": i} for i in df.columns], id='tbl'),
dbc.Alert(id='tbl_out'),
])
#app.callback(Output('tbl_out', 'children'),
Input('tbl', 'active_cell'))
def update_graphs(active_cell):
return str(active_cell) if active_cell else "Click the table"
def main_Table():
layout = html.Div([
nav,
body
])
return layout
if __name__ == "__main__":
app.run_server(debug=True)
Thanks for your help!
So, the callback is not triggered because you’re trying to populate the dash table in a separate application while the callback for the same is created inside a different application.
You don't have to create a new app object given that it's already created in index.py and the layout is passed to that same app object
Here's what you should do inside dash_table.py
import dash
from dash import Dash, dash_table, dcc, html,callback
from dash.dependencies import Input, Output
import pandas as pd
import dash_bootstrap_components as dbc
from navbar import Navbar
nav = Navbar()
df = pd.read_csv('https://git.io/Juf1t')
body = dbc.Container([
dbc.Label('Click a cell in the table:'),
dash_table.DataTable(df.to_dict('records'),[{"name": i, "id": i} for i in df.columns], id='tbl'),
dbc.Alert(id='tbl_out'),
])
#callback(Output('tbl_out', 'children'),
Input('tbl', 'active_cell'))
def update_graphs(active_cell):
print(active_cell)
return str(active_cell) if active_cell else "Click the table"
def main_Table():
layout = html.Div([
nav,
body
])
return layout
I am trying to make a basic Dash app, and I got this error. Here is my code.
import dash
import plotly
from dash import dcc
#from dash_core_components.Markdown import Markdown
from dash import html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import os
import PyPDF2
app = dash.Dash(__name__, meta_tags=[{"name": "viewport", "content": "width=device- width, initial-scale=1"}], external_stylesheets=[dbc.themes.SUPERHERO])
app.title = 'FODS'
server = app.server
app.layout = html.Div([
dcc.Input(
id='input_text',
type= 'text',
placeholder="Enter Unicode Search Phrase".format('text'),
),
html.Div(id = 'output-area')
])
#app.callback(
Output('output-area', 'children'),
Input('input_text', 'value'),
)
def return_pages(input_text):
locations = []
answers = 'Please refer '
for file in os.listdir('./Solutions'):
path = './Solutions/' + file
pdfFileObj = open(path, 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFileObj, strict = False)
for i in range(pdfReader.numPages):
pageObj = pdfReader.getPage(i)
text = str(pageObj.extractText())
if input_text in text:
locations.append([file, i+1])
answers += file + ', at page ' + str(i + 1) + ', '
if len(locations) != 0:
return answers + ' for your answers'
else:
return 'Sorry, your query fetched no answers'
if __name__ == '__main__':
app.run_server(debug=True)
Screenshot of the error on local development server
I have tried updating the libraries and restarting the venv. Please advise on what can be done. There is a slight time crunch on this project.
Thanks in advance.
I'm new in Dash. I'm trying to use a daq.BooleanSwitch() like an input to callback a graph. I can display a message but I have troubles with the graph.
Does anyone have any advice that can help me?
import dash
from dash.dependencies import Input, Output
import dash_daq as daq
import dash_html_components as html
app = dash.Dash(__name__)
app.layout = html.Div([
html.H1("Here we go"),
daq.BooleanSwitch(id='my_pb', on=False,color="red"),
html.Div(id='power-button-result-1'),
dcc.Graph(id="plot")
])
#app.callback(
Output('power-button-result-1', 'children'),
Input('my_pb', 'on')
)
def update_output(on):
x = '{}'.format(on)
if x == "True":
return "Hi Iḿ using DASH"
#app.callback(
Output('plot', 'figure'),
Input('my_pb', 'on')
)
def figura(on):
x = '{}'.format(on)
if x == "True":
# fig1 = Code to do a nice plot
return fig1
if __name__ == "__main__":
app.run_server(port = 1895)
My DASH output look like this:
I took a look at your code, and a couple changes were necessary:
import dash
import dash_daq as daq
from dash import dcc
from dash import html
from dash.dependencies import Input
from dash.dependencies import Output
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.H1("Here we go"),
daq.BooleanSwitch(id="my_pb", on=False, color="red"),
html.Div(id="power-button-result-1"),
]
)
#app.callback(
Output("power-button-result-1", "children"),
Input("my_pb", "on"),
)
def update_output(on):
x = "{}".format(on)
if x == "True":
return [dcc.Graph(id="plot")]
if __name__ == "__main__":
app.run_server(debug=True)
You were super close - I think you only need one callback. Here, you can see the boolean switch now toggles the display (or not) of the dcc.Graph object. Is this what you were looking for?
↓ (toggle the switch)
If you want the graph to already be displayed, and then updated upon toggling, here's a slightly modified expanded version of same code above to do that:
import dash
import dash_daq as daq
from dash import dcc
from dash import html
from dash import no_update
from dash.dependencies import Input
from dash.dependencies import Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.H1("Here we go"),
daq.BooleanSwitch(id="my_pb", on=False, color="red"),
html.Div(
[dcc.Graph(id="plot")], id="power-button-result-1"
),
]
)
#app.callback(
Output("power-button-result-1", "children"),
Input("my_pb", "on"),
)
def update_output(on):
df = px.data.iris()
if on:
fig = px.scatter(df, x="sepal_width", y="sepal_length")
dcc.Graph(figure=fig)
return [dcc.Graph(figure=fig)]
else:
fig = px.scatter()
return [dcc.Graph(figure=fig)]
if __name__ == "__main__":
app.run_server(debug=True)
There - that's much better, hopefully helpful?
I’m learning python and dash and I’m building an application for monitoring my trading.
I’ve adapted the code from : “Live Updating Components” example (Orbital Satellite). It works well on jupyter notebook and repl.it but I have an error when I try it on my computer :
"Traceback (most recent call last):
File "orbital.py", line 62, in
Input('interval-component', 'n_intervals'))"
“The input argument interval-component.n_intervals must be a list or tuple of
dash.dependencies.Inputs.”
I don’t understand why
Here is my code :
import ccxt
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly
from dash.dependencies import Input, Output
import pandas as pd
app = dash.Dash(__name__)
ftx = ccxt.ftx({'verbose': True})
ftx = ccxt.ftx({
'apiKey': '',
'secret': '',
})
app.layout = html.Div(
html.Div([
html.H4('FTX Live Feed'),
html.Div(id='live-update-text'),
dcc.Interval(
id='interval-component',
interval=1*1000, # in milliseconds
n_intervals=0
)
])
)
class Client:
"""A sample client class"""
def __init__(self):
self.pnl = []
#classmethod
def get_balances(client):
try:
balance = ftx.fetch_balance()
except ccxt.BaseError as e:
print(f"Could not get account with error: {e}")
raise e
else:
result = balance["info"]["result"]
total = []
for x in result:
if float(x["free"]) > 0.0:
total.append(x["usdValue"])
a = list(map(float, total))
df = pd.Series(a)
# global totCap
totCap = df.sum()
return totCap
#app.callback(Output('live-update-text', 'children'),
Input('interval-component', 'n_intervals'))
def update_metrics(n):
arc = Client().get_balances()
style = {'padding': '5px', 'fontSize': '16px'}
return [
html.Span('Balance: {0:.2f}'.format(arc), style=style)
]
if __name__ == '__main__':
app.run_server(host="0.0.0.0", port="8050")
Here is a screenshot from the replit app :
replit dash
As the error is trying to say, you need to wrap your Input in a list, like this:
#app.callback(Output('live-update-text', 'children'),
[Input('interval-component', 'n_intervals')])
I am working on a project on which I have to monitor a ftp directory for any new files which appear , once a new file appears I want to extract data from and plot the results in real time so far I have sorted out the ftp function that monitors the directory , for testing purpose I am using my phone as a test ftp server and I have created a function which uploads a new file every n seconds :
from ftplib import FTP
from time import sleep
import os
ftp = FTP()
ftp.connect('192.168.1.109', 2221)
ftp.login('android', 'android')
ftp.cwd('/test_folder')
folder = 'C:\\Users\\QC\\Desktop\\sample_files_to_upload'
for file in os.listdir(folder):
fp = open(folder + file,'rb')
ftp.storbinary('STOR %s' % os.path.basename(file), fp, 1024)
sleep(2)
fp.close()
sleep(2)
print("File {} uploaded sucessfully".format(file))
I also have a function which watches the directory for any new files which appear in the directory and as soon as the file appears it copies it on the local machine performs data extraction prints the output and removes the file:
from ftplib import FTP
from time import sleep
import time
import os
def monitor_ftp():
ftp = FTP()
ftp.connect('192.168.1.109', 2221', 21)
ftp.login('android', 'android)
ftp.cwd('/test_folder')
print("Connection Established {}".format(ftp.getwelcome()))
direct = 'C:\\Users\\QC\\Desktop\\local_temp_directory\\'
old_files = ['1']
#print(old_files)
while True:
try:
new_files = ftp.nlst()
#print(new_files)
#print(new_files)
if len(old_files) != 0 and new_files != old_files:
changes = [i for i in new_files if i not in old_files]
#
# print(changes)
for x in changes:
filename = str(direct + x)
localfile = open(filename, 'wb')
ftp.retrbinary('RETR'+' ' + x , localfile.write, 1024)
localfile.close()
xcorr = extract_function(filename)
print("updating data ***************************************************")
print("found new file---> {}".format(str(filename).split('\\')[-1]))
print("Calculating cross-correlation")
print("*****************************************************************")
print(" ")
sleep(3)
os.remove(filename)
a = time.perf_counter()
if time.perf_counter() > a + 20:
print("Done Waiting")
break
old_files = new_files
except KeyboardInterrupt:
ftp.quit()
I have also created a basic test_dash app :
import dash
import plotly.graph_objects as go
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
from app import app
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Graph(id = 'live-graph', animate = True),
dcc.Interval(
id = 'graph-update',
interval = 10000,
n_intervals = 0
),
html.Div(dbc.Row([
dbc.Col(html.H2(id='check_update_div', children='check ' ))
]) )
]
)
#app.callback(
Output('check_update_div', 'children'),
[ Input('graph-update', 'n_intervals') ]
)
def update_graph_scatter(n):
print('one loop done ')
a = monitor_ftp()
return ("this is X {}".format(a))
I want to tie everything together and create a dash app which monitors the ftp directory and plots the result of data extract , currently I don't have a graph in my app, I have just put a div which I want to update with the file name for every new file that appears in the folder , but I am not sure how to combine these functions together. Can you please help.
Edit:
I have got a working example which shows that ftp inside the callback function prevents the function from returning anything , if ftp is outside the return function then callback returns and updates the div every n_intervals
import dash
from dash.dependencies import Output, Input
import dash_core_components as dcc
import dash_html_components as html
import plotly
import random
import plotly.graph_objs as go
from collections import deque
from ftplib import FTP
from time import sleep
#ftp otside the function and function works fine
#Deactivae this part and activate ftp inside the function , and function
#stops returning anything and div is not updated every n_interval
ftp = FTP()
ftp.connect('10.199.44.240', 21)
ftp.login('display')
ftp.cwd('/home/display/test_qc')
print("Connection Established {}".format(ftp.getwelcome()))
direct = 'C:\\Users\\QC\\Desktop\\Gunlink_local\\'
app = dash.Dash(__name__)
app.layout = html.Div([
html.Div([
dcc.Interval(
id = 'graph-update',
interval = 10000,
n_intervals = 0
)
]),
html.Div([
html.H1(id='print_value', children="Output Value"),
])
])
#app.callback(
Output('print_value', 'children'),
[ Input('graph-update', 'n_intervals') ]
)
def update_value(n):
# ftp inside the function prevents the function from returning anything
# Div is not updated every n_interval
'''
ftp = FTP()
ftp.connect('10.199.44.240', 21)
ftp.login('display')
ftp.cwd('/home/display/test_qc')
print("Connection Established {}".format(ftp.getwelcome()))
a = ftp.nlst()
'''
a = ftp.nlst()
sleep(2)
print('one loop done ')
return ("this is X {}".format(a))
if __name__ == '__main__':
app.run_server()
You need the interval component.
Dash cannot do constant updates, like running that while loop nonstop, but you can have the interval set to fire a callback every X seconds. Using that callback, you can check the FTP server on that schedule for updates.
Check out this page of the docs for some good examples of using it to create a live-updating page.