pygel3d.jupyter_display

This is a module with a function, display, that provides functionality for displaying a Manifold or a Graph as an interactive 3D model in a Jupyter Notebook. It is based on plotly.

 1""" This is a module with a function, display, that provides functionality for displaying a
 2    Manifold or a Graph as an interactive 3D model in a Jupyter Notebook. It is based on 
 3    plotly. """
 4from pygel3d import hmesh, graph
 5from numpy import array
 6import plotly.graph_objs as go
 7import plotly.offline as py
 8import plotly.express as px
 9
10
11EXPORT_MODE = False
12
13def set_export_mode(_exp_mode=True):
14    """ Calling this function will set export mode to true. It is necessary
15    to do so if we wish to export a notebook containing interactive
16    plotly graphics (made with display below) to HTML. In other words, this function
17    should not necessarily be called in normal usage but only when we export to HTML. It is
18    then called once in the beginning of the notebook. However, as a bit of a twist on
19    this story, it appears that if we don't call this function, any call to display must
20    be the last thing that happens in a cell. So, maybe it is best to always call
21    set_export_mode in the beginning of a notebook.
22    """
23    global EXPORT_MODE
24    EXPORT_MODE=_exp_mode
25    if EXPORT_MODE:
26        py.init_notebook_mode(connected=False)
27
28def display(m,wireframe=True,smooth=True,data=None):
29    """ The display function shows an interactive presentation of the Manifold, m, inside
30        a Jupyter Notebook. wireframe=True means that a wireframe view of the mesh is
31        superimposed on the 3D model. If smooth=True, the mesh is rendered with vertex
32        normals. Otherwise, the mesh is rendered with face normals. If data=None, the
33        mesh is shown in a light grey color. If data contains an array of scalar values
34        per vertex, these are mapped to colors used to color the mesh. Finally, note that
35        m can also be a Graph. In that case the display function just draws the edges as
36        black lines. """
37    mesh_data = []
38    if isinstance(m,hmesh.Manifold):
39        xyz = array([ p for p in m.positions()])
40        m_tri = hmesh.Manifold(m)
41        hmesh.triangulate(m_tri, clip_ear=False)
42        ijk = array([[ idx for idx in m_tri.circulate_face(f,'v')] for f in m_tri.faces()])
43        mesh = go.Mesh3d(x=xyz[:,0],y=xyz[:,1],z=xyz[:,2],
44                i=ijk[:,0],j=ijk[:,1],k=ijk[:,2],color='#dddddd',flatshading=not smooth)
45        if data is not None:
46            mesh['intensity'] = data
47            mesh['contour'] = {'show': True, 'color': '#ff0000'}
48        mesh_data += [mesh]
49        if wireframe:
50            pos = m.positions()
51            xyze = []
52            for h in m.halfedges():
53                if h < m.opposite_halfedge(h):
54                    p0 = pos[m.incident_vertex(m.opposite_halfedge(h))]
55                    p1 = pos[m.incident_vertex(h)]
56                    xyze.append(array(p0))
57                    xyze.append(array(p1))
58                    xyze.append(array([None, None, None]))
59            xyze = array(xyze)
60            trace1=go.Scatter3d(x=xyze[:,0],y=xyze[:,1],z=xyze[:,2],
61                       mode='lines',
62                       line=dict(color='rgb(125,0,0)', width=1),
63                       hoverinfo='none')
64            mesh_data += [trace1]
65    elif isinstance(m,graph.Graph):
66        pos = m.positions()
67        xyze = []
68        for v in m.nodes():
69            for w in m.neighbors(v):
70                if v < w:
71                    p0 = pos[v]
72                    p1 = pos[w]
73                    xyze.append(array(p0))
74                    xyze.append(array(p1))
75                    xyze.append(array([None, None, None]))
76        xyze = array(xyze)
77        trace1=go.Scatter3d(x=xyze[:,0],y=xyze[:,1],z=xyze[:,2],
78                   mode='lines',
79                   line=dict(color='rgb(0,0,0)', width=1),
80                   hoverinfo='none')
81        mesh_data += [trace1]
82
83        
84    lyt = go.Layout(width=850,height=800)
85    lyt.scene.aspectmode="data"
86    if EXPORT_MODE:
87        py.iplot(dict(data=mesh_data,layout=lyt))
88    else:
89        return go.FigureWidget(mesh_data,lyt)
def set_export_mode(_exp_mode=True):
14def set_export_mode(_exp_mode=True):
15    """ Calling this function will set export mode to true. It is necessary
16    to do so if we wish to export a notebook containing interactive
17    plotly graphics (made with display below) to HTML. In other words, this function
18    should not necessarily be called in normal usage but only when we export to HTML. It is
19    then called once in the beginning of the notebook. However, as a bit of a twist on
20    this story, it appears that if we don't call this function, any call to display must
21    be the last thing that happens in a cell. So, maybe it is best to always call
22    set_export_mode in the beginning of a notebook.
23    """
24    global EXPORT_MODE
25    EXPORT_MODE=_exp_mode
26    if EXPORT_MODE:
27        py.init_notebook_mode(connected=False)

Calling this function will set export mode to true. It is necessary to do so if we wish to export a notebook containing interactive plotly graphics (made with display below) to HTML. In other words, this function should not necessarily be called in normal usage but only when we export to HTML. It is then called once in the beginning of the notebook. However, as a bit of a twist on this story, it appears that if we don't call this function, any call to display must be the last thing that happens in a cell. So, maybe it is best to always call set_export_mode in the beginning of a notebook.

def display(m, wireframe=True, smooth=True, data=None):
29def display(m,wireframe=True,smooth=True,data=None):
30    """ The display function shows an interactive presentation of the Manifold, m, inside
31        a Jupyter Notebook. wireframe=True means that a wireframe view of the mesh is
32        superimposed on the 3D model. If smooth=True, the mesh is rendered with vertex
33        normals. Otherwise, the mesh is rendered with face normals. If data=None, the
34        mesh is shown in a light grey color. If data contains an array of scalar values
35        per vertex, these are mapped to colors used to color the mesh. Finally, note that
36        m can also be a Graph. In that case the display function just draws the edges as
37        black lines. """
38    mesh_data = []
39    if isinstance(m,hmesh.Manifold):
40        xyz = array([ p for p in m.positions()])
41        m_tri = hmesh.Manifold(m)
42        hmesh.triangulate(m_tri, clip_ear=False)
43        ijk = array([[ idx for idx in m_tri.circulate_face(f,'v')] for f in m_tri.faces()])
44        mesh = go.Mesh3d(x=xyz[:,0],y=xyz[:,1],z=xyz[:,2],
45                i=ijk[:,0],j=ijk[:,1],k=ijk[:,2],color='#dddddd',flatshading=not smooth)
46        if data is not None:
47            mesh['intensity'] = data
48            mesh['contour'] = {'show': True, 'color': '#ff0000'}
49        mesh_data += [mesh]
50        if wireframe:
51            pos = m.positions()
52            xyze = []
53            for h in m.halfedges():
54                if h < m.opposite_halfedge(h):
55                    p0 = pos[m.incident_vertex(m.opposite_halfedge(h))]
56                    p1 = pos[m.incident_vertex(h)]
57                    xyze.append(array(p0))
58                    xyze.append(array(p1))
59                    xyze.append(array([None, None, None]))
60            xyze = array(xyze)
61            trace1=go.Scatter3d(x=xyze[:,0],y=xyze[:,1],z=xyze[:,2],
62                       mode='lines',
63                       line=dict(color='rgb(125,0,0)', width=1),
64                       hoverinfo='none')
65            mesh_data += [trace1]
66    elif isinstance(m,graph.Graph):
67        pos = m.positions()
68        xyze = []
69        for v in m.nodes():
70            for w in m.neighbors(v):
71                if v < w:
72                    p0 = pos[v]
73                    p1 = pos[w]
74                    xyze.append(array(p0))
75                    xyze.append(array(p1))
76                    xyze.append(array([None, None, None]))
77        xyze = array(xyze)
78        trace1=go.Scatter3d(x=xyze[:,0],y=xyze[:,1],z=xyze[:,2],
79                   mode='lines',
80                   line=dict(color='rgb(0,0,0)', width=1),
81                   hoverinfo='none')
82        mesh_data += [trace1]
83
84        
85    lyt = go.Layout(width=850,height=800)
86    lyt.scene.aspectmode="data"
87    if EXPORT_MODE:
88        py.iplot(dict(data=mesh_data,layout=lyt))
89    else:
90        return go.FigureWidget(mesh_data,lyt)

The display function shows an interactive presentation of the Manifold, m, inside a Jupyter Notebook. wireframe=True means that a wireframe view of the mesh is superimposed on the 3D model. If smooth=True, the mesh is rendered with vertex normals. Otherwise, the mesh is rendered with face normals. If data=None, the mesh is shown in a light grey color. If data contains an array of scalar values per vertex, these are mapped to colors used to color the mesh. Finally, note that m can also be a Graph. In that case the display function just draws the edges as black lines.