-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
_graph.py
168 lines (132 loc) · 6.45 KB
/
_graph.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#-----------------------------------------------------------------------------
# Copyright (c) 2012 - 2023, Anaconda, Inc., and Bokeh Contributors.
# All rights reserved.
#
# The full license is in the file LICENSE.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Boilerplate
#-----------------------------------------------------------------------------
from __future__ import annotations
import logging # isort:skip
log = logging.getLogger(__name__)
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
# Standard library imports
import sys
# Bokeh imports
from ..core.properties import field
from ..models import (
Circle,
ColumnarDataSource,
ColumnDataSource,
GlyphRenderer,
MultiLine,
Scatter,
)
from ._renderer import make_glyph, pop_visuals
#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------
__all__ = (
'get_graph_kwargs'
)
RENDERER_ARGS = ['name', 'level', 'visible', 'x_range_name', 'y_range_name',
'selection_policy', 'inspection_policy']
#-----------------------------------------------------------------------------
# General API
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Dev API
#-----------------------------------------------------------------------------
def get_graph_kwargs(node_source, edge_source, **kwargs):
if not isinstance(node_source, ColumnarDataSource):
try:
# try converting the source to ColumnDataSource
node_source = ColumnDataSource(node_source)
except ValueError as err:
msg = f"Failed to auto-convert {type(node_source)} to ColumnDataSource.\n Original error: {err.message}"
raise ValueError(msg).with_traceback(sys.exc_info()[2])
if not isinstance(edge_source, ColumnarDataSource):
try:
# try converting the source to ColumnDataSource
edge_source = ColumnDataSource(edge_source)
except ValueError as err:
msg = f"Failed to auto-convert {type(edge_source)} to ColumnDataSource.\n Original error: {err.message}"
raise ValueError(msg).with_traceback(sys.exc_info()[2])
marker = kwargs.pop('node_marker', None)
marker_type = Scatter
if isinstance(marker, dict) and 'field' in marker or marker in node_source.data:
kwargs['node_marker'] = field(marker)
else:
if isinstance(marker, dict) and 'value' in marker:
marker = marker['value']
if marker is None or marker == "circle":
marker_type = Circle
else:
kwargs["node_marker"] = marker
## node stuff
node_visuals = pop_visuals(marker_type, kwargs, prefix="node_")
if any(x.startswith('node_selection_') for x in kwargs):
snode_visuals = pop_visuals(marker_type, kwargs, prefix="node_selection_", defaults=node_visuals)
else:
snode_visuals = None
if any(x.startswith('node_hover_') for x in kwargs):
hnode_visuals = pop_visuals(marker_type, kwargs, prefix="node_hover_", defaults=node_visuals)
else:
hnode_visuals = None
mnode_visuals = pop_visuals(marker_type, kwargs, prefix="node_muted_", defaults=node_visuals, override_defaults={'alpha':0.2})
nsnode_visuals = pop_visuals(marker_type, kwargs, prefix="node_nonselection_", defaults=node_visuals)
## edge stuff
edge_visuals = pop_visuals(MultiLine, kwargs, prefix="edge_")
if any(x.startswith('edge_selection_') for x in kwargs):
sedge_visuals = pop_visuals(MultiLine, kwargs, prefix="edge_selection_", defaults=edge_visuals)
else:
sedge_visuals = None
if any(x.startswith('edge_hover_') for x in kwargs):
hedge_visuals = pop_visuals(MultiLine, kwargs, prefix="edge_hover_", defaults=edge_visuals)
else:
hedge_visuals = None
medge_visuals = pop_visuals(MultiLine, kwargs, prefix="edge_muted_", defaults=edge_visuals, override_defaults={'alpha':0.2})
nsedge_visuals = pop_visuals(MultiLine, kwargs, prefix="edge_nonselection_", defaults=edge_visuals)
## node stuff
node_kwargs = {k.lstrip('node_'): v for k, v in kwargs.copy().items() if k.lstrip('node_') in marker_type.properties()}
node_glyph = make_glyph(marker_type, node_kwargs, node_visuals)
nsnode_glyph = make_glyph(marker_type, node_kwargs, nsnode_visuals)
snode_glyph = make_glyph(marker_type, node_kwargs, snode_visuals)
hnode_glyph = make_glyph(marker_type, node_kwargs, hnode_visuals)
mnode_glyph = make_glyph(marker_type, node_kwargs, mnode_visuals)
node_renderer = GlyphRenderer(
data_source=node_source,
glyph=node_glyph,
selection_glyph=snode_glyph or "auto",
nonselection_glyph=nsnode_glyph or "auto",
hover_glyph=hnode_glyph,
muted_glyph=mnode_glyph or "auto",
)
## edge stuff
edge_kwargs = {k.lstrip('edge_'): v for k, v in kwargs.copy().items() if k.lstrip('edge_') in MultiLine.properties()}
edge_glyph = make_glyph(MultiLine, edge_kwargs, edge_visuals)
nsedge_glyph = make_glyph(MultiLine, edge_kwargs, nsedge_visuals)
sedge_glyph = make_glyph(MultiLine, edge_kwargs, sedge_visuals)
hedge_glyph = make_glyph(MultiLine, edge_kwargs, hedge_visuals)
medge_glyph = make_glyph(MultiLine, edge_kwargs, medge_visuals)
edge_renderer = GlyphRenderer(
data_source=edge_source,
glyph=edge_glyph,
selection_glyph=sedge_glyph or "auto",
nonselection_glyph=nsedge_glyph or "auto",
hover_glyph=hedge_glyph,
muted_glyph=medge_glyph or "auto",
)
renderer_kwargs = {attr: kwargs.pop(attr) for attr in RENDERER_ARGS if attr in kwargs}
renderer_kwargs["node_renderer"] = node_renderer
renderer_kwargs["edge_renderer"] = edge_renderer
return renderer_kwargs
#-----------------------------------------------------------------------------
# Private API
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------