spanner-graph-notebook 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. assets/authentication.png +0 -0
  2. assets/full_viz.png +0 -0
  3. assets/hero.png +0 -0
  4. assets/hero_with_properties.png +0 -0
  5. assets/jupyter-spin-up.png +0 -0
  6. assets/load_ext.png +0 -0
  7. assets/mock_data_result.png +0 -0
  8. assets/new_notebook.png +0 -0
  9. assets/notebook_package_load.png +0 -0
  10. assets/query_graph.png +0 -0
  11. assets/sample_jupyter.png +0 -0
  12. spanner_graph_notebook-1.0.0.dist-info/LICENSE +202 -0
  13. spanner_graph_notebook-1.0.0.dist-info/METADATA +169 -0
  14. spanner_graph_notebook-1.0.0.dist-info/RECORD +40 -0
  15. spanner_graph_notebook-1.0.0.dist-info/WHEEL +5 -0
  16. spanner_graph_notebook-1.0.0.dist-info/top_level.txt +2 -0
  17. spanner_graphs/__init__.py +19 -0
  18. spanner_graphs/conversion.py +299 -0
  19. spanner_graphs/database.py +199 -0
  20. spanner_graphs/graph_entities.py +405 -0
  21. spanner_graphs/graph_mock_data.csv +51 -0
  22. spanner_graphs/graph_mock_schema.json +681 -0
  23. spanner_graphs/magics.py +211 -0
  24. spanner_graphs/schema_manager.py +60 -0
  25. templates/assets/images/graph-bg.svg +4 -0
  26. templates/spanner-graph/models/edge.js +77 -0
  27. templates/spanner-graph/models/graph-object.js +64 -0
  28. templates/spanner-graph/models/node.js +77 -0
  29. templates/spanner-graph/models/schema.js +327 -0
  30. templates/spanner-graph/spanner-config.js +304 -0
  31. templates/spanner-graph/spanner-store.js +382 -0
  32. templates/spanner-graph/visualization/spanner-forcegraph.js +1380 -0
  33. templates/spanner-graph/visualization/spanner-sidebar.js +904 -0
  34. templates/template-spannergraph.html +210 -0
  35. tests/__init__.py +13 -0
  36. tests/conversion_test.py +163 -0
  37. tests/database_test.py +62 -0
  38. tests/graph_entities_test.py +124 -0
  39. tests/schema_manager_test.py +115 -0
  40. tests/test_notebook.json +23 -0
@@ -0,0 +1,382 @@
1
+ /**
2
+ * Copyright 2024 Google LLC
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ */
15
+
16
+ /**
17
+ * @callback GraphConfigCallback
18
+ * @param {GraphConfig} config - The graph configuration.
19
+ * @returns {void}
20
+ */
21
+
22
+ /**
23
+ * @callback FocusedGraphObjectCallback
24
+ * @param {GraphObject|null} focusedGraphObject - The graph object currently focused. If null, nothing is focused.
25
+ * @param {GraphConfig} config - The graph configuration.
26
+ * @returns {void}
27
+ */
28
+
29
+ /**
30
+ * @callback SelectedGraphObjectCallback
31
+ * @param {GraphObject|null} selectedGraphObject - The graph object currently selected. If null, nothing is selected.
32
+ * @param {GraphConfig} config - The graph configuration.
33
+ * @returns {void}
34
+ */
35
+
36
+ /**
37
+ * @callback SelectedGraphColorSchemeCallback
38
+ * @param {GraphConfig.ColorScheme} colorScheme - The color scheme to use for nodes.
39
+ * @param {GraphConfig} config - The graph configuration.
40
+ * @returns {void}
41
+ */
42
+
43
+ /**
44
+ * @callback ViewModeChangedCallback
45
+ * @param {ViewModes} ViewMode - The color scheme to use for nodes.
46
+ * @param {GraphConfig} config - The graph configuration.
47
+ * @returns {void}
48
+ */
49
+
50
+ class GraphStore {
51
+ /**
52
+ * The configuration that the graph store is based on.
53
+ * @type {GraphConfig}
54
+ */
55
+ config;
56
+
57
+ /**
58
+ * @type {Object.<string, string>}
59
+ * An object to store reserved colors keyed by label.
60
+ */
61
+ reservedColorsByLabel = {};
62
+
63
+ /**
64
+ * @type {Array.<string>}
65
+ * An array to store reserved colors for neighborhoods.
66
+ */
67
+ reservedColorsByNeighborhood = [];
68
+
69
+
70
+ static EventTypes = Object.freeze({
71
+ CONFIG_CHANGE: Symbol('configChange'),
72
+ FOCUS_OBJECT: Symbol('focusObject'),
73
+ SELECT_OBJECT: Symbol('selectObject'),
74
+ COLOR_SCHEME: Symbol('colorScheme'),
75
+ VIEW_MODE_CHANGE: Symbol('viewModeChange')
76
+ });
77
+
78
+ static ViewModes = Object.freeze({
79
+ DEFAULT: Symbol('Default'),
80
+ SCHEMA: Symbol('Schema')
81
+ });
82
+
83
+ viewMode = GraphStore.ViewModes.DEFAULT;
84
+
85
+ /**
86
+ * Events that are broadcasted to GraphVisualization implementations.
87
+ * @type Map<GraphStore.EventTypes, GraphConfigCallback[]>.
88
+ */
89
+ eventListeners = {
90
+ /**
91
+ * Stores event listeners for config changes.
92
+ * @type {GraphStore.EventTypes.CONFIG_CHANGE, GraphConfigCallback[]>}
93
+ */
94
+ [GraphStore.EventTypes.CONFIG_CHANGE]: [],
95
+ /**
96
+ * @type {GraphStore.EventTypes.FOCUS_OBJECT, FocusedGraphObjectCallback[]>}
97
+ */
98
+ [GraphStore.EventTypes.FOCUS_OBJECT]: [],
99
+ /**
100
+ * @type {GraphStore.EventTypes.SELECT_OBJECT, SelectedGraphObjectCallback[]>}
101
+ */
102
+ [GraphStore.EventTypes.SELECT_OBJECT]: [],
103
+ /**
104
+ * @type {GraphStore.EventTypes.COLOR_SCHEME, SelectedGraphColorSchemeCallback[]>}
105
+ */
106
+ [GraphConfig.ColorScheme.COLOR_SCHEME]: [],
107
+ /**
108
+ * @type {GraphStore.EventTypes.VIEW_MODE_CHANGE, ViewModeChangedCallback[]>}
109
+ */
110
+ [GraphStore.EventTypes.VIEW_MODE_CHANGE]: []
111
+ };
112
+
113
+ /**
114
+ * The data store that a GraphVisualization implementation utilizes.
115
+ * @param GraphConfig
116
+ */
117
+ constructor(config) {
118
+ if (!(config instanceof GraphConfig)) {
119
+ throw Error('Config must be an instance of GraphConfig', config);
120
+ }
121
+
122
+ this.config = config;
123
+ }
124
+
125
+ /**
126
+ * Adds an event listener for a specific event type.
127
+ * @param {GraphStore.EventTypes} eventType - The event type to listen for.
128
+ * @param {GraphConfigCallback} callback - The callback to execute when the event is triggered.
129
+ */
130
+ addEventListener(eventType, callback) {
131
+ if (!this.eventListeners[eventType]) {
132
+ throw Error('Invalid event type', eventType);
133
+ }
134
+
135
+ this.eventListeners[eventType].push(callback);
136
+ }
137
+
138
+ /**
139
+ * @param {ViewModes} viewMode
140
+ */
141
+ setViewMode(viewMode) {
142
+ this.setFocusedObject(null);
143
+ this.setSelectedObject(null);
144
+ this.viewMode = viewMode;
145
+ this.eventListeners[GraphStore.EventTypes.VIEW_MODE_CHANGE]
146
+ .forEach(callback => callback(viewMode, this.config));
147
+ }
148
+
149
+ /**
150
+ * Sets the focused object in the graph and notifies all registered listeners about the focus change.
151
+ * @param {Object} graphObject - The graph object to be focused.
152
+ */
153
+ setFocusedObject(graphObject) {
154
+ this.config.focusedGraphObject = graphObject;
155
+ this.eventListeners[GraphStore.EventTypes.FOCUS_OBJECT].forEach(callback => callback(graphObject, this.config));
156
+ }
157
+
158
+ /**
159
+ * Sets the selected object in the graph and notifies all registered listeners about the selection change.
160
+ * @param {Object} graphObject - The graph object to be selected.
161
+ */
162
+ setSelectedObject(graphObject) {
163
+ this.config.selectedGraphObject = graphObject;
164
+ this.eventListeners[GraphStore.EventTypes.SELECT_OBJECT].forEach(callback => callback(graphObject, this.config));
165
+ }
166
+
167
+ /**
168
+ * Sets the new color scheme and notifies all registered listeners about the color scheme change.
169
+ * @param {GraphConfig.ColorScheme} colorScheme - The new color scheme to use for nodes.
170
+ */
171
+ setColorScheme(colorScheme) {
172
+ if (!colorScheme) {
173
+ console.error('Color scheme must be provided', colorScheme);
174
+ }
175
+
176
+ this.config.colorScheme = colorScheme;
177
+ this.eventListeners[GraphStore.EventTypes.COLOR_SCHEME].forEach(callback => callback(colorScheme, this.config));
178
+ }
179
+
180
+ getEdgesOfObject(graphObject) {
181
+ if (!graphObject || !graphObject instanceof GraphObject) {
182
+ return [];
183
+ }
184
+
185
+ if (graphObject instanceof Node) {
186
+ return this.getEdgesOfNode(graphObject);
187
+ }
188
+
189
+ return [];
190
+ }
191
+
192
+ getEdgesOfNode(node) {
193
+ if (!node || !node instanceof Node) {
194
+ return [];
195
+ }
196
+
197
+ return this.getEdges().filter(edge => edge.source === node || edge.target === node);
198
+ }
199
+
200
+ getNodeById(id) {
201
+ return this.getNodes().find(node => node.id === id);
202
+ }
203
+
204
+ getNeighborsOfObject(graphObject) {
205
+ if (!graphObject || !graphObject instanceof GraphObject) {
206
+ return [];
207
+ }
208
+
209
+ if (graphObject instanceof Node) {
210
+ return this.getNeighborsOfNode(graphObject);
211
+ }
212
+
213
+ if (graphObject instanceof Edge) {
214
+ return [graphObject.source, graphObject.target];
215
+ }
216
+ }
217
+
218
+ getNeighborsOfNode(node) {
219
+ if (!node || !node instanceof Node) {
220
+ return [];
221
+ }
222
+
223
+ const edges = this.getEdgesOfNode(node);
224
+ return edges.map(edge => edge.source === node ? edge.target : edge.source);
225
+ }
226
+
227
+ edgeIsConnectedToNode(edge, node) {
228
+ if (!node || !node instanceof Node) {
229
+ return false;
230
+ }
231
+
232
+ return edge.source === node || edge.target === node
233
+ }
234
+
235
+ nodeIsNeighborTo(node, potentialNeighbor) {
236
+ return this.getNeighborsOfNode(node).includes(potentialNeighbor);
237
+ }
238
+
239
+ edgeIsConnectedToFocusedNode(edge) {
240
+ return this.edgeIsConnectedToNode(edge, this.config.focusedGraphObject);
241
+ }
242
+
243
+ edgeIsConnectedToSelectedNode(edge) {
244
+ return this.edgeIsConnectedToNode(edge, this.config.selectedGraphObject);
245
+ }
246
+
247
+ nodeIsNeighborToFocusedNode(node) {
248
+ return this.nodeIsNeighborTo(node, this.config.focusedGraphObject);
249
+ }
250
+
251
+ nodeIsNeighborToSelectedNode(node) {
252
+ return this.nodeIsNeighborTo(node, this.config.selectedGraphObject);
253
+ }
254
+
255
+ /**
256
+ * Gets the color for a node based on its neighborhood.
257
+ * @param {GraphObject} node - The node to get the color for.
258
+ * @returns {string} The color for the node based on its neighborhood.
259
+ */
260
+ getColorForNodeByNeighborhood(node) {
261
+ if (!node || typeof node.neighborhood !== 'number') {
262
+ console.error('Node must have a neighborhood', node);
263
+ }
264
+
265
+ let index = this.reservedColorsByNeighborhood.indexOf(node.neighborhood);
266
+ if (index === -1) {
267
+ index = this.reservedColorsByNeighborhood.push(node.neighborhood) - 1;
268
+ }
269
+
270
+ if (index > this.config.colorPalette.length - 1) {
271
+ console.error('Ran out of colors for neighborhood');
272
+ return this.config.colorPalette[0];
273
+ }
274
+
275
+ return this.config.colorPalette[index];
276
+ }
277
+
278
+ /**
279
+ * Gets the color for a node based on its label.
280
+ * @param {GraphObject} node - The node to get the color for.
281
+ * @returns {string} The color for the node based on its label.
282
+ */
283
+ getColorForNodeByLabel(node) {
284
+ if (!node || !node.label) {
285
+ console.error('Node must have a label', node);
286
+ }
287
+
288
+ switch (this.viewMode) {
289
+ case GraphStore.ViewModes.SCHEMA:
290
+ const schemaColor = this.config.schemaNodeColors[node.label];
291
+ if (schemaColor) {
292
+ return schemaColor;
293
+ }
294
+ break;
295
+ case GraphStore.ViewModes.DEFAULT:
296
+ const nodeColor = this.config.nodeColors[node.label];
297
+ if (nodeColor) {
298
+ return nodeColor;
299
+ }
300
+ break;
301
+ }
302
+
303
+ return 'rgb(100, 100, 100)';
304
+ }
305
+
306
+ /**
307
+ * Gets the color for a node based on the specified color scheme.
308
+ * @param {GraphObject} node - The node to get the color for.
309
+ * @param {GraphConfig.ColorScheme} colorScheme - The color scheme to use.
310
+ * @returns {string} The color for the node.
311
+ * @throws {Error} If an invalid color scheme is provided.
312
+ */
313
+ getColorForNode(node) {
314
+ switch (this.config.colorScheme) {
315
+ case GraphConfig.ColorScheme.NEIGHBORHOOD:
316
+ return this.getColorForNodeByNeighborhood(node);
317
+ case GraphConfig.ColorScheme.LABEL:
318
+ return this.getColorForNodeByLabel(node);
319
+ default:
320
+ throw Error('Invalid color scheme', colorScheme);
321
+ }
322
+ }
323
+
324
+ /**
325
+ * @returns {Array<Node>|*[]}
326
+ */
327
+ getNodes() {
328
+ switch (this.viewMode) {
329
+ case GraphStore.ViewModes.DEFAULT:
330
+ return this.config.nodes;
331
+ case GraphStore.ViewModes.SCHEMA:
332
+ return this.config.schemaNodes;
333
+ default:
334
+ return [];
335
+ }
336
+ }
337
+
338
+ /**
339
+ * @returns {Array<Edge>|*[]}
340
+ */
341
+ getEdges() {
342
+ switch (this.viewMode) {
343
+ case GraphStore.ViewModes.DEFAULT:
344
+ return this.config.edges;
345
+ case GraphStore.ViewModes.SCHEMA:
346
+ return this.config.schemaEdges;
347
+ default:
348
+ return [];
349
+ }
350
+ }
351
+
352
+ getEdgeDesign(edge) {
353
+ const hasSelectedObject = this.config.selectedGraphObject
354
+ const edgeIsSelected = this.config.selectedGraphObject && edge === this.config.selectedGraphObject;
355
+ if (hasSelectedObject && edgeIsSelected) {
356
+ return this.config.edgeDesign.selected;
357
+ }
358
+
359
+ if (hasSelectedObject) {
360
+ if (this.edgeIsConnectedToSelectedNode(edge)) {
361
+ return this.config.edgeDesign.focused;
362
+ } else {
363
+ return this.config.edgeDesign.default;
364
+ }
365
+ }
366
+
367
+ const edgeIsFocused = this.config.focusedGraphObject && edge === this.config.focusedGraphObject;
368
+ if (!hasSelectedObject && edgeIsFocused) {
369
+ return this.config.edgeDesign.focused;
370
+ }
371
+
372
+ const isNeighbor = this.edgeIsConnectedToFocusedNode(edge) ||
373
+ this.edgeIsConnectedToSelectedNode(edge);
374
+ if (isNeighbor) {
375
+ return this.config.edgeDesign.focused;
376
+ }
377
+
378
+ return this.config.edgeDesign.default;
379
+ }
380
+ }
381
+
382
+ window[namespace].GraphStore = GraphStore;