Insert image to DataTable tooltip_data from callback with dcc.upload

I write the code below to let users upload photos, then I use a callback to update datatable according to number of photos uploaded.
To let users preview their uploaded photos, I want to display them wth tooltip_data in datatable accordingly.

    dcc.Upload(id='upload-image', children=html.Div(['Drag and Drop or ', html.A('Select Files')]),
          style={'width': '100%','height': '60px', 'lineHeight': '60px', 'borderWidth': '1px', 'borderStyle': 'dashed',
             'borderRadius': '5px','textAlign': 'center', 'margin': '10px'}, multiple=True)
    ),
    html.Hr(),
    dash_table.DataTable(id = "site_photo_datatable",
               columns = [{"id":col, "name":col} for col in ["Photo", "Photo Date", "Location", "Remarks"]],
               data=[{"Photo":"default.jpg", "Photo Date":today, "Location":"Location", "Remarks":"Remarks"}],
               tooltip_data = [],
               editable = True,
               column_selectable = "multi",
               row_deletable = True,
               style_cell = {"textAlign":"left"},
               style_header={"backgroundColor":"Aquamarine", "font-weight":"bold"}),
    ])

@app.callback(Output('site_photo_datatable', 'data'),
       Output('site_photo_datatable', 'tooltip_data'),       
       Input('upload-image', 'contents'),
       State('upload-image', 'filename'),
       State("site_photo_datatable", "data"),
       prevent_initial_call = True
)
def update_output(contents, filename, data):
  if contents is not None:
    photo_no = 1
    data = []
    tooltip_for_table = []
    for i in range(len(contents)):
      data.append({"Photo":f"Photo {photo_no}", "Photo Date":today, "Location":"", "Remarks":""})
      tooltip_for_table.append({"Photo": {"value": f"![]({html.Img(src=contents[photo_no-1])})",
                   "type":"markdown"}})
      photo_no += 1
    return data, tooltip_for_table

However, after I run the code, I only get a blank tooltip pop-up cell, without photo displayed. Any advice?

app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])

*I have used bootstrap in my code, in case it matters

Hi @munchkit

The tooltip in DataTable does not support components like html.Img. It also doesn’t look like it supports the base64 encoded image that’s uploaded.

However, you can do this with a custom tooltip using Dash AG Grid. Here’s an example

import dash
from dash import dcc, html, Dash, Input, Output, State
import dash_ag_grid as dag

app = Dash(__name__)

upload = dcc.Upload(
    id="upload-image",
    children=html.Div(["Drag and Drop or ", html.A("Select Image Files")]),
    style={
        "width": "100%",
        "height": "60px",
        "lineHeight": "60px",
        "borderWidth": "1px",
        "borderStyle": "dashed",
        "borderRadius": "5px",
        "textAlign": "center",
        "margin": "10px",
    },
    multiple=True,
)

grid = dag.AgGrid(
    id="site-photo-grid",
    rowData=[
        {
            "Photo": "default.jpg",
            "Location": "Location",
            "Remarks": "Remarks",
            "Image": "",
        }
    ],
    columnDefs=[
        {
            "field": "Photo",
            "tooltipComponent": "CustomTooltipImage",
            "tooltipField": "Photo",
        },
        {"field": "Location"},
        {"field": "Remarks"},
    ],
    defaultColDef={"editable": True},
    dashGridOptions={"tooltipShowDelay": 100},
    columnSize="sizeToFit",
)

app.layout = html.Div([upload, grid])


@app.callback(
    Output("site-photo-grid", "rowData"),
    Input("upload-image", "contents"),
    State("upload-image", "filename"),
    prevent_initial_call=True,
)
def update_output(contents, filename):
    if contents:
        photo_no = 1
        data = []
        for i in range(len(contents)):
            data.append(
                {
                    "Photo": f"Photo {photo_no}",
                    "Location": "",
                    "Remarks": "",
                    "Image": contents[photo_no - 1],
                }
            )
            photo_no += 1
        return data
    return dash.no_update


if __name__ == "__main__":
    app.run_server(debug=True)


For the custom tooltip:

Put the following in the dashAgGridComponentFunctions.js file in the assets folder


var dagcomponentfuncs = window.dashAgGridComponentFunctions = window.dashAgGridComponentFunctions || {};

dagcomponentfuncs.CustomTooltipImage = function (props) {
  return React.createElement(
    'img',
    {
      style: {
        width: '100%',
        maxWidth: '200px',
        height: 'auto',
        border: '2px solid grey',
        pointerEvents: 'none',
      },
      src: props.data.Image
    },
  );
};

You can find more information on custom tooltips here:

1 Like