# Highlighting scatter3d selection via callback & mesh3d blocking click event

**URL:** <https://community.plotly.com/t/highlighting-scatter3d-selection-via-callback-mesh3d-blocking-click-event/32006>\
**Category:** Dash Python\
**Created:** [November 29, 2019, 4:46am UTC](https://community.plotly.com/t/highlighting-scatter3d-selection-via-callback-mesh3d-blocking-click-event/32006 "2019-11-29T04:46:49Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![aochtman](https://avatars.discourse-cdn.com/v4/letter/a/53a042/32.png) [@aochtman](https://community.plotly.com/u/aochtman)\
**Post date:** [November 29, 2019, 4:46am UTC](https://community.plotly.com/t/highlighting-scatter3d-selection-via-callback-mesh3d-blocking-click-event/32006/1 "2019-11-29T04:46:49Z")

</div>

I have created a 3D scatter plot of my data. This data can be divided into labeled data and non labeled data but all belonging to one instance.

The goal was to show a 3d model of this data with a difference in color for labeled and non labeled points. I also tried to add a mesh3d to get a better feel of the model. The code can be found below

# Questions

1. I would like to highlight a selected point in my scatter3d plot. Make it bigger / change color- whatever is visible. How can this be done via callback?
2. How can I avoid my mesh3d of blocking clickable points (labeled and non-labeled)?

# Code

#3d model cluster  
labeled = dict(  
mode = “markers”,  
name = “Labeled”,  
type = “scatter3d”,  
opacity = 0.5,  
x = df\_labeled[‘x’].values,  
y = df\_labeled[‘y’].values,  
z = df\_labeled[‘z’].values,  
ids = df\_labeled[‘id’].values,  
text = df\_labeled[‘id’].values,  
hoverinfo = ‘text’,  
marker = dict( size=2, color=“red” )  
)

nonlabeled = dict(  
mode = “markers”,  
name = “Non Labeled”,  
type = “scatter3d”,  
opacity = 0.3,  
x = df\_nonlabeled[‘x’].values,  
y = df\_nonlabeled[‘y’].values,  
z = df\_nonlabeled[‘z’].values,  
ids = df\_nonlabeled[‘id’].values,  
text = df\_nonlabeled[‘id’].values,  
hoverinfo = ‘text’,  
marker = dict( size=4, color=“blue” )  
)

clusters = dict(  
alphahull = 6,  
name = “mesh”,  
color = ‘red’,  
opacity = 0.2,  
type = “mesh3d”,  
x = x,  
y = y,  
z = z,  
mode = ‘markers’,  
hoverinfo = ‘skip’,  
showlegend = True  
)

layout = dict(  
title = ‘3D Point Clustering Model’,  
scene = dict(  
xaxis = dict( zeroline=False ),  
yaxis = dict( zeroline=False ),  
zaxis = dict( zeroline=False ),  
),  
layout = {‘clickmode’: ‘event+select’}  
)

#fig= dict( data=[labeled, nonlabeled, clusters], layout=layout ) # including mesh3d - this blocks clickable points  
fig = dict( data=[labeled, nonlabeled], layout=layout )  
model3d = dcc.Graph(id=“myScatter3d”,figure=fig,style={‘height’: ‘650px’, ‘width’:‘800px’})

---

<div class="post-metadata">

**Author:** ![Emmanuelle](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/emmanuelle/32/7853_2.png) [@Emmanuelle](https://community.plotly.com/u/Emmanuelle)\
**Post date:** [December 1, 2019, 12:35am UTC](https://community.plotly.com/t/highlighting-scatter3d-selection-via-callback-mesh3d-blocking-click-event/32006/2 "2019-12-01T00:35:07Z")

</div>

Hi @aochtman, for the update of the scatter3d via a callback I adapted below the example of [https://dash.plot.ly/interactive-graphing](https://dash.plot.ly/interactive-graphing) (I kept the div because it’s quite useful to see the information in `clickData`, `hoverData` etc).

```auto
import json
from textwrap import dedent as d

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.graph_objects as go
import numpy as np

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash( __name__ , external_stylesheets=external_stylesheets)

styles = {
    'pre': {
        'border': 'thin lightgrey solid',
        'overflowX': 'scroll'
    }
}

fig = go.Figure(go.Scatter3d(x=np.arange(10),
                             y=np.arange(10),
                             z=np.arange(10),
                             marker_size=8 * np.ones(10),
                             mode='markers'))

app.layout = html.Div([
    dcc.Graph(
        id='basic-interactions',
        figure=fig
    ),

    html.Div(className='row', children=[
        html.Div([
            dcc.Markdown(d("""
                **Hover Data**

                Mouse over values in the graph.
            """)),
            html.Pre(id='hover-data', style=styles['pre'])
        ], className='three columns'),

        html.Div([
            dcc.Markdown(d("""
                **Click Data**

                Click on points in the graph.
            """)),
            html.Pre(id='click-data', style=styles['pre']),
        ], className='three columns'),

        html.Div([
            dcc.Markdown(d("""
                **Zoom and Relayout Data**

                Click and drag on the graph to zoom or click on the zoom
                buttons in the graph's menu bar.
                Clicking on legend items will also fire
                this event.
            """)),
            html.Pre(id='relayout-data', style=styles['pre']),
        ], className='three columns')
    ])
])

@app.callback(
    Output('hover-data', 'children'),
    [Input('basic-interactions', 'hoverData')])
def display_hover_data(hoverData):
    return json.dumps(hoverData, indent=2)

@app.callback(
    [Output('click-data', 'children'),
     Output('basic-interactions', 'figure')],
    [Input('basic-interactions', 'clickData')],
    [State('basic-interactions', 'relayoutData')])
def display_click_data(clickData, relayoutData):
    if not clickData:
        return dash.no_update, dash.no_update
    point = clickData["points"][0]
    # Do something only for a specific trace
    if point["curveNumber"] > 0:
        return dash.no_update, dash.no_update
    else: 
        fig = go.Figure(go.Scatter3d(
            x=np.arange(10),
            y=np.arange(10),
            z=np.arange(10),
            mode='markers'))
        sizes = 8 * np.ones(10)
        sizes[point["pointNumber"]] = 15
        colors = ['blue',]*10
        colors[point["pointNumber"]] = 'red'
        fig.update_traces(marker_size=sizes, marker_color=colors)
    # Make sure the view/angle stays the same when updating the figure
    if relayoutData and "scene.camera" in relayoutData:
        fig.update_layout(scene_camera=relayoutData["scene.camera"])
    return json.dumps(clickData, indent=2), fig

@app.callback(
    Output('relayout-data', 'children'),
    [Input('basic-interactions', 'relayoutData')])
def display_relayout_data(relayoutData):
    return json.dumps(relayoutData, indent=2)

if __name__ == ' __main__':
    app.run_server(debug=True, port=8089)

```

In this example I made sure the callback for `clickData` does something only for one single trace so it would exclude the mesh3d but unfortunately I don’t know any way of disabling interaction with one trace.
