I’m using plotly and dash to create and render two scatter plots, one in 3D and the other in 2D, similar to the network graph examples. I’m using updatemenus
buttons for the update
method to toggle visibility of the markers/lines to go between the 2D and 3D representations.
I’m having issues with the hover text. I currently have it working for the 3D plot, but it will not work for the 2D plot when it is toggled. Hovering over the points in the 3D scatter, I am able to see the hover text. However, when the 2D scatter is visible hover does not work.
Here’s a few interesting things I’ve noticed:
- the order of the traces added to the
Data
element changes the hover behavior - without the
opacity=0.99
setting I’ve put in with when defining themarker
elements for the scatters, the hover doesn’t seem to work correctly: no matter which element I hover over, the hover text is only shown for one of the markers - using box select to zoom in the 2D mode doesn’t work either
My environment is based on Debian testing.
Python Version: 3.6.5rc1
igraph Version: 0.7.1
Plotly Version: 2.5.1
Dash Version: 0.21.1
I’ve tried loading the dash page in several browsers (chrome, firefox), with similar behaviors in each.
I’ve distilled the problem down to a simple self-contained example. Here’s the code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import platform
import string
import random
import igraph as ig
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly
import plotly.plotly as py
import plotly.graph_objs as go
##############################################################################
def randStr(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for x in range(size))
##############################################################################
def getPlotPoints(NetGraph, ThreeDeeMode):
if ThreeDeeMode:
layt = NetGraph.layout('fr_3d', dim=3)
else:
layt = NetGraph.layout('fr', dim=2)
vertexCount = len(NetGraph.vs)
Xn = [layt[k][0] for k in range(vertexCount)]
Yn = [layt[k][1] for k in range(vertexCount)]
Xe = []
Ye = []
if ThreeDeeMode:
Zn = [layt[k][2] for k in range(vertexCount)]
Ze = []
for ePos in [edge.tuple for edge in NetGraph.es]:
Xe += [layt[ePos[0]][0],layt[ePos[1]][0], None]
Ye += [layt[ePos[0]][1],layt[ePos[1]][1], None]
if ThreeDeeMode:
Ze += [layt[ePos[0]][2],layt[ePos[1]][2], None]
if ThreeDeeMode:
return (Xn, Yn, Zn, Xe, Ye, Ze)
else:
return (Xn, Yn, Xe, Ye)
##############################################################################
def main():
print(f"Python Version: {platform.python_version()}")
print(f"igraph Version: {ig.__version__}")
print(f"Plotly Version: {plotly.__version__}")
print(f"Dash Version: {dash.__version__}")
# graph construction
netGraph = ig.Graph.GRG(10, 0.8)
nodeLabels = [randStr(6) for vx in netGraph.vs]
(flatPointsX, flatPointsY, flatLinesX, flatLinesY) = getPlotPoints(netGraph, False)
(cubePointX, cubePointsY, cubePointsZ, cubeLinesX, cubeLinesY, cubeLinesZ) = getPlotPoints(netGraph, True)
# create 3d and 2d network graphs
netTrace1 = go.Scatter3d(name="cubeLines",
x=cubeLinesX,
y=cubeLinesY,
z=cubeLinesZ,
mode='lines',
line=dict(color='rgb(210,210,210)',
width=2),
hoverinfo='none',
visible=True)
netTrace2 = go.Scatter3d(name="cubePoints",
x=cubePointX,
y=cubePointsY,
z=cubePointsZ,
mode='markers',
marker=dict(color='rgb(144, 198, 149)',
size=10,
symbol='dot',
line=dict(color='rgb(108, 122, 137)',
width=0.2),
opacity=0.99),
text=nodeLabels,
hoverinfo='text',
visible=True)
netTrace3 = go.Scatter(name="flatLines",
x=flatLinesX,
y=flatLinesY,
mode='lines',
line=dict(color='rgb(210,210,210)',
width=2),
hoverinfo='none',
visible=False)
netTrace4 = go.Scatter(name="flatPoints",
x=flatPointsX,
y=flatPointsY,
mode='markers',
marker=dict(color='rgb(144, 198, 149)',
size=10,
symbol='dot',
line=dict(color='rgb(108, 122, 137)',
width=0.2),
opacity=0.99),
text=nodeLabels,
hoverinfo='text',
visible=False)
# layout
updatemenus = list([
dict(type="buttons",
active=0,
buttons=list([
dict(label = '3D',
method = 'update',
args = [{'visible': [False, True, False, True]}]),
dict(label = '2D',
method = 'update',
args = [{'visible': [True, False, True, False]}])
]),
)
])
graphWidth = 1280
graphWeight = 960
graphLayout = go.Layout(showlegend=False,
autosize=True,
width=graphWidth,
height=graphWeight,
xaxis = dict(visible=False),
yaxis = dict(visible=False),
scene = dict(xaxis = dict(visible=False),
yaxis = dict(visible=False),
zaxis = dict(visible=False)),
hovermode='closest',
updatemenus=updatemenus)
netGraphData = go.Data([netTrace3, netTrace2, netTrace4, netTrace1])
netFig = go.Figure(data=netGraphData, layout=graphLayout)
# serve HTML
app = dash.Dash(__name__)
server = app.server
app.css.config.serve_locally = True
app.scripts.config.serve_locally = True
app.layout = html.Div([
dcc.Graph(id='networkmap',figure = netFig)])
app.run_server(debug=False, host='127.0.0.1')
if __name__ == '__main__':
main()
Thanks in advance for any help or advice rendered!