Black Lives Matter. Please consider donating to Black Girls Code today.

Looking for a better way to display image

Ultimately I want a scatter plot shown on the left and an image shown on the right. When the mouse is hovered over a data point in the scatter plot, I want the image shown on the right to be updated. There are probably a few ways to go about doing this. My approach, which is probably not the best way, is to show the image as a background image in a “figure” and hide the axis lines, grid, and tick marks (which I have not implemented in my code just yet). As it stands, the scatter plot is displayed fine, however, the background image is not seen. The issue (as best I can tell) is not related to the image being off-screen. Below is my script. If there is a better way, I would love to hear it.

import dash
import dash_core_components as dcc
from dash.dependencies import Input, Output
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
import base64

app = dash.Dash()
app.css.append_css({'external_url': 'https://codepen.io/illsci/pen/wxZMQm.css'})

df = pd.read_csv(r'test.csv')

y_data = 'ER'
x_data = 'channels'

app.layout = html.Div(className="row", children=[
    html.Div([
        dcc.Graph(
            id='scatter',
            figure={
                'data': [{
                    'x': df[x_data],
                    'y': df[y_data],
                    'customdata': df['filename'],
                    'mode': 'markers',
                    'marker': {
                        'size': 12,
                        'color': 'rgba(0, 116, 217, 0.5)',
                        'line': {
                            'color': 'rgb(0, 116, 217)',
                            'width': 0.5
                        }
                    }
                }],
                'layout': {
                    'xaxis': {
                        'title': x_data,
                    },
                    'yaxis': {
                        'title': y_data,
                    },
                    'margin': {
                        'l': 50,
                        'r': 10,
                        't': 80,
                        'b': 50
                    },
		'title':"Peak Position vs. ER",
		'hovermode': 'closest'
                }
            },
            hoverData={'points': [{'customdata': 'test.mca'}]}
        )
    ], className="six columns"),

    html.Div([
	dcc.Graph(id='image', 
		)
	], className="six columns")
])

image_route = 'C:/users/test/'

def get_image (encoded_image):
	return{
		'data': [go.Scatter(
			x=[0,1000],
			y=[0,1000],
		)],
		'layout':{
			'height': 0,
			'margin': {'l': 50, 'b': 30, 'r': 10, 't': 10},
			'images': {
				'source': encoded_image,
				'xref': 'x',
				'yref': 'y',
				'x':0,
				'y':500,
				'sizex':200,
				'sizey':200,
				'sizing': 'contain',
				'visible': True,
				'layer': 'above'
				}
			}}
			
@app.callback(
    dash.dependencies.Output('image', 'figure'),
    [dash.dependencies.Input('scatter', 'hoverData')])
def update_plot_timeseries(hoverData):
	filename = hoverData['points'][0]['customdata']
	image_name=filename+".png"
	location = image_route + image_name
	with open('%s' %location, "rb") as image_file:
			encoded_string = base64.b64encode(image_file.read()).decode()
	encoded_image = "data:image/png;base64," + encoded_string
	
	return get_image (encoded_image)

if __name__ == '__main__':
	app.run_server(debug=False, port=8090)
1 Like

I did something like that in a dashboard that I created for myself. The code for that is on GitHub.

The particular parts of the code, that are relevant to what you want to do, look like this:

html.Div(
        className="row",
        style=css_style["plotting-area"],
        children=[
            dcc.Graph(
                id="weight-plot",
                className="nine columns",
                figure=weight_plot(df_weight),
                hoverData={"points": [{"x": most_recent_date_weight}]}
            ),
            html.Img(
                id="body-image",
                className="three columns"
            ),

and this:

@app.callback(Output("body-image", "src"),
             [Input("weight-plot", "hoverData")])
def update_body_image(hover_data):
    date = hover_data["points"][0]["x"]
    src = "/assets/{}.jpg".format(date)
        
    return src

PS: The dash user guide contains a section that explains how you can embed images in your app.

1 Like

What if I want to show image from the URL?

And also not download the image as it’s gonna increase the size of my image?

Hi @mantey, I ran the Tutorial you referred to:
https://dash.plotly.com/external-resources

However, it appears that folder structure and name (assets) has to be exactly as shown. Do you know of a way to show an image from another location in my machine?

I tried html.Img(src=r'C://Users/knight/Documents/snapshot.png') but that didn’t work.

Okay, this is how I solved it (attempting to load C:/Users/knight/Documents/asset_test/snapshot.png):

app = dash.Dash(__name__,
                assets_folder= 'C:/Users/knight/Documents/asset_test',
                assets_url_path='/')      

Then:

app.layout= html.Div([
    html.Img(id= 'matplotlib-plot', src='snapshot.png')
])