Hi everyone! I am new to dash and I am trying to create a callback which will update my Interactive Image and my Graph which is showing histogram of pixel values from the image. Here is how my layout looks like:
def serve_layout():
# Generates a session ID
session_id = str(uuid.uuid4())
# Post the image to the right key, inside the bucket named after the
# session ID
store_image_string(utils.IMAGE_STRING_PLACEHOLDER, session_id)
# App Layout
return html.Div(
id="root",
children=[
# Session ID
html.Div(session_id, id="session-id"),
# Main body
html.Div(
id="app-container",
children=[
html.Div(
id="image",
children=[
# The Interactive Image Div contains the dcc Graph
# showing the image, as well as the hidden div storing
# the true image
html.Div(
id="div-interactive-image",
children=[
utils.GRAPH_PLACEHOLDER,
html.Div(
id="div-storage",
children=utils.STORAGE_PLACEHOLDER,
),
],
)
],
),
drc.Card(
[
dcc.Upload(
id="upload-image",
children=[
"Drag and Drop or ",
html.A(children="Select an Image"),
],
# No CSS alternative here
style={
"color": "darkgray",
"width": "100%",
"height": "20px",
"lineHeight": "20px",
"borderWidth": "1px",
"borderStyle": "dashed",
"borderRadius": "5px",
"borderColor": "gray",
"textAlign": "center",
"padding": "2rem 0",
"margin-bottom": "2rem",
},
accept="image/*",
),
]
),
],
),
# Sidebar
html.Div(
id="sidebar",
children=[
drc.Card(
[
drc.NamedInlineRadioItems(
name="Selection Mode",
short="selection-mode",
options=[
{"label": " Rectangular", "value": "select"},
{"label": " Lasso", "value": "lasso"},
],
val="select",
),
drc.CustomDropdown(
id="dropdown-roi",
options=[
{"label": "Find Abnormalities", "value": "find_abn"},
{"label": "Show Ground Truth", "value": "show_gt"},
{"label": "Classification", "value": "classify"},
],
searchable=False,
placeholder="Region of Interest (ROI)",
),
drc.CustomDropdown(
id="dropdown-filters",
options=[
],
searchable=False,
placeholder="Basic Filter...",
),
drc.CustomDropdown(
id="dropdown-enhance",
options=[
{"label": "Binarize", "value": "binarize"},
{"label": "Negative", "value": "negative"},
{"label": "Contrast Limited Adaptive Histogram Equalization (CLAHE)", "value": "clahe"},
{"label": "Adaptive Gamma Contrast Weighted Distribution (AGCWD)", "value": "agcwd"},
],
searchable=False,
placeholder="Enhance...",
),
html.Div(
id="div-enhancement-factor",
children=[
f"Enhancement Factor:",
html.Div(
children=dcc.Slider(
id="slider-enhancement-factor",
min=0,
max=2,
step=0.1,
value=1,
updatemode="drag",
)
),
],
),
html.Div(
id="button-group",
children=[
html.Button(
"Run Operation", id="button-run-operation"
),
html.Button(
"ROI Histogram", id="button-update-graph"
),
html.Button("Undo", id="button-undo"),
],
),
]
),
dcc.Graph(
id="graph-histogram-grayvalues",
figure={
"layout": {
"paper_bgcolor": "#272a31",
"plot_bgcolor": "#272a31",
}
},
config={"displayModeBar": False},
),
],
),
],
)
app.layout = serve_layout
And here is how I designed my callback which should update interactive image (specifically action stack on its storage) and my graph of pixel value histogram.
@app.callback(
[
Output("graph-histogram-grayvalues", "figure"),
Output("div-interactive-image", "children"),
],
[
Input("interactive-image", "figure"),
Input("button-update-graph", "n_clicks"),
Input("button-undo", "n_clicks"),
],
[
State("interactive-image", "selectedData"),
State("div-storage", "children"),
State("radio-selection-mode", "value"),
]
)
def update_histogram(figure, n_clicks, undo_clicks, selectedData, storage, dragmode):
storage = json.loads(storage)
filename = storage["filename"] # Filename is the name of the image file.
image_signature = storage["image_signature"]
# Runs the undo function if the undo button was clicked. Storage stays
# the same otherwise.
storage = undo_last_action(undo_clicks, storage)
enc_str = figure["layout"]["images"][0]["source"].split(";base64,")[-1]
# Creates the PIL Image object from the b64 png encoding
im_pil = drc.b64_to_pil(string=enc_str)
im_size = im_pil.size
# Select using Lasso
if selectedData and "lassoPoints" in selectedData:
selection_mode = "lasso"
selection_zone = utils.generate_lasso_mask(im_pil, selectedData)
selection_zone_np = np.array(selection_zone).flatten()
selection_zone_np = selection_zone_np[selection_zone_np != 0]
im_pil = Image.fromarray(np.expand_dims(selection_zone_np, 0))
add_action_to_stack(storage["action_stack"], n_clicks, "button-click", selectedData)
# Select using rectangular box
elif selectedData and "range" in selectedData:
print("[INFO]: ROI selected with RECTANGLE")
selection_mode = "select"
lower, upper = map(int, selectedData["range"]["y"])
left, right = map(int, selectedData["range"]["x"])
# Adjust height difference
height = im_size[1]
upper = height - upper
lower = height - lower
selection_zone = (left, upper, right, lower)
im_pil = im_pil.crop(selection_zone)
add_action_to_stack(storage["action_stack"], n_clicks, "button-click", selectedData)
return utils.show_histogram(im_pil), [
drc.InteractiveImagePIL(
image_id="interactive-image",
image=im_pil,
dragmode=dragmode,
verbose=DEBUG,
selectedData=selectedData,
),
html.Div(
id="div-storage", children=json.dumps(storage), style={"display": "none"}
),
]
For some reason this code does not work and I am not seeing any error messages, but when I run my dash up neither image or graph are being shown. Take a look:
On the image above DEAFULT image should be loaded and graph should be showing pixel value histogram.
Any help would be appreciated. Much thanks!