I want to update a html content after a calculation from the server side to the client side.
I have an example where a random image is created in background but to see the image/content immediately I need to wait (from the client side) an amount of time before I get the content from the server. (now imagine the calculation would need/take > 10 seconds or even minutes!)
Here is the example code:
import base64
import dash
import flask
import hashlib
import inspect
import os
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
from PIL import Image
from dash.dependencies import Input, Output
STATIC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static')
if not os.path.exists(STATIC_PATH):
os.makedirs(STATIC_PATH)
if STATIC_PATH[-1] != "/":
STATIC_PATH += "/"
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server, external_stylesheets=external_stylesheets)
app.config['suppress_callback_exceptions']=True
app.title = 'Random Images'
colors = {
'fg_div1': '#7FFF80',
'fg_h1': '#6734D2',
'fg_p': '#E0F040',
'bg_button_1': '#30E090',
'bg_button_2': '#40A0A0',
}
def get_random_picture(height, width):
return Image.fromarray(np.random.randint(0, 256, (height, width, 3), dtype=np.uint8))
def get_sha512_value(file_path):
with open(file_path, 'rb') as fin:
hexdigest = hashlib.sha512(fin.read()).hexdigest()
return hexdigest
def create_random_image(size):
img = get_random_picture(size, size)
img.save(STATIC_PATH+'random_image_{}_{}.png'.format(size, size))
app.layout = html.Div(
className='row',
style={
'margin-left': 'auto',
'margin-right': 'auto',
'display': 'flex',
'justify-content': 'center',
'align-items': 'center',
},
children=[
html.Div(
style={
'margin-left': 'auto',
'margin-right': 'auto',
'width': '50%',
'margin': '0%',
},
children=[
html.Div(
style={
'textAlign': 'center',
},
children=[
html.H1(
style={
'textAlign': 'center',
'color': colors['fg_h1'],
'display': 'inline-block',
'margin-top': '20px',
},
children=[
'Random Image'
]),
]),
html.Div(
style={'textAlign': 'center'},
children=[
html.P(
style={
'textAlign': 'center',
'color': colors['fg_p'],
'display': 'inline-block',
'font-size': '16px',
},
children=[
'Create a simple random image!'
]),
]),
html.Div(
className='row',
style={
'margin-left': 'auto',
'margin-right': 'auto',
},
children=[
html.Div(
className='row',
style={
'text-align': 'center',
},
children=[
html.Span(
id='create_128_128_image',
className='button button--primary add noselect',
style={
'background-color': colors['bg_button_1'],
'margin-left': '10px',
'margin-right': '10px',
},
children=[
'Create 128x128 Random Image'
]),
html.Span(
id='load_128_128_image',
n_clicks=0,
className='button button--primary add noselect',
style={
'background-color': colors['bg_button_2'],
'margin-left': '10px',
'margin-right': '10px',
},
children=[
'Load 128x128 Image'
]),
html.Span(
id='remove_128_128_image',
n_clicks=0,
className='button button--primary add noselect',
style={
'background-color': colors['bg_button_2'],
'margin-left': '10px',
'margin-right': '10px',
},
children=[
'Remove 128x128 Image'
]),
]),
html.Div(
id='random_image_display',
),
]),
]),
])
# size is for height and width of the image
def button_pressed_random_picture(size, more_text=''):
file_name = 'random_image_{}_{}.png'.format(size, size)
file_path = STATIC_PATH+'/'+file_name
sha512_value = get_sha512_value(file_path).upper()
sha512_value_split = (lambda length: [sha512_value[length*i:length*(i+1)] for i in range(0, 4)])(len(sha512_value)//4)
with open(file_path, 'rb') as fin:
encoded_image = base64.b64encode(fin.read())
src='data:image/png;base64,{}'.format(encoded_image.decode())
print('Now it is {}x{} a random image'.format(size, size))
return [
html.Div(
style={
'color': colors['fg_div1'],
'text-align': 'center',
'margin-top': '10px',
'margin-bottom': '10px',
},
children=[
html.Div('Test {}x{}{}'.format(size, size, more_text)),
html.Div('SHA512 sum of file "{}":'.format('/static/'+file_name)),
]+[
html.Div('{}'.format(sha512_value_part),
style={
'font-family': 'monospace, sans-serif',
'margin-left': 'auto',
'margin-right': 'auto',
})
for sha512_value_part in sha512_value_split
]+[
html.Img(
id='random_image',
src=src,
style={
'height': '{}px'.format(size),
'width': '{}px'.format(size),
}),
]),
]
@app.callback(
Output('random_image_display', 'children'),
[
Input('create_128_128_image', 'n_clicks_timestamp'),
Input('load_128_128_image', 'n_clicks_timestamp'),
Input('remove_128_128_image', 'n_clicks_timestamp'),
]
)
def display_calculation_labyrinth(nt1, nt2, nt3):
if nt1 == None:
nt1 = 0
if nt2 == None:
nt2 = 0
if nt3 == None:
nt3 = 0
button_num = np.argmax([nt1, nt2, nt3])
print('button_num: {}'.format(button_num))
if button_num == 0:
# TODO: First update random_image_display with e.g. html.Div('Calculating new image...')
create_random_image(128)
# TODO: After the calculation/function do an update of the content in random_image_display!
layout = button_pressed_random_picture(128)
elif button_num == 1:
size = 128
layout = button_pressed_random_picture(128, more_text=', only loaded the image now!')
elif button_num == 2:
layout = [
html.Div('Delted Content!',
style={
'color': '#FFFFFF',
'text-align': 'center'
})
]
return layout
if __name__ == '__main__':
app.run_server(debug=True, host='0.0.0.0', port='31415')
Consider after pressing the create button, there should normally come a message like ‘Image is in process, waiting…’ or what ever.
Now I have seen some questions like here (which is empty so far),
Or here, but I know I could use dcc.Interval to make this working.
To be more precise: I only want to update the content when the calculation/function is finished!
Is there already a similar problem with a solution? Or is there maybe another approach to solve this kind of problem?
Any kind of help would be really nice and thank you in advance.