How to display image on point hover of 3D plot in python?

According to this thread, displaying images on point hover isn't possible in plotly-python but might be built out in the future.

However, you can accomplish this in plotly-dash because this library allows you to modify the html using callbacks.

Following the example here, I created some sample data and a go.Scatter3d figure that matches your use case a bit more:

from dash import Dash, dcc, html, Input, Output, no_update
import plotly.graph_objects as go
import pandas as pd

## create sample random data
df = pd.DataFrame({
    'x': [1,2,3],
    'y': [2,3,4],
    'z': [3,4,5],
    'color': ['red','green','blue'],
    'img_url': [
        "https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Stack_Overflow_logo.svg/2880px-Stack_Overflow_logo.svg.png",
        "https://upload.wikimedia.org/wikipedia/commons/3/37/Plotly-logo-01-square.png",
        "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Pandas_logo.svg/2880px-Pandas_logo.svg.png"
    ]
})

fig = go.Figure(data=[
    go.Scatter3d(
        x=df['x'], 
        y=df['y'], 
        z=df['z'],
        mode='markers',
        marker=dict(color=df['color'])
    )
])

# turn off native plotly.js hover effects - make sure to use
# hoverinfo="none" rather than "skip" which also halts events.
fig.update_traces(hoverinfo="none", hovertemplate=None)
fig.update_layout(
    scene = dict(
        xaxis = dict(range=[-1,8],),
                     yaxis = dict(range=[-1,8],),
                     zaxis = dict(range=[-1,8],),
    ),
)
app = Dash(__name__)

app.layout = html.Div([
    dcc.Graph(id="graph-basic-2", figure=fig, clear_on_unhover=True),
    dcc.Tooltip(id="graph-tooltip"),
])


@app.callback(
    Output("graph-tooltip", "show"),
    Output("graph-tooltip", "bbox"),
    Output("graph-tooltip", "children"),
    Input("graph-basic-2", "hoverData"),
)
def display_hover(hoverData):
    if hoverData is None:
        return False, no_update, no_update

    # demo only shows the first point, but other points may also be available
    pt = hoverData["points"][0]
    bbox = pt["bbox"]
    num = pt["pointNumber"]

    df_row = df.iloc[num]
    img_src = df_row['img_url']

    children = [
        html.Div([
            html.Img(src=img_src, style={"width": "100%"}),
        ], style={'width': '100px', 'white-space': 'normal'})
    ]

    return True, bbox, children

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

EDIT: I am also including an answer that allows you to run a dash app from a jupyter notebook based on this sample notebook:

from jupyter_dash import JupyterDash
from dash import Dash, dcc, html, Input, Output, no_update
import plotly.graph_objects as go
import pandas as pd

## create sample random data
df = pd.DataFrame({
    'x': [1,2,3],
    'y': [2,3,4],
    'z': [3,4,5],
    'color': ['red','green','blue'],
    'img_url': [
        "https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Stack_Overflow_logo.svg/2880px-Stack_Overflow_logo.svg.png",
        "https://upload.wikimedia.org/wikipedia/commons/3/37/Plotly-logo-01-square.png",
        "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Pandas_logo.svg/2880px-Pandas_logo.svg.png"
    ]
})

fig = go.Figure(data=[
    go.Scatter3d(
        x=df['x'], 
        y=df['y'], 
        z=df['z'],
        mode='markers',
        marker=dict(color=df['color'])
    )
])

# turn off native plotly.js hover effects - make sure to use
# hoverinfo="none" rather than "skip" which also halts events.
fig.update_traces(hoverinfo="none", hovertemplate=None)
fig.update_layout(
    scene = dict(
        xaxis = dict(range=[-1,8],),
                     yaxis = dict(range=[-1,8],),
                     zaxis = dict(range=[-1,8],),
    ),
)

app = JupyterDash(__name__)

server = app.server

app.layout = html.Div([
    dcc.Graph(id="graph-basic-2", figure=fig, clear_on_unhover=True),
    dcc.Tooltip(id="graph-tooltip"),
])


@app.callback(
    Output("graph-tooltip", "show"),
    Output("graph-tooltip", "bbox"),
    Output("graph-tooltip", "children"),
    Input("graph-basic-2", "hoverData"),
)
def display_hover(hoverData):
    if hoverData is None:
        return False, no_update, no_update

    # demo only shows the first point, but other points may also be available
    pt = hoverData["points"][0]
    bbox = pt["bbox"]
    num = pt["pointNumber"]

    df_row = df.iloc[num]
    img_src = df_row['img_url']

    children = [
        html.Div([
            html.Img(src=img_src, style={"width": "100%"}),
        ], style={'width': '100px', 'white-space': 'normal'})
    ]

    return True, bbox, children

app.run_server(mode="inline")

enter image description here