├── .github └── workflows │ ├── build-package.yml │ └── publish.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE.md ├── README.md ├── README_DEV.md ├── environment.build.yml ├── environment.dev.yml ├── examples ├── basic_example.ipynb ├── configurations_example.ipynb ├── feature_example.ipynb ├── grouping.ipynb └── selection_example.ipynb ├── images ├── example.png └── features │ ├── grouping_feature.png │ ├── heat_feature.png │ ├── map_feature.png │ └── size_feature.png ├── pyproject.toml └── src └── yfiles_jupyter_graphs_for_neo4j ├── Yfiles_Neo4j_Graphs.py └── __init__.py /.github/workflows/build-package.yml: -------------------------------------------------------------------------------- 1 | name: Build package 2 | 3 | on: [workflow_dispatch] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - name: Set up Python 3.10 14 | uses: actions/setup-python@v3 15 | with: 16 | python-version: "3.10" 17 | - name: Install dependencies 18 | run: | 19 | python -m pip install --upgrade pip 20 | pip install build 21 | - name: Build package 22 | run: | 23 | python -m build 24 | - name: Upload artifact 25 | uses: actions/upload-artifact@v4 26 | with: 27 | path: dist/ 28 | overwrite: true 29 | 30 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish to PyPi 2 | 3 | on: [workflow_dispatch] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - name: Set up Python 3.10 14 | uses: actions/setup-python@v3 15 | with: 16 | python-version: "3.10" 17 | - name: Install dependencies 18 | run: | 19 | python -m pip install --upgrade pip 20 | pip install build 21 | - name: Build package 22 | run: | 23 | python -m build 24 | - name: Upload artifact 25 | uses: actions/upload-artifact@v4 26 | with: 27 | path: dist/ 28 | overwrite: true 29 | publish: 30 | runs-on: ubuntu-latest 31 | needs: build 32 | environment: 33 | name: pypi 34 | url: https://pypi.org/p/yfiles-jupyter-graphs-for-neo4j/ 35 | permissions: 36 | id-token: write # IMPORTANT: this permission is mandatory for trusted publishing 37 | steps: 38 | - uses: actions/checkout@v3 39 | - name: Download artifact 40 | uses: actions/download-artifact@v4 41 | with: 42 | path: dist/ 43 | - name: Display structure of downloaded files 44 | run: ls -R dist/ 45 | - name: Publish package distributions to PyPI 46 | uses: pypa/gh-action-pypi-publish@release/v1 47 | with: 48 | packages-dir: dist/artifact 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | .ipynb_checkpoints 4 | .idea 5 | /src/yfiles_jupyter_graphs_for_neo4j.egg-info/ 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies within all project spaces, and it also applies when 49 | an individual is representing the project or its community in public spaces. 50 | Examples of representing a project or community include using an official 51 | project e-mail address, posting via an official social media account, or acting 52 | as an appointed representative at an online or offline event. Representation of 53 | a project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [contact@yworks.com](mailto:contact@yworks.com). All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 yWorks GmbH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yFiles Jupyter Graphs for Neo4j 2 | ![A screenshot showing the yFiles graph widget for neo4j in a jupyter lab notebook](https://raw.githubusercontent.com/yWorks/yfiles-jupyter-graphs-for-neo4j/main/images/example.png) 3 | 4 | [![PyPI version](https://badge.fury.io/py/yfiles-jupyter-graphs-for-neo4j.svg)](https://badge.fury.io/py/yfiles-jupyter-graphs-for-neo4j) 5 | 6 | Easily visualize a [Neo4j](https://neo4j.com/) Cypher query as a graph in a Jupyter Notebook. 7 | 8 | This packages provides an easy-to-use interface to 9 | the [yFiles Graphs for Jupyter](https://github.com/yWorks/yfiles-jupyter-graphs) widget to directly visualize Cypher 10 | queries. 11 | 12 | ## Installation 13 | Just install it from the [Python Package Index](https://pypi.org/project/yfiles-jupyter-graphs-for-neo4j/) 14 | ```bash 15 | pip install yfiles_jupyter_graphs_for_neo4j 16 | ``` 17 | or see [README_DEV.md](https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/blob/main/README_DEV.md) to build it yourself. 18 | 19 | ## Usage 20 | 21 | ```python 22 | from yfiles_jupyter_graphs_for_neo4j import Neo4jGraphWidget 23 | from neo4j import GraphDatabase 24 | 25 | NEO4J_URI = "neo4j+ssc://demo.neo4jlabs.com" 26 | NEO4J_USERNAME = "movies" 27 | NEO4J_PASSWORD = "movies" 28 | driver = GraphDatabase.driver(uri = NEO4J_URI, auth = (NEO4J_USERNAME, NEO4J_PASSWORD), database = 'movies') 29 | 30 | g = Neo4jGraphWidget(driver) 31 | 32 | g.show_cypher("MATCH (s)-[r]->(t) RETURN s,r,t LIMIT 20") 33 | ``` 34 | 35 | See 36 | the [basic example notebook](https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/blob/main/examples/basic_example.ipynb) 37 | for a running example. 38 | 39 | ## Supported Environments 40 | 41 | The widget uses yFiles Graphs for Jupyter at its core, and therefore runs in any environment that is supported by it, 42 | see [supported environments](https://github.com/yWorks/yfiles-jupyter-graphs/tree/main?tab=readme-ov-file#supported-environments). 43 | 44 | ## Documentation 45 | 46 | The main class `Neo4jGraphWidget` provides the following API: 47 | 48 | ### Constructor 49 | 50 | - `Neo4jGraphWidget`: Creates a new class instance with the following arguments 51 | 52 | | Argument | Description | Default | 53 | |--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------| 54 | | `driver` | The neo4j `driver` that is used to execute Cypher queries. | `None` | 55 | | `widget_layout` | Can be used to specify general widget appearance through css attributes. See ipywidget's [`layout`](https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Layout.html#the-layout-attribute) for more information. | `None` | 56 | | `overview_enabled` | Enable graph overview component. Default behaviour depends on cell width. | `None` | 57 | | `context_start_with` | Start with a specific side-panel opened in the interactive widget. Starts with closed side-panel by default. | `None` | 58 | | `layout` | Can be used to specify a general default node and edge layout. Available algorithms are: "circular", "hierarchic", "organic", "interactive_organic", "orthogonal", "radial", "tree", "map", "orthogonal_edge_router", "organic_edge_router" | `organic` | 59 | 60 | ### Methods 61 | 62 | - `show_cypher(cypher: str, layout: Optional[str] = None, **kwargs: Dict[str, Any]) -> None` 63 | - `cypher (str)`: The [Cypher query](https://neo4j.com/docs/cypher-manual/current/introduction/) that should be 64 | visualized. 65 | - `layout (Optional[str])`: The graph layout that is used. This overwrites the general layout in this specific graph instance. The following arguments are supported: 66 | - `hierarchic` 67 | - `organic` 68 | - `interactive_organic` 69 | - `circular` 70 | - `circular_straight_line` 71 | - `orthogonal` 72 | - `tree` 73 | - `radial` 74 | - `map` 75 | - `orthogonal_edge_router` 76 | - `organic_edge_router` 77 | - `**kwargs (Dict[str, Any])`: Additional parameters that should be passed to the Cypher query (e.g., see 78 | the [selection example](https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/blob/main/examples/selection_example.ipynb)). 79 | 80 | The default behavior is to only show the nodes and relationships returned by the Cypher query. 81 | This can be changed to autocomplete relationships like in neo4j browser: 82 | - `set_autocomplete_relationships(autocomplete_relationships: Union[bool, str, list[str]]) -> None`: Sets whether to autocomplete relationships in the graph or not. 83 | 84 | The Cypher queries are executed by the provided Neo4j driver. If you have not specified a driver when instantiating the 85 | class, you can set 86 | a driver afterward: 87 | 88 | - `set_driver(driver)`: Sets the Neo4j driver that is used to resolve the Cypher queries. 89 | - `get_driver()`: Returns the current Neo4j driver. 90 | 91 | The graph visualization can be adjusted by adding configurations to each node label or edge type with the following 92 | functions: 93 | 94 | - `add_node_configuration(label: Union[str, list[str]], **kwargs: Dict[str, Any]) -> None` 95 | - `label (Union[str, list[str]])`: The node label(s) for which this configuration should be used. Supports `*` to address all labels. 96 | - `**kwargs (Dict[str, Any])`: Visualization configuration for the given node label. The following arguments are supported: 97 | - `text`: The text that displayed at the node. By default, the node's label is used. 98 | - `color`: A convenience color binding for the node (see also `styles` argument). 99 | - `size`: The size of the node. 100 | - `styles`: A dictionary that may contain the following attributes `color`, `shape` (one of 'ellipse', ' 101 | hexagon', 'hexagon2', 'octagon', 'pill', 'rectangle', 'round-rectangle' or 'triangle'), `image`. 102 | - `property`: Allows to specify additional properties on the node, which may be bound by other bindings. 103 | - `type`: Defines a specific "type" for the node as described 104 | in [yFiles Graphs for Jupyter](https://yworks.github.io/yfiles-jupyter-graphs/02_graph_widget/#def-default_node_type_mappingindex-node) 105 | which affects the automatic positioning of nodes (same "type"s are preferred to be placed next to each other). 106 | - `parent_configuration`: Configure grouping for this node label. See [grouping.ipynb](https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/blob/main/examples/grouping.ipynb) 107 | for examples. 108 | 109 | - `add_relationship_configuration(type: Union[str, list[str]], **kwargs: Dict[str, Any]) -> None` 110 | - `type (Union[str, list[str]])`: The relationship type for which this configuration should be used. Supports `*` to address all types. 111 | - `**kwargs`: Visualization configuration for the given relationship type. The following arguments are supported: 112 | - `text`: The text that displayed at the relationship. By default, the relationship's type is used. 113 | - `color`: The relationship's color. 114 | - `thickness_factor`: The relationship's stroke thickness factor. By default, `1`. 115 | - `styles`: The style of the edge. 116 | - `property`: Allows to specify additional properties on the relationship, which may be bound by other bindings. 117 | 118 | - `add_parent_relationship_configuration(type: Union[str, list[str]], reverse: Optional[bool] = False) -> None` 119 | - `type`: The relationship type that should be visualized as node grouping hierarchy instead of the actual relationship. 120 | - `reverse`: By default the target node is considered as parent. This can be reverted with this argument. 121 | 122 | To remove a configuration use the following functions: 123 | 124 | - `del_node_configuration(label: Union[str, list[str]]) -> None`: Deletes configuration for the given node label(s). Supports `*` to address all types. 125 | - `del_relationship_configurations(type: Union[str, list[str]]) -> None`: Deletes configuration for the given relationship type(s). Supports `*` to address all labels. 126 | - `del_parent_relationship_configuration(type: Union[str, list[str]]) -> None`: Deletes configuration for the given parent relationship type(s). 127 | 128 | You can select nodes and relationships to retrieve their ids. For example, you can use these ids in new Cypher queries 129 | by providing them as parameter to `show_cypher` as shown in 130 | the [selection example](https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/blob/main/examples/selection_example.ipynb). 131 | 132 | - `get_selected_node_ids(widget: Optional[Type["Neo4jGraphWidget"]] = None) -> List[str]`: Returns an Array of node ids 133 | - `widget`: The widget that is used to select nodes from. If `None` is specified, the most recently shown widget is 134 | used. 135 | 136 | - `get_selected_relationship_ids(widget: Optional[Type["Neo4jGraphWidget"]] = None) -> List[str]`: Returns an Array of relationship ids 137 | - `widget`: The widget that is used to select edges from. If `None` is specified, the most recently shown widget is 138 | used. 139 | 140 | ## How configuration bindings are resolved 141 | 142 | The configuration bindings (see `add_node_configuration` or `add_relationship_configuration`) are resolved as follows: 143 | 144 | If the configuration binding is a string, the package first tries to resolve it against the item's properties 145 | and uses the property value if available. If there is no property with the given key, the string value itself is used as 146 | a constant binding. 147 | 148 | In case you want to create a constant string value as binding, which also happens to be a property key, use a binding 149 | function with a constant string as return value instead. 150 | 151 | If the configuration binding is a function, the return value of the function is used as value for the respective 152 | configuration. 153 | 154 | ## yFiles Graphs for Jupyter 155 | 156 | The graph visualization is provided by [yFiles Graphs for Jupyter](https://github.com/yWorks/yfiles-jupyter-graphs), a 157 | versatile graph visualization widget for Jupyter Notebooks. 158 | 159 | It can import and visualize graphs from various popular Python packages 160 | (e.g. [NetworkX](https://github.com/yWorks/yfiles-jupyter-graphs/blob/main/examples/13_networkx_import.ipynb), 161 | [PyGraphviz](https://github.com/yWorks/yfiles-jupyter-graphs/blob/main/examples/15_graphviz_import.ipynb), 162 | [igraph](https://github.com/yWorks/yfiles-jupyter-graphs/blob/main/examples/17_igraph_import.ipynb)) or just structured 163 | [node and edge lists](https://github.com/yWorks/yfiles-jupyter-graphs/blob/main/examples/01_introduction.ipynb). 164 | 165 | And provides a rich set of visualization options to bring your data to life (see 166 | the [example notebooks](https://github.com/yWorks/yfiles-jupyter-graphs/blob/main/examples/00_toc.ipynb)). 167 | 168 | ### Feature Highlights 169 | 170 | 171 | 172 | 174 | 176 | 177 | 178 | 180 | 182 | 183 |
Heatmap visualization 173 | Heatmap visualization
Open In Colab
Geospatial data visualization 175 | Geospatial data visualization
Open In Colab
Data-driven item visualization 179 | Data-driven item visualization
Open In Colab
node nesting 181 | Group items
Open In Colab
184 | 185 | For a detailed feature guide, check out the main widget [example notebooks](https://colab.research.google.com/github/yWorks/yfiles-jupyter-graphs/blob/main/examples/00_toc.ipynb) 186 | 187 | ## Code of Conduct 188 | 189 | This project and everyone participating in it is governed by 190 | the [Code of Conduct](https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/blob/main/CODE_OF_CONDUCT.md). 191 | By participating, you are expected to uphold this code. 192 | Please report unacceptable behavior to [contact@yworks.com](mailto:contact@yworks.com). 193 | 194 | ## Feedback 195 | 196 | This widget is by no means perfect. 197 | If you find something is not working as expected 198 | we are glad to receive an issue report from you. 199 | Please make sure 200 | to [search for existing issues](https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/search?q=is%3Aissue) first 201 | and check if the issue is not an unsupported feature or known issue. 202 | If you did not find anything related, report a new issue with necessary information. 203 | Please also provide a clear and descriptive title and stick to the issue templates. 204 | See [issues](https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/issues). 205 | 206 | ## Dependencies 207 | 208 | * [yFiles Graphs for Jupyter](https://github.com/yWorks/yfiles-jupyter-graphs) 209 | 210 | ## License 211 | See [LICENSE](https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/blob/main/LICENSE.md) file. -------------------------------------------------------------------------------- /README_DEV.md: -------------------------------------------------------------------------------- 1 | # How to build this project 2 | 3 | Open a terminal in the yfiles-jupyter-graphs-for-neo4j directory and execute the following command: 4 | 5 | ```bash 6 | python -m build 7 | ``` 8 | 9 | This creates two files, 10 | - yfiles_jupyter_graphs_for_neo4j-1.0.0b0.tar.gz and 11 | - yfiles_jupyter_graphs_for_neo4j-1.0.0b0-py3-none-any.whl 12 | 13 | To use the build package install either one of them: 14 | 15 | ```bash 16 | pip install dist/yfiles_jupyter_graphs_for_neo4j-1.0.0b0.whl 17 | ``` 18 | 19 | Now you're ready to use this in jupyter lab or jupyter notebook. -------------------------------------------------------------------------------- /environment.build.yml: -------------------------------------------------------------------------------- 1 | name: yfiles_jupyter_graphs_for_neo4j_build 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - python 6 | - build 7 | -------------------------------------------------------------------------------- /environment.dev.yml: -------------------------------------------------------------------------------- 1 | name: yfiles_jupyter_graphs_for_neo4j_dev 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - python 6 | - jupyterlab 7 | - build 8 | -------------------------------------------------------------------------------- /examples/basic_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "58495ba6-70f8-4a34-b849-70f378cf7a58", 6 | "metadata": {}, 7 | "source": [ 8 | "# Basic Usage \"Open" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "879409d1-37c2-4ab2-80ae-deb4d7dc8412", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "%pip install yfiles_jupyter_graphs_for_neo4j --quiet\n", 19 | "%pip install neo4j --quiet\n", 20 | "from yfiles_jupyter_graphs_for_neo4j import Neo4jGraphWidget\n", 21 | "from neo4j import GraphDatabase" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "id": "b8a1fc4a-e8ef-4346-abcd-9fb99aa62429", 27 | "metadata": {}, 28 | "source": [ 29 | "You can also open this notebook in Google Colab when Google Colab's custom widget manager is enabled:" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": null, 35 | "id": "08c37cdc-b2f4-498f-8e24-d87cc9547048", 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "try:\n", 40 | " import google.colab\n", 41 | " from google.colab import output\n", 42 | " output.enable_custom_widget_manager()\n", 43 | "except:\n", 44 | " pass" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "id": "15fdc273-8bf8-4746-82c1-4fea2fc422d5", 50 | "metadata": {}, 51 | "source": [ 52 | "## Use the Neo4j driver" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "id": "53b5f2b5-0279-40d9-9434-c888f4e85924", 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "NEO4J_URI = \"neo4j+ssc://demo.neo4jlabs.com\" \n", 63 | "NEO4J_USERNAME = \"movies\"\n", 64 | "NEO4J_PASSWORD = \"movies\"\n", 65 | "driver = GraphDatabase.driver(uri = NEO4J_URI, auth = (NEO4J_USERNAME, NEO4J_PASSWORD), database = 'movies')\n", 66 | "\n", 67 | "g = Neo4jGraphWidget(driver)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "id": "8f350852-71ce-49e7-828b-a4285c221d29", 73 | "metadata": {}, 74 | "source": [ 75 | "## Query the database with Cypher" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": null, 81 | "id": "e7bc9c8a-d32d-4af7-935f-08154753210e", 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "g.show_cypher(\"MATCH (s)-[r]->(t) RETURN s,r,t LIMIT 10\")" 86 | ] 87 | } 88 | ], 89 | "metadata": { 90 | "kernelspec": { 91 | "display_name": "Python 3 (ipykernel)", 92 | "language": "python", 93 | "name": "python3" 94 | }, 95 | "language_info": { 96 | "codemirror_mode": { 97 | "name": "ipython", 98 | "version": 3 99 | }, 100 | "file_extension": ".py", 101 | "mimetype": "text/x-python", 102 | "name": "python", 103 | "nbconvert_exporter": "python", 104 | "pygments_lexer": "ipython3", 105 | "version": "3.9.19" 106 | } 107 | }, 108 | "nbformat": 4, 109 | "nbformat_minor": 5 110 | } 111 | -------------------------------------------------------------------------------- /examples/configurations_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "5dbe0b6a-35ce-49d1-acbf-d0590d1619c2", 6 | "metadata": {}, 7 | "source": [ 8 | "# Custom Data Configurations \"Open" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "8891bd52-e89c-46ba-a236-7a8ffee9b3da", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "%pip install yfiles_jupyter_graphs_for_neo4j --quiet\n", 19 | "%pip install neo4j --quiet\n", 20 | "from yfiles_jupyter_graphs_for_neo4j import Neo4jGraphWidget\n", 21 | "from neo4j import GraphDatabase\n", 22 | "from datetime import datetime" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "id": "ebbc75dd-35db-4aff-bde2-2be4a9b11309", 28 | "metadata": {}, 29 | "source": [ 30 | "You can also open this notebook in Google Colab when Google Colab's custom widget manager is enabled:" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "id": "db54c371-ccb6-4f5c-9d96-917692af08bb", 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "try:\n", 41 | " import google.colab\n", 42 | " from google.colab import output\n", 43 | " output.enable_custom_widget_manager()\n", 44 | "except:\n", 45 | " pass" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "id": "e85cde2a-5dba-4c06-9c9e-af199246dd53", 51 | "metadata": {}, 52 | "source": [ 53 | "## Use the Neo4j driver" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": null, 59 | "id": "0a50afba-06d6-47a4-9e38-106aa2823a83", 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "NEO4J_URI = \"neo4j+ssc://demo.neo4jlabs.com\" \n", 64 | "NEO4J_USERNAME = \"movies\"\n", 65 | "NEO4J_PASSWORD = \"movies\"\n", 66 | "driver = GraphDatabase.driver(uri = NEO4J_URI, auth = (NEO4J_USERNAME, NEO4J_PASSWORD), database = 'movies')\n", 67 | "\n", 68 | "g = Neo4jGraphWidget(driver)" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "id": "1ac1f749-f180-4870-955b-ea397879e6ce", 74 | "metadata": {}, 75 | "source": [ 76 | "## Configure data mappings\n", 77 | "\n", 78 | "Configurable values for the node visualization: `text`, `color`, `size`, `styles`, `property`, `coordinate`, `heat` and `type`.\n", 79 | "\n", 80 | "Configurable values for the relationship visualization: `text`, `color`, `thickness_factor`, `styles`, `heat` and `property`.\n", 81 | "\n", 82 | "When adding a configuration, you always need to specify the type of node or edge you want to adjust. (Here 'Person' or 'DIRECTED'),\n", 83 | "additionally you can define the new values for the above mentioned properties. The values may either be:\n", 84 | "- A lambda the resolves the node or relationship to a specific value.\n", 85 | "- A constant value which is directly used.\n", 86 | "- A property-key that points to the value that should be used for the configuration.\n", 87 | "\n", 88 | "For nodes, there is an additional `parent_configuration` that defines parent nodes for the node label. This configuration may either be:\n", 89 | "- A constant string value that is used as text for the created group node.\n", 90 | "- A property-key pointing to a string value that is used as text for the created group node.\n", 91 | "- A dict that with a 'text' property as label and additional styling properties (similar to the above mentioned visualization properties)." 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "id": "af00a09e-9842-4dcd-b296-fe0f01ba09e4", 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [ 101 | "g.add_node_configuration('Person', text='name', size=(100,100), styles=lambda node : {'shape': 'rectangle'}, parent_configuration= {'text': 'people', 'color': '#cca9ff'})\n", 102 | "g.add_node_configuration('Movie', text= lambda node : {\n", 103 | " 'text': 'Title:\\n' + node['properties']['title'], \n", 104 | " 'backgroundColor': 'rgba(0,0,0,0.7)', \n", 105 | " 'fontSize': 20, \n", 106 | " 'color': '#FFFFFF', \n", 107 | " 'position': 'north', \n", 108 | " 'fontWeight': 'lighter',\n", 109 | " 'maximumWidth': 130, \n", 110 | " 'wrapping': 'word', \n", 111 | " 'textAlignment': 'center'\n", 112 | " }, parent_configuration='movies') \n", 113 | "g.add_relationship_configuration('DIRECTED', color=\"blue\", styles={'dashStyle': 'dot'})\n", 114 | "g.add_relationship_configuration('PRODUCED', text = lambda edge: {'text': 'produced', 'fontWeight': 'bolder', 'fontSize': 16}, color='#AC94F4')\n", 115 | "g.add_relationship_configuration('ACTED_IN', thickness_factor=2, color='#AC94F4') " 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "id": "7b88d8d4-dbb8-4d87-b9bf-ee6316d96dd5", 121 | "metadata": {}, 122 | "source": [ 123 | "## Query the database with Cypher" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": null, 129 | "id": "514823d3-b3a4-4d5e-a48f-97058110ea4e", 130 | "metadata": {}, 131 | "outputs": [], 132 | "source": [ 133 | "g.show_cypher(\"MATCH (s)-[r]->(t) RETURN s,r,t LIMIT 20\")" 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "id": "a5d61081-2075-4d85-91a9-0ec49d720918", 139 | "metadata": {}, 140 | "source": [ 141 | "### Visualize \"ACTED_IN\" as nested hierarchy\n", 142 | "\n", 143 | "Relationship types may be replaced by a nesting hierarchy. This restructures the graph by removing these relationships and instead representing them as nested parent-child structure. The relationship structure may als be reversed with the `reverse` keyword argument to the `add_parent_relationship_configuration` method." 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": null, 149 | "id": "69211d43-39c5-4fb3-8fcb-5b6f1d4c0652", 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "g.add_parent_relationship_configuration('ACTED_IN')\n", 154 | "g.show_cypher(\"MATCH (s)-[r]->(t:Movie {title: 'The Matrix'}) RETURN s,r,t LIMIT 20\")" 155 | ] 156 | }, 157 | { 158 | "cell_type": "markdown", 159 | "id": "69570f85-9fb9-4cf3-b7bf-4125ff677a81", 160 | "metadata": {}, 161 | "source": [ 162 | "## Wildcard configurations\n", 163 | "\n", 164 | "Using `'*'` as the node or relationship type, all nodes or relationships are affected by the given configuration.\n", 165 | "\n", 166 | "Using an explicit type configuration overwrites the wildcard configuration." 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": null, 172 | "id": "158bf75e-3382-4748-a920-dc0f756b1bbe", 173 | "metadata": {}, 174 | "outputs": [], 175 | "source": [ 176 | "g2 = Neo4jGraphWidget(driver, layout='circular')\n", 177 | "g2.add_relationship_configuration('*', color='gray') # all relationship types gray\n", 178 | "g2.add_relationship_configuration('PRODUCED', color='red') # highlight the \"produced\" type\n", 179 | "g2.show_cypher(\"MATCH (s)-[r]->(t) RETURN s,r,t LIMIT 10\")" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": null, 185 | "id": "255cfdb6-7cd9-44b5-beee-834208bc0535", 186 | "metadata": {}, 187 | "outputs": [], 188 | "source": [] 189 | } 190 | ], 191 | "metadata": { 192 | "kernelspec": { 193 | "display_name": "Python 3 (ipykernel)", 194 | "language": "python", 195 | "name": "python3" 196 | }, 197 | "language_info": { 198 | "codemirror_mode": { 199 | "name": "ipython", 200 | "version": 3 201 | }, 202 | "file_extension": ".py", 203 | "mimetype": "text/x-python", 204 | "name": "python", 205 | "nbconvert_exporter": "python", 206 | "pygments_lexer": "ipython3", 207 | "version": "3.12.3" 208 | }, 209 | "widgets": { 210 | "application/vnd.jupyter.widget-state+json": { 211 | "state": { 212 | "02ec6d2ada004284ae819698a43f3a94": { 213 | "model_module": "yfiles-jupyter-graphs", 214 | "model_module_version": "^1.10.2", 215 | "model_name": "GraphModel", 216 | "state": { 217 | "_context_pane_mapping": [ 218 | { 219 | "id": "Neighborhood", 220 | "title": "Neighborhood" 221 | }, 222 | { 223 | "id": "Data", 224 | "title": "Data" 225 | }, 226 | { 227 | "id": "Search", 228 | "title": "Search" 229 | }, 230 | { 231 | "id": "About", 232 | "title": "About" 233 | } 234 | ], 235 | "_data_importer": "neo4j", 236 | "_directed": true, 237 | "_edges": [ 238 | { 239 | "color": "gray", 240 | "directed": true, 241 | "end": 0, 242 | "id": 0, 243 | "label": "ACTED_IN", 244 | "properties": { 245 | "label": "ACTED_IN", 246 | "roles": [ 247 | "Neo" 248 | ] 249 | }, 250 | "start": 1, 251 | "styles": {}, 252 | "thickness_factor": 1 253 | }, 254 | { 255 | "color": "gray", 256 | "directed": true, 257 | "end": 0, 258 | "id": 1, 259 | "label": "ACTED_IN", 260 | "properties": { 261 | "label": "ACTED_IN", 262 | "roles": [ 263 | "Trinity" 264 | ] 265 | }, 266 | "start": 2, 267 | "styles": {}, 268 | "thickness_factor": 1 269 | }, 270 | { 271 | "color": "gray", 272 | "directed": true, 273 | "end": 0, 274 | "id": 2, 275 | "label": "ACTED_IN", 276 | "properties": { 277 | "label": "ACTED_IN", 278 | "roles": [ 279 | "Morpheus" 280 | ] 281 | }, 282 | "start": 3, 283 | "styles": {}, 284 | "thickness_factor": 1 285 | }, 286 | { 287 | "color": "gray", 288 | "directed": true, 289 | "end": 0, 290 | "id": 3, 291 | "label": "ACTED_IN", 292 | "properties": { 293 | "label": "ACTED_IN", 294 | "roles": [ 295 | "Agent Smith" 296 | ] 297 | }, 298 | "start": 4, 299 | "styles": {}, 300 | "thickness_factor": 1 301 | }, 302 | { 303 | "color": "gray", 304 | "directed": true, 305 | "end": 0, 306 | "id": 4, 307 | "label": "DIRECTED", 308 | "properties": { 309 | "label": "DIRECTED" 310 | }, 311 | "start": 5, 312 | "styles": {}, 313 | "thickness_factor": 1 314 | }, 315 | { 316 | "color": "gray", 317 | "directed": true, 318 | "end": 0, 319 | "id": 5, 320 | "label": "DIRECTED", 321 | "properties": { 322 | "label": "DIRECTED" 323 | }, 324 | "start": 6, 325 | "styles": {}, 326 | "thickness_factor": 1 327 | }, 328 | { 329 | "color": "red", 330 | "directed": true, 331 | "end": 0, 332 | "id": 6, 333 | "label": "PRODUCED", 334 | "properties": { 335 | "label": "PRODUCED" 336 | }, 337 | "start": 7, 338 | "styles": {}, 339 | "thickness_factor": 1 340 | }, 341 | { 342 | "color": "gray", 343 | "directed": true, 344 | "end": 0, 345 | "id": 7, 346 | "label": "ACTED_IN", 347 | "properties": { 348 | "label": "ACTED_IN", 349 | "roles": [ 350 | "Emil" 351 | ] 352 | }, 353 | "start": 8, 354 | "styles": {}, 355 | "thickness_factor": 1 356 | }, 357 | { 358 | "color": "gray", 359 | "directed": true, 360 | "end": 9, 361 | "id": 8, 362 | "label": "ACTED_IN", 363 | "properties": { 364 | "label": "ACTED_IN", 365 | "roles": [ 366 | "Neo" 367 | ] 368 | }, 369 | "start": 1, 370 | "styles": {}, 371 | "thickness_factor": 1 372 | }, 373 | { 374 | "color": "gray", 375 | "directed": true, 376 | "end": 9, 377 | "id": 9, 378 | "label": "ACTED_IN", 379 | "properties": { 380 | "label": "ACTED_IN", 381 | "roles": [ 382 | "Trinity" 383 | ] 384 | }, 385 | "start": 2, 386 | "styles": {}, 387 | "thickness_factor": 1 388 | } 389 | ], 390 | "_graph_layout": { 391 | "algorithm": "circular", 392 | "options": {} 393 | }, 394 | "_model_module_version": "^1.10.2", 395 | "_nodes": [ 396 | { 397 | "color": "#2196F3", 398 | "id": 1, 399 | "label": "Keanu Reeves", 400 | "position": [ 401 | 0, 402 | 0 403 | ], 404 | "properties": { 405 | "born": 1964, 406 | "label": "Person", 407 | "name": "Keanu Reeves" 408 | }, 409 | "scale_factor": 1, 410 | "size": [ 411 | 55, 412 | 55 413 | ], 414 | "styles": {}, 415 | "type": "#2196F3" 416 | }, 417 | { 418 | "color": "#4CAF50", 419 | "id": 0, 420 | "label": "The Matrix", 421 | "position": [ 422 | 0, 423 | 0 424 | ], 425 | "properties": { 426 | "label": "Movie", 427 | "released": 1999, 428 | "tagline": "Welcome to the Real World", 429 | "title": "The Matrix", 430 | "votes": 6345 431 | }, 432 | "scale_factor": 1, 433 | "size": [ 434 | 55, 435 | 55 436 | ], 437 | "styles": {}, 438 | "type": "#4CAF50" 439 | }, 440 | { 441 | "color": "#2196F3", 442 | "id": 2, 443 | "label": "Carrie-Anne Moss", 444 | "position": [ 445 | 0, 446 | 0 447 | ], 448 | "properties": { 449 | "born": 1967, 450 | "label": "Person", 451 | "name": "Carrie-Anne Moss" 452 | }, 453 | "scale_factor": 1, 454 | "size": [ 455 | 55, 456 | 55 457 | ], 458 | "styles": {}, 459 | "type": "#2196F3" 460 | }, 461 | { 462 | "color": "#2196F3", 463 | "id": 3, 464 | "label": "Laurence Fishburne", 465 | "position": [ 466 | 0, 467 | 0 468 | ], 469 | "properties": { 470 | "born": 1961, 471 | "label": "Person", 472 | "name": "Laurence Fishburne" 473 | }, 474 | "scale_factor": 1, 475 | "size": [ 476 | 55, 477 | 55 478 | ], 479 | "styles": {}, 480 | "type": "#2196F3" 481 | }, 482 | { 483 | "color": "#2196F3", 484 | "id": 4, 485 | "label": "Hugo Weaving", 486 | "position": [ 487 | 0, 488 | 0 489 | ], 490 | "properties": { 491 | "born": 1960, 492 | "label": "Person", 493 | "name": "Hugo Weaving" 494 | }, 495 | "scale_factor": 1, 496 | "size": [ 497 | 55, 498 | 55 499 | ], 500 | "styles": {}, 501 | "type": "#2196F3" 502 | }, 503 | { 504 | "color": "#2196F3", 505 | "id": 5, 506 | "label": "Lilly Wachowski", 507 | "position": [ 508 | 0, 509 | 0 510 | ], 511 | "properties": { 512 | "born": 1967, 513 | "label": "Person", 514 | "name": "Lilly Wachowski" 515 | }, 516 | "scale_factor": 1, 517 | "size": [ 518 | 55, 519 | 55 520 | ], 521 | "styles": {}, 522 | "type": "#2196F3" 523 | }, 524 | { 525 | "color": "#2196F3", 526 | "id": 6, 527 | "label": "Lana Wachowski", 528 | "position": [ 529 | 0, 530 | 0 531 | ], 532 | "properties": { 533 | "born": 1965, 534 | "label": "Person", 535 | "name": "Lana Wachowski" 536 | }, 537 | "scale_factor": 1, 538 | "size": [ 539 | 55, 540 | 55 541 | ], 542 | "styles": {}, 543 | "type": "#2196F3" 544 | }, 545 | { 546 | "color": "#2196F3", 547 | "id": 7, 548 | "label": "Joel Silver", 549 | "position": [ 550 | 0, 551 | 0 552 | ], 553 | "properties": { 554 | "born": 1952, 555 | "label": "Person", 556 | "name": "Joel Silver" 557 | }, 558 | "scale_factor": 1, 559 | "size": [ 560 | 55, 561 | 55 562 | ], 563 | "styles": {}, 564 | "type": "#2196F3" 565 | }, 566 | { 567 | "color": "#2196F3", 568 | "id": 8, 569 | "label": "Emil Eifrem", 570 | "position": [ 571 | 0, 572 | 0 573 | ], 574 | "properties": { 575 | "born": 1978, 576 | "label": "Person", 577 | "name": "Emil Eifrem" 578 | }, 579 | "scale_factor": 1, 580 | "size": [ 581 | 55, 582 | 55 583 | ], 584 | "styles": {}, 585 | "type": "#2196F3" 586 | }, 587 | { 588 | "color": "#4CAF50", 589 | "id": 9, 590 | "label": "The Matrix Reloaded", 591 | "position": [ 592 | 0, 593 | 0 594 | ], 595 | "properties": { 596 | "label": "Movie", 597 | "released": 2003, 598 | "tagline": "Free your mind", 599 | "title": "The Matrix Reloaded", 600 | "votes": 1841 601 | }, 602 | "scale_factor": 1, 603 | "size": [ 604 | 55, 605 | 55 606 | ], 607 | "styles": {}, 608 | "type": "#4CAF50" 609 | } 610 | ], 611 | "_overview": { 612 | "enabled": null, 613 | "overview_set": false 614 | }, 615 | "_selected_graph": [ 616 | [], 617 | [] 618 | ], 619 | "_sidebar": { 620 | "enabled": false, 621 | "start_with": "About" 622 | }, 623 | "_view_module_version": "^1.10.2", 624 | "layout": "IPY_MODEL_0462e2af62b4401f92fb547db77996ee" 625 | } 626 | }, 627 | "0462e2af62b4401f92fb547db77996ee": { 628 | "model_module": "@jupyter-widgets/base", 629 | "model_module_version": "2.0.0", 630 | "model_name": "LayoutModel", 631 | "state": { 632 | "height": "500px", 633 | "width": "100%" 634 | } 635 | }, 636 | "21ebaf0ab0b841aca22867906841cceb": { 637 | "model_module": "yfiles-jupyter-graphs", 638 | "model_module_version": "^1.10.2", 639 | "model_name": "GraphModel", 640 | "state": { 641 | "_context_pane_mapping": [ 642 | { 643 | "id": "Neighborhood", 644 | "title": "Neighborhood" 645 | }, 646 | { 647 | "id": "Data", 648 | "title": "Data" 649 | }, 650 | { 651 | "id": "Search", 652 | "title": "Search" 653 | }, 654 | { 655 | "id": "About", 656 | "title": "About" 657 | } 658 | ], 659 | "_data_importer": "neo4j", 660 | "_directed": true, 661 | "_edges": [ 662 | { 663 | "color": "blue", 664 | "directed": true, 665 | "end": 0, 666 | "id": 4, 667 | "label": "DIRECTED", 668 | "properties": { 669 | "label": "DIRECTED" 670 | }, 671 | "start": 5, 672 | "styles": { 673 | "dashStyle": "dot" 674 | }, 675 | "thickness_factor": 1 676 | }, 677 | { 678 | "color": "blue", 679 | "directed": true, 680 | "end": 0, 681 | "id": 5, 682 | "label": "DIRECTED", 683 | "properties": { 684 | "label": "DIRECTED" 685 | }, 686 | "start": 6, 687 | "styles": { 688 | "dashStyle": "dot" 689 | }, 690 | "thickness_factor": 1 691 | }, 692 | { 693 | "color": "#AC94F4", 694 | "directed": true, 695 | "end": 0, 696 | "id": 6, 697 | "label": "produced", 698 | "properties": { 699 | "label": "PRODUCED" 700 | }, 701 | "start": 7, 702 | "styles": { 703 | "label_styles": {} 704 | }, 705 | "thickness_factor": 1 706 | }, 707 | { 708 | "color": "blue", 709 | "directed": true, 710 | "end": 9, 711 | "id": 12, 712 | "label": "DIRECTED", 713 | "properties": { 714 | "label": "DIRECTED" 715 | }, 716 | "start": 5, 717 | "styles": { 718 | "dashStyle": "dot" 719 | }, 720 | "thickness_factor": 1 721 | }, 722 | { 723 | "color": "blue", 724 | "directed": true, 725 | "end": 9, 726 | "id": 13, 727 | "label": "DIRECTED", 728 | "properties": { 729 | "label": "DIRECTED" 730 | }, 731 | "start": 6, 732 | "styles": { 733 | "dashStyle": "dot" 734 | }, 735 | "thickness_factor": 1 736 | }, 737 | { 738 | "color": "#AC94F4", 739 | "directed": true, 740 | "end": 9, 741 | "id": 14, 742 | "label": "produced", 743 | "properties": { 744 | "label": "PRODUCED" 745 | }, 746 | "start": 7, 747 | "styles": { 748 | "label_styles": {} 749 | }, 750 | "thickness_factor": 1 751 | }, 752 | { 753 | "color": "blue", 754 | "directed": true, 755 | "end": 10, 756 | "id": 19, 757 | "label": "DIRECTED", 758 | "properties": { 759 | "label": "DIRECTED" 760 | }, 761 | "start": 5, 762 | "styles": { 763 | "dashStyle": "dot" 764 | }, 765 | "thickness_factor": 1 766 | } 767 | ], 768 | "_graph_layout": { 769 | "algorithm": "organic", 770 | "options": {} 771 | }, 772 | "_model_module_version": "^1.10.2", 773 | "_nodes": [ 774 | { 775 | "color": "#2196F3", 776 | "id": 1, 777 | "label": "Keanu Reeves", 778 | "parentId": 10, 779 | "position": [ 780 | 0, 781 | 0 782 | ], 783 | "properties": { 784 | "born": 1964, 785 | "label": "Person", 786 | "name": "Keanu Reeves" 787 | }, 788 | "scale_factor": 1, 789 | "size": [ 790 | 100, 791 | 100 792 | ], 793 | "styles": { 794 | "shape": "rectangle" 795 | }, 796 | "type": "#2196F3" 797 | }, 798 | { 799 | "color": "#4CAF50", 800 | "id": 0, 801 | "label": "Title:\nThe Matrix", 802 | "parentId": "GroupNodemovies", 803 | "position": [ 804 | 0, 805 | 0 806 | ], 807 | "properties": { 808 | "label": "Movie", 809 | "released": 1999, 810 | "tagline": "Welcome to the Real World", 811 | "title": "The Matrix", 812 | "votes": 6345 813 | }, 814 | "scale_factor": 1, 815 | "size": [ 816 | 55, 817 | 55 818 | ], 819 | "styles": { 820 | "label_styles": { 821 | "backgroundColor": "rgba(0,0,0,0.7)", 822 | "color": "#FFFFFF", 823 | "fontSize": 20, 824 | "fontWeight": "lighter", 825 | "maximumWidth": 130, 826 | "position": "north", 827 | "textAlignment": "center", 828 | "wrapping": "word" 829 | } 830 | }, 831 | "type": "#4CAF50" 832 | }, 833 | { 834 | "color": "#2196F3", 835 | "id": 2, 836 | "label": "Carrie-Anne Moss", 837 | "parentId": 10, 838 | "position": [ 839 | 0, 840 | 0 841 | ], 842 | "properties": { 843 | "born": 1967, 844 | "label": "Person", 845 | "name": "Carrie-Anne Moss" 846 | }, 847 | "scale_factor": 1, 848 | "size": [ 849 | 100, 850 | 100 851 | ], 852 | "styles": { 853 | "shape": "rectangle" 854 | }, 855 | "type": "#2196F3" 856 | }, 857 | { 858 | "color": "#2196F3", 859 | "id": 3, 860 | "label": "Laurence Fishburne", 861 | "parentId": 10, 862 | "position": [ 863 | 0, 864 | 0 865 | ], 866 | "properties": { 867 | "born": 1961, 868 | "label": "Person", 869 | "name": "Laurence Fishburne" 870 | }, 871 | "scale_factor": 1, 872 | "size": [ 873 | 100, 874 | 100 875 | ], 876 | "styles": { 877 | "shape": "rectangle" 878 | }, 879 | "type": "#2196F3" 880 | }, 881 | { 882 | "color": "#2196F3", 883 | "id": 4, 884 | "label": "Hugo Weaving", 885 | "parentId": 10, 886 | "position": [ 887 | 0, 888 | 0 889 | ], 890 | "properties": { 891 | "born": 1960, 892 | "label": "Person", 893 | "name": "Hugo Weaving" 894 | }, 895 | "scale_factor": 1, 896 | "size": [ 897 | 100, 898 | 100 899 | ], 900 | "styles": { 901 | "shape": "rectangle" 902 | }, 903 | "type": "#2196F3" 904 | }, 905 | { 906 | "color": "#2196F3", 907 | "id": 5, 908 | "label": "Lilly Wachowski", 909 | "parentId": "GroupNodepeople", 910 | "position": [ 911 | 0, 912 | 0 913 | ], 914 | "properties": { 915 | "born": 1967, 916 | "label": "Person", 917 | "name": "Lilly Wachowski" 918 | }, 919 | "scale_factor": 1, 920 | "size": [ 921 | 100, 922 | 100 923 | ], 924 | "styles": { 925 | "shape": "rectangle" 926 | }, 927 | "type": "#2196F3" 928 | }, 929 | { 930 | "color": "#2196F3", 931 | "id": 6, 932 | "label": "Lana Wachowski", 933 | "parentId": "GroupNodepeople", 934 | "position": [ 935 | 0, 936 | 0 937 | ], 938 | "properties": { 939 | "born": 1965, 940 | "label": "Person", 941 | "name": "Lana Wachowski" 942 | }, 943 | "scale_factor": 1, 944 | "size": [ 945 | 100, 946 | 100 947 | ], 948 | "styles": { 949 | "shape": "rectangle" 950 | }, 951 | "type": "#2196F3" 952 | }, 953 | { 954 | "color": "#2196F3", 955 | "id": 7, 956 | "label": "Joel Silver", 957 | "parentId": "GroupNodepeople", 958 | "position": [ 959 | 0, 960 | 0 961 | ], 962 | "properties": { 963 | "born": 1952, 964 | "label": "Person", 965 | "name": "Joel Silver" 966 | }, 967 | "scale_factor": 1, 968 | "size": [ 969 | 100, 970 | 100 971 | ], 972 | "styles": { 973 | "shape": "rectangle" 974 | }, 975 | "type": "#2196F3" 976 | }, 977 | { 978 | "color": "#2196F3", 979 | "id": 8, 980 | "label": "Emil Eifrem", 981 | "parentId": 0, 982 | "position": [ 983 | 0, 984 | 0 985 | ], 986 | "properties": { 987 | "born": 1978, 988 | "label": "Person", 989 | "name": "Emil Eifrem" 990 | }, 991 | "scale_factor": 1, 992 | "size": [ 993 | 100, 994 | 100 995 | ], 996 | "styles": { 997 | "shape": "rectangle" 998 | }, 999 | "type": "#2196F3" 1000 | }, 1001 | { 1002 | "color": "#4CAF50", 1003 | "id": 9, 1004 | "label": "Title:\nThe Matrix Reloaded", 1005 | "parentId": "GroupNodemovies", 1006 | "position": [ 1007 | 0, 1008 | 0 1009 | ], 1010 | "properties": { 1011 | "label": "Movie", 1012 | "released": 2003, 1013 | "tagline": "Free your mind", 1014 | "title": "The Matrix Reloaded", 1015 | "votes": 1841 1016 | }, 1017 | "scale_factor": 1, 1018 | "size": [ 1019 | 55, 1020 | 55 1021 | ], 1022 | "styles": { 1023 | "label_styles": { 1024 | "backgroundColor": "rgba(0,0,0,0.7)", 1025 | "color": "#FFFFFF", 1026 | "fontSize": 20, 1027 | "fontWeight": "lighter", 1028 | "maximumWidth": 130, 1029 | "position": "north", 1030 | "textAlignment": "center", 1031 | "wrapping": "word" 1032 | } 1033 | }, 1034 | "type": "#4CAF50" 1035 | }, 1036 | { 1037 | "color": "#4CAF50", 1038 | "id": 10, 1039 | "label": "Title:\nThe Matrix Revolutions", 1040 | "parentId": "GroupNodemovies", 1041 | "position": [ 1042 | 0, 1043 | 0 1044 | ], 1045 | "properties": { 1046 | "label": "Movie", 1047 | "released": 2003, 1048 | "tagline": "Everything that has a beginning has an end", 1049 | "title": "The Matrix Revolutions", 1050 | "votes": 1534 1051 | }, 1052 | "scale_factor": 1, 1053 | "size": [ 1054 | 55, 1055 | 55 1056 | ], 1057 | "styles": { 1058 | "label_styles": { 1059 | "backgroundColor": "rgba(0,0,0,0.7)", 1060 | "color": "#FFFFFF", 1061 | "fontSize": 20, 1062 | "fontWeight": "lighter", 1063 | "maximumWidth": 130, 1064 | "position": "north", 1065 | "textAlignment": "center", 1066 | "wrapping": "word" 1067 | } 1068 | }, 1069 | "type": "#4CAF50" 1070 | }, 1071 | { 1072 | "color": "#cca9ff", 1073 | "id": "GroupNodepeople", 1074 | "label": "people", 1075 | "position": [ 1076 | 0, 1077 | 0 1078 | ], 1079 | "properties": { 1080 | "label": "people" 1081 | }, 1082 | "scale_factor": 1, 1083 | "size": [ 1084 | 55, 1085 | 55 1086 | ], 1087 | "styles": {}, 1088 | "type": "#cca9ff" 1089 | }, 1090 | { 1091 | "color": "#F44336", 1092 | "id": "GroupNodemovies", 1093 | "label": "movies", 1094 | "position": [ 1095 | 0, 1096 | 0 1097 | ], 1098 | "properties": { 1099 | "label": "movies" 1100 | }, 1101 | "scale_factor": 1, 1102 | "size": [ 1103 | 55, 1104 | 55 1105 | ], 1106 | "styles": {}, 1107 | "type": "#F44336" 1108 | } 1109 | ], 1110 | "_overview": { 1111 | "enabled": null, 1112 | "overview_set": false 1113 | }, 1114 | "_selected_graph": [ 1115 | [], 1116 | [] 1117 | ], 1118 | "_sidebar": { 1119 | "enabled": false, 1120 | "start_with": "About" 1121 | }, 1122 | "_view_module_version": "^1.10.2", 1123 | "layout": "IPY_MODEL_6bdf055e98594e2599fa5156c3f65956" 1124 | } 1125 | }, 1126 | "34bbd98495ca4f32aae4dbb34758f654": { 1127 | "model_module": "@jupyter-widgets/base", 1128 | "model_module_version": "2.0.0", 1129 | "model_name": "LayoutModel", 1130 | "state": { 1131 | "height": "500px", 1132 | "width": "100%" 1133 | } 1134 | }, 1135 | "577983e1cec84593b62c1b70fb1637ae": { 1136 | "model_module": "@jupyter-widgets/base", 1137 | "model_module_version": "2.0.0", 1138 | "model_name": "LayoutModel", 1139 | "state": { 1140 | "height": "500px", 1141 | "width": "100%" 1142 | } 1143 | }, 1144 | "5fd3993005a24254b3a3d6b0ee922944": { 1145 | "model_module": "@jupyter-widgets/base", 1146 | "model_module_version": "2.0.0", 1147 | "model_name": "LayoutModel", 1148 | "state": { 1149 | "height": "630px", 1150 | "width": "100%" 1151 | } 1152 | }, 1153 | "61b4005ae6884205994ae640442962eb": { 1154 | "model_module": "@jupyter-widgets/base", 1155 | "model_module_version": "2.0.0", 1156 | "model_name": "LayoutModel", 1157 | "state": { 1158 | "height": "500px", 1159 | "width": "100%" 1160 | } 1161 | }, 1162 | "63e098dd1ddd46d08940956fca858f87": { 1163 | "model_module": "yfiles-jupyter-graphs", 1164 | "model_module_version": "^1.10.2", 1165 | "model_name": "GraphModel", 1166 | "state": { 1167 | "_context_pane_mapping": [ 1168 | { 1169 | "id": "Neighborhood", 1170 | "title": "Neighborhood" 1171 | }, 1172 | { 1173 | "id": "Data", 1174 | "title": "Data" 1175 | }, 1176 | { 1177 | "id": "Search", 1178 | "title": "Search" 1179 | }, 1180 | { 1181 | "id": "About", 1182 | "title": "About" 1183 | } 1184 | ], 1185 | "_data_importer": "neo4j", 1186 | "_directed": true, 1187 | "_edges": [ 1188 | { 1189 | "color": "blue", 1190 | "directed": true, 1191 | "end": 0, 1192 | "id": 4, 1193 | "label": "DIRECTED", 1194 | "properties": { 1195 | "label": "DIRECTED" 1196 | }, 1197 | "start": 5, 1198 | "styles": { 1199 | "dashStyle": "dot" 1200 | }, 1201 | "thickness_factor": 1 1202 | }, 1203 | { 1204 | "color": "blue", 1205 | "directed": true, 1206 | "end": 0, 1207 | "id": 5, 1208 | "label": "DIRECTED", 1209 | "properties": { 1210 | "label": "DIRECTED" 1211 | }, 1212 | "start": 6, 1213 | "styles": { 1214 | "dashStyle": "dot" 1215 | }, 1216 | "thickness_factor": 1 1217 | }, 1218 | { 1219 | "color": "#AC94F4", 1220 | "directed": true, 1221 | "end": 0, 1222 | "id": 6, 1223 | "label": "produced", 1224 | "properties": { 1225 | "label": "PRODUCED" 1226 | }, 1227 | "start": 7, 1228 | "styles": { 1229 | "label_styles": { 1230 | "fontWeight": "bolder" 1231 | } 1232 | }, 1233 | "thickness_factor": 1 1234 | }, 1235 | { 1236 | "color": "blue", 1237 | "directed": true, 1238 | "end": 9, 1239 | "id": 12, 1240 | "label": "DIRECTED", 1241 | "properties": { 1242 | "label": "DIRECTED" 1243 | }, 1244 | "start": 5, 1245 | "styles": { 1246 | "dashStyle": "dot" 1247 | }, 1248 | "thickness_factor": 1 1249 | }, 1250 | { 1251 | "color": "blue", 1252 | "directed": true, 1253 | "end": 9, 1254 | "id": 13, 1255 | "label": "DIRECTED", 1256 | "properties": { 1257 | "label": "DIRECTED" 1258 | }, 1259 | "start": 6, 1260 | "styles": { 1261 | "dashStyle": "dot" 1262 | }, 1263 | "thickness_factor": 1 1264 | }, 1265 | { 1266 | "color": "#AC94F4", 1267 | "directed": true, 1268 | "end": 9, 1269 | "id": 14, 1270 | "label": "produced", 1271 | "properties": { 1272 | "label": "PRODUCED" 1273 | }, 1274 | "start": 7, 1275 | "styles": { 1276 | "label_styles": { 1277 | "fontWeight": "bolder" 1278 | } 1279 | }, 1280 | "thickness_factor": 1 1281 | }, 1282 | { 1283 | "color": "blue", 1284 | "directed": true, 1285 | "end": 10, 1286 | "id": 19, 1287 | "label": "DIRECTED", 1288 | "properties": { 1289 | "label": "DIRECTED" 1290 | }, 1291 | "start": 5, 1292 | "styles": { 1293 | "dashStyle": "dot" 1294 | }, 1295 | "thickness_factor": 1 1296 | } 1297 | ], 1298 | "_graph_layout": { 1299 | "algorithm": "organic", 1300 | "options": {} 1301 | }, 1302 | "_model_module_version": "^1.10.2", 1303 | "_nodes": [ 1304 | { 1305 | "color": "#2196F3", 1306 | "id": 1, 1307 | "label": "Keanu Reeves", 1308 | "parentId": 10, 1309 | "position": [ 1310 | 0, 1311 | 0 1312 | ], 1313 | "properties": { 1314 | "born": 1964, 1315 | "label": "Person", 1316 | "name": "Keanu Reeves" 1317 | }, 1318 | "scale_factor": 1, 1319 | "size": [ 1320 | 100, 1321 | 100 1322 | ], 1323 | "styles": { 1324 | "shape": "rectangle" 1325 | }, 1326 | "type": "#2196F3" 1327 | }, 1328 | { 1329 | "color": "#4CAF50", 1330 | "id": 0, 1331 | "label": "Title:\nThe Matrix", 1332 | "parentId": "GroupNodemovies", 1333 | "position": [ 1334 | 0, 1335 | 0 1336 | ], 1337 | "properties": { 1338 | "label": "Movie", 1339 | "released": 1999, 1340 | "tagline": "Welcome to the Real World", 1341 | "title": "The Matrix", 1342 | "votes": 6345 1343 | }, 1344 | "scale_factor": 1, 1345 | "size": [ 1346 | 55, 1347 | 55 1348 | ], 1349 | "styles": { 1350 | "label_styles": { 1351 | "backgroundColor": "rgba(0,0,0,0.7)", 1352 | "color": "#FFFFFF", 1353 | "fontSize": 20, 1354 | "fontWeight": "lighter", 1355 | "maximumWidth": 130, 1356 | "position": "north", 1357 | "textAlignment": "center", 1358 | "wrapping": "word" 1359 | } 1360 | }, 1361 | "type": "#4CAF50" 1362 | }, 1363 | { 1364 | "color": "#2196F3", 1365 | "id": 2, 1366 | "label": "Carrie-Anne Moss", 1367 | "parentId": 10, 1368 | "position": [ 1369 | 0, 1370 | 0 1371 | ], 1372 | "properties": { 1373 | "born": 1967, 1374 | "label": "Person", 1375 | "name": "Carrie-Anne Moss" 1376 | }, 1377 | "scale_factor": 1, 1378 | "size": [ 1379 | 100, 1380 | 100 1381 | ], 1382 | "styles": { 1383 | "shape": "rectangle" 1384 | }, 1385 | "type": "#2196F3" 1386 | }, 1387 | { 1388 | "color": "#2196F3", 1389 | "id": 3, 1390 | "label": "Laurence Fishburne", 1391 | "parentId": 10, 1392 | "position": [ 1393 | 0, 1394 | 0 1395 | ], 1396 | "properties": { 1397 | "born": 1961, 1398 | "label": "Person", 1399 | "name": "Laurence Fishburne" 1400 | }, 1401 | "scale_factor": 1, 1402 | "size": [ 1403 | 100, 1404 | 100 1405 | ], 1406 | "styles": { 1407 | "shape": "rectangle" 1408 | }, 1409 | "type": "#2196F3" 1410 | }, 1411 | { 1412 | "color": "#2196F3", 1413 | "id": 4, 1414 | "label": "Hugo Weaving", 1415 | "parentId": 10, 1416 | "position": [ 1417 | 0, 1418 | 0 1419 | ], 1420 | "properties": { 1421 | "born": 1960, 1422 | "label": "Person", 1423 | "name": "Hugo Weaving" 1424 | }, 1425 | "scale_factor": 1, 1426 | "size": [ 1427 | 100, 1428 | 100 1429 | ], 1430 | "styles": { 1431 | "shape": "rectangle" 1432 | }, 1433 | "type": "#2196F3" 1434 | }, 1435 | { 1436 | "color": "#2196F3", 1437 | "id": 5, 1438 | "label": "Lilly Wachowski", 1439 | "parentId": "GroupNodepeople", 1440 | "position": [ 1441 | 0, 1442 | 0 1443 | ], 1444 | "properties": { 1445 | "born": 1967, 1446 | "label": "Person", 1447 | "name": "Lilly Wachowski" 1448 | }, 1449 | "scale_factor": 1, 1450 | "size": [ 1451 | 100, 1452 | 100 1453 | ], 1454 | "styles": { 1455 | "shape": "rectangle" 1456 | }, 1457 | "type": "#2196F3" 1458 | }, 1459 | { 1460 | "color": "#2196F3", 1461 | "id": 6, 1462 | "label": "Lana Wachowski", 1463 | "parentId": "GroupNodepeople", 1464 | "position": [ 1465 | 0, 1466 | 0 1467 | ], 1468 | "properties": { 1469 | "born": 1965, 1470 | "label": "Person", 1471 | "name": "Lana Wachowski" 1472 | }, 1473 | "scale_factor": 1, 1474 | "size": [ 1475 | 100, 1476 | 100 1477 | ], 1478 | "styles": { 1479 | "shape": "rectangle" 1480 | }, 1481 | "type": "#2196F3" 1482 | }, 1483 | { 1484 | "color": "#2196F3", 1485 | "id": 7, 1486 | "label": "Joel Silver", 1487 | "parentId": "GroupNodepeople", 1488 | "position": [ 1489 | 0, 1490 | 0 1491 | ], 1492 | "properties": { 1493 | "born": 1952, 1494 | "label": "Person", 1495 | "name": "Joel Silver" 1496 | }, 1497 | "scale_factor": 1, 1498 | "size": [ 1499 | 100, 1500 | 100 1501 | ], 1502 | "styles": { 1503 | "shape": "rectangle" 1504 | }, 1505 | "type": "#2196F3" 1506 | }, 1507 | { 1508 | "color": "#2196F3", 1509 | "id": 8, 1510 | "label": "Emil Eifrem", 1511 | "parentId": 0, 1512 | "position": [ 1513 | 0, 1514 | 0 1515 | ], 1516 | "properties": { 1517 | "born": 1978, 1518 | "label": "Person", 1519 | "name": "Emil Eifrem" 1520 | }, 1521 | "scale_factor": 1, 1522 | "size": [ 1523 | 100, 1524 | 100 1525 | ], 1526 | "styles": { 1527 | "shape": "rectangle" 1528 | }, 1529 | "type": "#2196F3" 1530 | }, 1531 | { 1532 | "color": "#4CAF50", 1533 | "id": 9, 1534 | "label": "Title:\nThe Matrix Reloaded", 1535 | "parentId": "GroupNodemovies", 1536 | "position": [ 1537 | 0, 1538 | 0 1539 | ], 1540 | "properties": { 1541 | "label": "Movie", 1542 | "released": 2003, 1543 | "tagline": "Free your mind", 1544 | "title": "The Matrix Reloaded", 1545 | "votes": 1841 1546 | }, 1547 | "scale_factor": 1, 1548 | "size": [ 1549 | 55, 1550 | 55 1551 | ], 1552 | "styles": { 1553 | "label_styles": { 1554 | "backgroundColor": "rgba(0,0,0,0.7)", 1555 | "color": "#FFFFFF", 1556 | "fontSize": 20, 1557 | "fontWeight": "lighter", 1558 | "maximumWidth": 130, 1559 | "position": "north", 1560 | "textAlignment": "center", 1561 | "wrapping": "word" 1562 | } 1563 | }, 1564 | "type": "#4CAF50" 1565 | }, 1566 | { 1567 | "color": "#4CAF50", 1568 | "id": 10, 1569 | "label": "Title:\nThe Matrix Revolutions", 1570 | "parentId": "GroupNodemovies", 1571 | "position": [ 1572 | 0, 1573 | 0 1574 | ], 1575 | "properties": { 1576 | "label": "Movie", 1577 | "released": 2003, 1578 | "tagline": "Everything that has a beginning has an end", 1579 | "title": "The Matrix Revolutions", 1580 | "votes": 1534 1581 | }, 1582 | "scale_factor": 1, 1583 | "size": [ 1584 | 55, 1585 | 55 1586 | ], 1587 | "styles": { 1588 | "label_styles": { 1589 | "backgroundColor": "rgba(0,0,0,0.7)", 1590 | "color": "#FFFFFF", 1591 | "fontSize": 20, 1592 | "fontWeight": "lighter", 1593 | "maximumWidth": 130, 1594 | "position": "north", 1595 | "textAlignment": "center", 1596 | "wrapping": "word" 1597 | } 1598 | }, 1599 | "type": "#4CAF50" 1600 | }, 1601 | { 1602 | "color": "#cca9ff", 1603 | "id": "GroupNodepeople", 1604 | "label": "people", 1605 | "position": [ 1606 | 0, 1607 | 0 1608 | ], 1609 | "properties": { 1610 | "label": "people" 1611 | }, 1612 | "scale_factor": 1, 1613 | "size": [ 1614 | 55, 1615 | 55 1616 | ], 1617 | "styles": {}, 1618 | "type": "#cca9ff" 1619 | }, 1620 | { 1621 | "color": "#F44336", 1622 | "id": "GroupNodemovies", 1623 | "label": "movies", 1624 | "position": [ 1625 | 0, 1626 | 0 1627 | ], 1628 | "properties": { 1629 | "label": "movies" 1630 | }, 1631 | "scale_factor": 1, 1632 | "size": [ 1633 | 55, 1634 | 55 1635 | ], 1636 | "styles": {}, 1637 | "type": "#F44336" 1638 | } 1639 | ], 1640 | "_overview": { 1641 | "enabled": null, 1642 | "overview_set": false 1643 | }, 1644 | "_selected_graph": [ 1645 | [], 1646 | [] 1647 | ], 1648 | "_sidebar": { 1649 | "enabled": false, 1650 | "start_with": "About" 1651 | }, 1652 | "_view_module_version": "^1.10.2", 1653 | "layout": "IPY_MODEL_d5976e6a66da45828c79552aad4df578" 1654 | } 1655 | }, 1656 | "68f8e05eabb5405c932e35fc3d52cda8": { 1657 | "model_module": "@jupyter-widgets/base", 1658 | "model_module_version": "2.0.0", 1659 | "model_name": "LayoutModel", 1660 | "state": { 1661 | "height": "500px", 1662 | "width": "100%" 1663 | } 1664 | }, 1665 | "6bdf055e98594e2599fa5156c3f65956": { 1666 | "model_module": "@jupyter-widgets/base", 1667 | "model_module_version": "2.0.0", 1668 | "model_name": "LayoutModel", 1669 | "state": { 1670 | "height": "630px", 1671 | "width": "100%" 1672 | } 1673 | }, 1674 | "77f79c1038da486ebdf3db3693fa1df7": { 1675 | "model_module": "@jupyter-widgets/base", 1676 | "model_module_version": "2.0.0", 1677 | "model_name": "LayoutModel", 1678 | "state": { 1679 | "height": "610px", 1680 | "width": "100%" 1681 | } 1682 | }, 1683 | "7e45a2312586497fbc5d6ed31e553dc3": { 1684 | "model_module": "@jupyter-widgets/base", 1685 | "model_module_version": "2.0.0", 1686 | "model_name": "LayoutModel", 1687 | "state": { 1688 | "height": "630px", 1689 | "width": "100%" 1690 | } 1691 | }, 1692 | "80ee4436b5b1406c9e8c025864afecdc": { 1693 | "model_module": "@jupyter-widgets/base", 1694 | "model_module_version": "2.0.0", 1695 | "model_name": "LayoutModel", 1696 | "state": { 1697 | "height": "500px", 1698 | "width": "100%" 1699 | } 1700 | }, 1701 | "9737c7185d0842118fca7fb4141a5cff": { 1702 | "model_module": "@jupyter-widgets/base", 1703 | "model_module_version": "2.0.0", 1704 | "model_name": "LayoutModel", 1705 | "state": { 1706 | "height": "500px", 1707 | "width": "100%" 1708 | } 1709 | }, 1710 | "9bbb8051faf243dbb3ed865d02d79116": { 1711 | "model_module": "yfiles-jupyter-graphs", 1712 | "model_module_version": "^1.10.2", 1713 | "model_name": "GraphModel", 1714 | "state": { 1715 | "_context_pane_mapping": [ 1716 | { 1717 | "id": "Neighborhood", 1718 | "title": "Neighborhood" 1719 | }, 1720 | { 1721 | "id": "Data", 1722 | "title": "Data" 1723 | }, 1724 | { 1725 | "id": "Search", 1726 | "title": "Search" 1727 | }, 1728 | { 1729 | "id": "About", 1730 | "title": "About" 1731 | } 1732 | ], 1733 | "_data_importer": "neo4j", 1734 | "_directed": true, 1735 | "_edges": [ 1736 | { 1737 | "color": "#AC94F4", 1738 | "directed": true, 1739 | "end": 0, 1740 | "id": 0, 1741 | "label": "ACTED_IN", 1742 | "properties": { 1743 | "label": "ACTED_IN", 1744 | "roles": [ 1745 | "Neo" 1746 | ] 1747 | }, 1748 | "start": 1, 1749 | "styles": {}, 1750 | "thickness_factor": 2 1751 | }, 1752 | { 1753 | "color": "#AC94F4", 1754 | "directed": true, 1755 | "end": 0, 1756 | "id": 1, 1757 | "label": "ACTED_IN", 1758 | "properties": { 1759 | "label": "ACTED_IN", 1760 | "roles": [ 1761 | "Trinity" 1762 | ] 1763 | }, 1764 | "start": 2, 1765 | "styles": {}, 1766 | "thickness_factor": 2 1767 | }, 1768 | { 1769 | "color": "#AC94F4", 1770 | "directed": true, 1771 | "end": 0, 1772 | "id": 2, 1773 | "label": "ACTED_IN", 1774 | "properties": { 1775 | "label": "ACTED_IN", 1776 | "roles": [ 1777 | "Morpheus" 1778 | ] 1779 | }, 1780 | "start": 3, 1781 | "styles": {}, 1782 | "thickness_factor": 2 1783 | }, 1784 | { 1785 | "color": "#AC94F4", 1786 | "directed": true, 1787 | "end": 0, 1788 | "id": 3, 1789 | "label": "ACTED_IN", 1790 | "properties": { 1791 | "label": "ACTED_IN", 1792 | "roles": [ 1793 | "Agent Smith" 1794 | ] 1795 | }, 1796 | "start": 4, 1797 | "styles": {}, 1798 | "thickness_factor": 2 1799 | }, 1800 | { 1801 | "color": "blue", 1802 | "directed": true, 1803 | "end": 0, 1804 | "id": 4, 1805 | "label": "DIRECTED", 1806 | "properties": { 1807 | "label": "DIRECTED" 1808 | }, 1809 | "start": 5, 1810 | "styles": { 1811 | "dashStyle": "dot" 1812 | }, 1813 | "thickness_factor": 1 1814 | }, 1815 | { 1816 | "color": "blue", 1817 | "directed": true, 1818 | "end": 0, 1819 | "id": 5, 1820 | "label": "DIRECTED", 1821 | "properties": { 1822 | "label": "DIRECTED" 1823 | }, 1824 | "start": 6, 1825 | "styles": { 1826 | "dashStyle": "dot" 1827 | }, 1828 | "thickness_factor": 1 1829 | }, 1830 | { 1831 | "color": "#AC94F4", 1832 | "directed": true, 1833 | "end": 0, 1834 | "id": 6, 1835 | "label": "produced", 1836 | "properties": { 1837 | "label": "PRODUCED" 1838 | }, 1839 | "start": 7, 1840 | "styles": { 1841 | "label_styles": { 1842 | "fontWeight": "bolder" 1843 | } 1844 | }, 1845 | "thickness_factor": 1 1846 | }, 1847 | { 1848 | "color": "#AC94F4", 1849 | "directed": true, 1850 | "end": 0, 1851 | "id": 7, 1852 | "label": "ACTED_IN", 1853 | "properties": { 1854 | "label": "ACTED_IN", 1855 | "roles": [ 1856 | "Emil" 1857 | ] 1858 | }, 1859 | "start": 8, 1860 | "styles": {}, 1861 | "thickness_factor": 2 1862 | }, 1863 | { 1864 | "color": "#AC94F4", 1865 | "directed": true, 1866 | "end": 9, 1867 | "id": 8, 1868 | "label": "ACTED_IN", 1869 | "properties": { 1870 | "label": "ACTED_IN", 1871 | "roles": [ 1872 | "Neo" 1873 | ] 1874 | }, 1875 | "start": 1, 1876 | "styles": {}, 1877 | "thickness_factor": 2 1878 | }, 1879 | { 1880 | "color": "#AC94F4", 1881 | "directed": true, 1882 | "end": 9, 1883 | "id": 9, 1884 | "label": "ACTED_IN", 1885 | "properties": { 1886 | "label": "ACTED_IN", 1887 | "roles": [ 1888 | "Trinity" 1889 | ] 1890 | }, 1891 | "start": 2, 1892 | "styles": {}, 1893 | "thickness_factor": 2 1894 | }, 1895 | { 1896 | "color": "#AC94F4", 1897 | "directed": true, 1898 | "end": 9, 1899 | "id": 10, 1900 | "label": "ACTED_IN", 1901 | "properties": { 1902 | "label": "ACTED_IN", 1903 | "roles": [ 1904 | "Morpheus" 1905 | ] 1906 | }, 1907 | "start": 3, 1908 | "styles": {}, 1909 | "thickness_factor": 2 1910 | }, 1911 | { 1912 | "color": "#AC94F4", 1913 | "directed": true, 1914 | "end": 9, 1915 | "id": 11, 1916 | "label": "ACTED_IN", 1917 | "properties": { 1918 | "label": "ACTED_IN", 1919 | "roles": [ 1920 | "Agent Smith" 1921 | ] 1922 | }, 1923 | "start": 4, 1924 | "styles": {}, 1925 | "thickness_factor": 2 1926 | }, 1927 | { 1928 | "color": "blue", 1929 | "directed": true, 1930 | "end": 9, 1931 | "id": 12, 1932 | "label": "DIRECTED", 1933 | "properties": { 1934 | "label": "DIRECTED" 1935 | }, 1936 | "start": 5, 1937 | "styles": { 1938 | "dashStyle": "dot" 1939 | }, 1940 | "thickness_factor": 1 1941 | }, 1942 | { 1943 | "color": "blue", 1944 | "directed": true, 1945 | "end": 9, 1946 | "id": 13, 1947 | "label": "DIRECTED", 1948 | "properties": { 1949 | "label": "DIRECTED" 1950 | }, 1951 | "start": 6, 1952 | "styles": { 1953 | "dashStyle": "dot" 1954 | }, 1955 | "thickness_factor": 1 1956 | }, 1957 | { 1958 | "color": "#AC94F4", 1959 | "directed": true, 1960 | "end": 9, 1961 | "id": 14, 1962 | "label": "produced", 1963 | "properties": { 1964 | "label": "PRODUCED" 1965 | }, 1966 | "start": 7, 1967 | "styles": { 1968 | "label_styles": { 1969 | "fontWeight": "bolder" 1970 | } 1971 | }, 1972 | "thickness_factor": 1 1973 | }, 1974 | { 1975 | "color": "#AC94F4", 1976 | "directed": true, 1977 | "end": 10, 1978 | "id": 15, 1979 | "label": "ACTED_IN", 1980 | "properties": { 1981 | "label": "ACTED_IN", 1982 | "roles": [ 1983 | "Neo" 1984 | ] 1985 | }, 1986 | "start": 1, 1987 | "styles": {}, 1988 | "thickness_factor": 2 1989 | }, 1990 | { 1991 | "color": "#AC94F4", 1992 | "directed": true, 1993 | "end": 10, 1994 | "id": 16, 1995 | "label": "ACTED_IN", 1996 | "properties": { 1997 | "label": "ACTED_IN", 1998 | "roles": [ 1999 | "Trinity" 2000 | ] 2001 | }, 2002 | "start": 2, 2003 | "styles": {}, 2004 | "thickness_factor": 2 2005 | }, 2006 | { 2007 | "color": "#AC94F4", 2008 | "directed": true, 2009 | "end": 10, 2010 | "id": 17, 2011 | "label": "ACTED_IN", 2012 | "properties": { 2013 | "label": "ACTED_IN", 2014 | "roles": [ 2015 | "Morpheus" 2016 | ] 2017 | }, 2018 | "start": 3, 2019 | "styles": {}, 2020 | "thickness_factor": 2 2021 | }, 2022 | { 2023 | "color": "#AC94F4", 2024 | "directed": true, 2025 | "end": 10, 2026 | "id": 18, 2027 | "label": "ACTED_IN", 2028 | "properties": { 2029 | "label": "ACTED_IN", 2030 | "roles": [ 2031 | "Agent Smith" 2032 | ] 2033 | }, 2034 | "start": 4, 2035 | "styles": {}, 2036 | "thickness_factor": 2 2037 | }, 2038 | { 2039 | "color": "blue", 2040 | "directed": true, 2041 | "end": 10, 2042 | "id": 19, 2043 | "label": "DIRECTED", 2044 | "properties": { 2045 | "label": "DIRECTED" 2046 | }, 2047 | "start": 5, 2048 | "styles": { 2049 | "dashStyle": "dot" 2050 | }, 2051 | "thickness_factor": 1 2052 | } 2053 | ], 2054 | "_graph_layout": { 2055 | "algorithm": "organic", 2056 | "options": {} 2057 | }, 2058 | "_model_module_version": "^1.10.2", 2059 | "_nodes": [ 2060 | { 2061 | "color": "#2196F3", 2062 | "id": 1, 2063 | "label": "Keanu Reeves", 2064 | "parentId": "GroupNodepeople", 2065 | "position": [ 2066 | 0, 2067 | 0 2068 | ], 2069 | "properties": { 2070 | "born": 1964, 2071 | "label": "Person", 2072 | "name": "Keanu Reeves" 2073 | }, 2074 | "scale_factor": 1, 2075 | "size": [ 2076 | 100, 2077 | 100 2078 | ], 2079 | "styles": { 2080 | "shape": "rectangle" 2081 | }, 2082 | "type": "#2196F3" 2083 | }, 2084 | { 2085 | "color": "#4CAF50", 2086 | "id": 0, 2087 | "label": "Title:\nThe Matrix", 2088 | "parentId": "GroupNodemovies", 2089 | "position": [ 2090 | 0, 2091 | 0 2092 | ], 2093 | "properties": { 2094 | "label": "Movie", 2095 | "released": 1999, 2096 | "tagline": "Welcome to the Real World", 2097 | "title": "The Matrix", 2098 | "votes": 6345 2099 | }, 2100 | "scale_factor": 1, 2101 | "size": [ 2102 | 55, 2103 | 55 2104 | ], 2105 | "styles": { 2106 | "label_styles": { 2107 | "backgroundColor": "rgba(0,0,0,0.7)", 2108 | "color": "#FFFFFF", 2109 | "fontSize": 20, 2110 | "fontWeight": "lighter", 2111 | "maximumWidth": 130, 2112 | "position": "north", 2113 | "textAlignment": "center", 2114 | "wrapping": "word" 2115 | } 2116 | }, 2117 | "type": "#4CAF50" 2118 | }, 2119 | { 2120 | "color": "#2196F3", 2121 | "id": 2, 2122 | "label": "Carrie-Anne Moss", 2123 | "parentId": "GroupNodepeople", 2124 | "position": [ 2125 | 0, 2126 | 0 2127 | ], 2128 | "properties": { 2129 | "born": 1967, 2130 | "label": "Person", 2131 | "name": "Carrie-Anne Moss" 2132 | }, 2133 | "scale_factor": 1, 2134 | "size": [ 2135 | 100, 2136 | 100 2137 | ], 2138 | "styles": { 2139 | "shape": "rectangle" 2140 | }, 2141 | "type": "#2196F3" 2142 | }, 2143 | { 2144 | "color": "#2196F3", 2145 | "id": 3, 2146 | "label": "Laurence Fishburne", 2147 | "parentId": "GroupNodepeople", 2148 | "position": [ 2149 | 0, 2150 | 0 2151 | ], 2152 | "properties": { 2153 | "born": 1961, 2154 | "label": "Person", 2155 | "name": "Laurence Fishburne" 2156 | }, 2157 | "scale_factor": 1, 2158 | "size": [ 2159 | 100, 2160 | 100 2161 | ], 2162 | "styles": { 2163 | "shape": "rectangle" 2164 | }, 2165 | "type": "#2196F3" 2166 | }, 2167 | { 2168 | "color": "#2196F3", 2169 | "id": 4, 2170 | "label": "Hugo Weaving", 2171 | "parentId": "GroupNodepeople", 2172 | "position": [ 2173 | 0, 2174 | 0 2175 | ], 2176 | "properties": { 2177 | "born": 1960, 2178 | "label": "Person", 2179 | "name": "Hugo Weaving" 2180 | }, 2181 | "scale_factor": 1, 2182 | "size": [ 2183 | 100, 2184 | 100 2185 | ], 2186 | "styles": { 2187 | "shape": "rectangle" 2188 | }, 2189 | "type": "#2196F3" 2190 | }, 2191 | { 2192 | "color": "#2196F3", 2193 | "id": 5, 2194 | "label": "Lilly Wachowski", 2195 | "parentId": "GroupNodepeople", 2196 | "position": [ 2197 | 0, 2198 | 0 2199 | ], 2200 | "properties": { 2201 | "born": 1967, 2202 | "label": "Person", 2203 | "name": "Lilly Wachowski" 2204 | }, 2205 | "scale_factor": 1, 2206 | "size": [ 2207 | 100, 2208 | 100 2209 | ], 2210 | "styles": { 2211 | "shape": "rectangle" 2212 | }, 2213 | "type": "#2196F3" 2214 | }, 2215 | { 2216 | "color": "#2196F3", 2217 | "id": 6, 2218 | "label": "Lana Wachowski", 2219 | "parentId": "GroupNodepeople", 2220 | "position": [ 2221 | 0, 2222 | 0 2223 | ], 2224 | "properties": { 2225 | "born": 1965, 2226 | "label": "Person", 2227 | "name": "Lana Wachowski" 2228 | }, 2229 | "scale_factor": 1, 2230 | "size": [ 2231 | 100, 2232 | 100 2233 | ], 2234 | "styles": { 2235 | "shape": "rectangle" 2236 | }, 2237 | "type": "#2196F3" 2238 | }, 2239 | { 2240 | "color": "#2196F3", 2241 | "id": 7, 2242 | "label": "Joel Silver", 2243 | "parentId": "GroupNodepeople", 2244 | "position": [ 2245 | 0, 2246 | 0 2247 | ], 2248 | "properties": { 2249 | "born": 1952, 2250 | "label": "Person", 2251 | "name": "Joel Silver" 2252 | }, 2253 | "scale_factor": 1, 2254 | "size": [ 2255 | 100, 2256 | 100 2257 | ], 2258 | "styles": { 2259 | "shape": "rectangle" 2260 | }, 2261 | "type": "#2196F3" 2262 | }, 2263 | { 2264 | "color": "#2196F3", 2265 | "id": 8, 2266 | "label": "Emil Eifrem", 2267 | "parentId": "GroupNodepeople", 2268 | "position": [ 2269 | 0, 2270 | 0 2271 | ], 2272 | "properties": { 2273 | "born": 1978, 2274 | "label": "Person", 2275 | "name": "Emil Eifrem" 2276 | }, 2277 | "scale_factor": 1, 2278 | "size": [ 2279 | 100, 2280 | 100 2281 | ], 2282 | "styles": { 2283 | "shape": "rectangle" 2284 | }, 2285 | "type": "#2196F3" 2286 | }, 2287 | { 2288 | "color": "#4CAF50", 2289 | "id": 9, 2290 | "label": "Title:\nThe Matrix Reloaded", 2291 | "parentId": "GroupNodemovies", 2292 | "position": [ 2293 | 0, 2294 | 0 2295 | ], 2296 | "properties": { 2297 | "label": "Movie", 2298 | "released": 2003, 2299 | "tagline": "Free your mind", 2300 | "title": "The Matrix Reloaded", 2301 | "votes": 1841 2302 | }, 2303 | "scale_factor": 1, 2304 | "size": [ 2305 | 55, 2306 | 55 2307 | ], 2308 | "styles": { 2309 | "label_styles": { 2310 | "backgroundColor": "rgba(0,0,0,0.7)", 2311 | "color": "#FFFFFF", 2312 | "fontSize": 20, 2313 | "fontWeight": "lighter", 2314 | "maximumWidth": 130, 2315 | "position": "north", 2316 | "textAlignment": "center", 2317 | "wrapping": "word" 2318 | } 2319 | }, 2320 | "type": "#4CAF50" 2321 | }, 2322 | { 2323 | "color": "#4CAF50", 2324 | "id": 10, 2325 | "label": "Title:\nThe Matrix Revolutions", 2326 | "parentId": "GroupNodemovies", 2327 | "position": [ 2328 | 0, 2329 | 0 2330 | ], 2331 | "properties": { 2332 | "label": "Movie", 2333 | "released": 2003, 2334 | "tagline": "Everything that has a beginning has an end", 2335 | "title": "The Matrix Revolutions", 2336 | "votes": 1534 2337 | }, 2338 | "scale_factor": 1, 2339 | "size": [ 2340 | 55, 2341 | 55 2342 | ], 2343 | "styles": { 2344 | "label_styles": { 2345 | "backgroundColor": "rgba(0,0,0,0.7)", 2346 | "color": "#FFFFFF", 2347 | "fontSize": 20, 2348 | "fontWeight": "lighter", 2349 | "maximumWidth": 130, 2350 | "position": "north", 2351 | "textAlignment": "center", 2352 | "wrapping": "word" 2353 | } 2354 | }, 2355 | "type": "#4CAF50" 2356 | }, 2357 | { 2358 | "color": "#cca9ff", 2359 | "id": "GroupNodepeople", 2360 | "label": "people", 2361 | "position": [ 2362 | 0, 2363 | 0 2364 | ], 2365 | "properties": { 2366 | "label": "people" 2367 | }, 2368 | "scale_factor": 1, 2369 | "size": [ 2370 | 55, 2371 | 55 2372 | ], 2373 | "styles": { 2374 | "color": "#cca9ff" 2375 | }, 2376 | "type": "#cca9ff" 2377 | }, 2378 | { 2379 | "color": "#F44336", 2380 | "id": "GroupNodemovies", 2381 | "label": "movies", 2382 | "position": [ 2383 | 0, 2384 | 0 2385 | ], 2386 | "properties": { 2387 | "label": "movies" 2388 | }, 2389 | "scale_factor": 1, 2390 | "size": [ 2391 | 55, 2392 | 55 2393 | ], 2394 | "styles": {}, 2395 | "type": "#F44336" 2396 | } 2397 | ], 2398 | "_overview": { 2399 | "enabled": null, 2400 | "overview_set": false 2401 | }, 2402 | "_selected_graph": [ 2403 | [ 2404 | { 2405 | "id": "GroupNodepeople", 2406 | "properties": { 2407 | "label": "people" 2408 | } 2409 | } 2410 | ], 2411 | [] 2412 | ], 2413 | "_sidebar": { 2414 | "enabled": false, 2415 | "start_with": "About" 2416 | }, 2417 | "_view_module_version": "^1.10.2", 2418 | "layout": "IPY_MODEL_7e45a2312586497fbc5d6ed31e553dc3" 2419 | } 2420 | }, 2421 | "9f6b785b62394938ae19744a4479b796": { 2422 | "model_module": "yfiles-jupyter-graphs", 2423 | "model_module_version": "^1.10.2", 2424 | "model_name": "GraphModel", 2425 | "state": { 2426 | "_context_pane_mapping": [ 2427 | { 2428 | "id": "Neighborhood", 2429 | "title": "Neighborhood" 2430 | }, 2431 | { 2432 | "id": "Data", 2433 | "title": "Data" 2434 | }, 2435 | { 2436 | "id": "Search", 2437 | "title": "Search" 2438 | }, 2439 | { 2440 | "id": "About", 2441 | "title": "About" 2442 | } 2443 | ], 2444 | "_data_importer": "neo4j", 2445 | "_directed": true, 2446 | "_edges": [ 2447 | { 2448 | "color": "blue", 2449 | "directed": true, 2450 | "end": 0, 2451 | "id": 4, 2452 | "label": "DIRECTED", 2453 | "properties": { 2454 | "label": "DIRECTED" 2455 | }, 2456 | "start": 5, 2457 | "styles": { 2458 | "dashStyle": "dot" 2459 | }, 2460 | "thickness_factor": 1 2461 | }, 2462 | { 2463 | "color": "blue", 2464 | "directed": true, 2465 | "end": 0, 2466 | "id": 5, 2467 | "label": "DIRECTED", 2468 | "properties": { 2469 | "label": "DIRECTED" 2470 | }, 2471 | "start": 6, 2472 | "styles": { 2473 | "dashStyle": "dot" 2474 | }, 2475 | "thickness_factor": 1 2476 | }, 2477 | { 2478 | "color": "#AC94F4", 2479 | "directed": true, 2480 | "end": 0, 2481 | "id": 6, 2482 | "label": "produced", 2483 | "properties": { 2484 | "label": "PRODUCED" 2485 | }, 2486 | "start": 7, 2487 | "styles": { 2488 | "label_styles": { 2489 | "fontWeight": "bolder" 2490 | } 2491 | }, 2492 | "thickness_factor": 1 2493 | }, 2494 | { 2495 | "color": "blue", 2496 | "directed": true, 2497 | "end": 9, 2498 | "id": 12, 2499 | "label": "DIRECTED", 2500 | "properties": { 2501 | "label": "DIRECTED" 2502 | }, 2503 | "start": 5, 2504 | "styles": { 2505 | "dashStyle": "dot" 2506 | }, 2507 | "thickness_factor": 1 2508 | }, 2509 | { 2510 | "color": "blue", 2511 | "directed": true, 2512 | "end": 9, 2513 | "id": 13, 2514 | "label": "DIRECTED", 2515 | "properties": { 2516 | "label": "DIRECTED" 2517 | }, 2518 | "start": 6, 2519 | "styles": { 2520 | "dashStyle": "dot" 2521 | }, 2522 | "thickness_factor": 1 2523 | }, 2524 | { 2525 | "color": "#AC94F4", 2526 | "directed": true, 2527 | "end": 9, 2528 | "id": 14, 2529 | "label": "produced", 2530 | "properties": { 2531 | "label": "PRODUCED" 2532 | }, 2533 | "start": 7, 2534 | "styles": { 2535 | "label_styles": { 2536 | "fontWeight": "bolder" 2537 | } 2538 | }, 2539 | "thickness_factor": 1 2540 | }, 2541 | { 2542 | "color": "blue", 2543 | "directed": true, 2544 | "end": 10, 2545 | "id": 19, 2546 | "label": "DIRECTED", 2547 | "properties": { 2548 | "label": "DIRECTED" 2549 | }, 2550 | "start": 5, 2551 | "styles": { 2552 | "dashStyle": "dot" 2553 | }, 2554 | "thickness_factor": 1 2555 | } 2556 | ], 2557 | "_graph_layout": { 2558 | "algorithm": "organic", 2559 | "options": {} 2560 | }, 2561 | "_model_module_version": "^1.10.2", 2562 | "_nodes": [ 2563 | { 2564 | "color": "#2196F3", 2565 | "id": 1, 2566 | "label": "Keanu Reeves", 2567 | "parentId": 10, 2568 | "position": [ 2569 | 0, 2570 | 0 2571 | ], 2572 | "properties": { 2573 | "born": 1964, 2574 | "label": "Person", 2575 | "name": "Keanu Reeves" 2576 | }, 2577 | "scale_factor": 1, 2578 | "size": [ 2579 | 100, 2580 | 100 2581 | ], 2582 | "styles": { 2583 | "shape": "rectangle" 2584 | }, 2585 | "type": "#2196F3" 2586 | }, 2587 | { 2588 | "color": "#4CAF50", 2589 | "id": 0, 2590 | "label": "Title:\nThe Matrix", 2591 | "parentId": "GroupNodemovies", 2592 | "position": [ 2593 | 0, 2594 | 0 2595 | ], 2596 | "properties": { 2597 | "label": "Movie", 2598 | "released": 1999, 2599 | "tagline": "Welcome to the Real World", 2600 | "title": "The Matrix", 2601 | "votes": 6345 2602 | }, 2603 | "scale_factor": 1, 2604 | "size": [ 2605 | 55, 2606 | 55 2607 | ], 2608 | "styles": { 2609 | "label_styles": { 2610 | "backgroundColor": "rgba(0,0,0,0.7)", 2611 | "color": "#FFFFFF", 2612 | "fontSize": 20, 2613 | "fontWeight": "lighter", 2614 | "maximumWidth": 130, 2615 | "position": "north", 2616 | "textAlignment": "center", 2617 | "wrapping": "word" 2618 | } 2619 | }, 2620 | "type": "#4CAF50" 2621 | }, 2622 | { 2623 | "color": "#2196F3", 2624 | "id": 2, 2625 | "label": "Carrie-Anne Moss", 2626 | "parentId": 10, 2627 | "position": [ 2628 | 0, 2629 | 0 2630 | ], 2631 | "properties": { 2632 | "born": 1967, 2633 | "label": "Person", 2634 | "name": "Carrie-Anne Moss" 2635 | }, 2636 | "scale_factor": 1, 2637 | "size": [ 2638 | 100, 2639 | 100 2640 | ], 2641 | "styles": { 2642 | "shape": "rectangle" 2643 | }, 2644 | "type": "#2196F3" 2645 | }, 2646 | { 2647 | "color": "#2196F3", 2648 | "id": 3, 2649 | "label": "Laurence Fishburne", 2650 | "parentId": 10, 2651 | "position": [ 2652 | 0, 2653 | 0 2654 | ], 2655 | "properties": { 2656 | "born": 1961, 2657 | "label": "Person", 2658 | "name": "Laurence Fishburne" 2659 | }, 2660 | "scale_factor": 1, 2661 | "size": [ 2662 | 100, 2663 | 100 2664 | ], 2665 | "styles": { 2666 | "shape": "rectangle" 2667 | }, 2668 | "type": "#2196F3" 2669 | }, 2670 | { 2671 | "color": "#2196F3", 2672 | "id": 4, 2673 | "label": "Hugo Weaving", 2674 | "parentId": 10, 2675 | "position": [ 2676 | 0, 2677 | 0 2678 | ], 2679 | "properties": { 2680 | "born": 1960, 2681 | "label": "Person", 2682 | "name": "Hugo Weaving" 2683 | }, 2684 | "scale_factor": 1, 2685 | "size": [ 2686 | 100, 2687 | 100 2688 | ], 2689 | "styles": { 2690 | "shape": "rectangle" 2691 | }, 2692 | "type": "#2196F3" 2693 | }, 2694 | { 2695 | "color": "#2196F3", 2696 | "id": 5, 2697 | "label": "Lilly Wachowski", 2698 | "parentId": "GroupNodepeople", 2699 | "position": [ 2700 | 0, 2701 | 0 2702 | ], 2703 | "properties": { 2704 | "born": 1967, 2705 | "label": "Person", 2706 | "name": "Lilly Wachowski" 2707 | }, 2708 | "scale_factor": 1, 2709 | "size": [ 2710 | 100, 2711 | 100 2712 | ], 2713 | "styles": { 2714 | "shape": "rectangle" 2715 | }, 2716 | "type": "#2196F3" 2717 | }, 2718 | { 2719 | "color": "#2196F3", 2720 | "id": 6, 2721 | "label": "Lana Wachowski", 2722 | "parentId": "GroupNodepeople", 2723 | "position": [ 2724 | 0, 2725 | 0 2726 | ], 2727 | "properties": { 2728 | "born": 1965, 2729 | "label": "Person", 2730 | "name": "Lana Wachowski" 2731 | }, 2732 | "scale_factor": 1, 2733 | "size": [ 2734 | 100, 2735 | 100 2736 | ], 2737 | "styles": { 2738 | "shape": "rectangle" 2739 | }, 2740 | "type": "#2196F3" 2741 | }, 2742 | { 2743 | "color": "#2196F3", 2744 | "id": 7, 2745 | "label": "Joel Silver", 2746 | "parentId": "GroupNodepeople", 2747 | "position": [ 2748 | 0, 2749 | 0 2750 | ], 2751 | "properties": { 2752 | "born": 1952, 2753 | "label": "Person", 2754 | "name": "Joel Silver" 2755 | }, 2756 | "scale_factor": 1, 2757 | "size": [ 2758 | 100, 2759 | 100 2760 | ], 2761 | "styles": { 2762 | "shape": "rectangle" 2763 | }, 2764 | "type": "#2196F3" 2765 | }, 2766 | { 2767 | "color": "#2196F3", 2768 | "id": 8, 2769 | "label": "Emil Eifrem", 2770 | "parentId": 0, 2771 | "position": [ 2772 | 0, 2773 | 0 2774 | ], 2775 | "properties": { 2776 | "born": 1978, 2777 | "label": "Person", 2778 | "name": "Emil Eifrem" 2779 | }, 2780 | "scale_factor": 1, 2781 | "size": [ 2782 | 100, 2783 | 100 2784 | ], 2785 | "styles": { 2786 | "shape": "rectangle" 2787 | }, 2788 | "type": "#2196F3" 2789 | }, 2790 | { 2791 | "color": "#4CAF50", 2792 | "id": 9, 2793 | "label": "Title:\nThe Matrix Reloaded", 2794 | "parentId": "GroupNodemovies", 2795 | "position": [ 2796 | 0, 2797 | 0 2798 | ], 2799 | "properties": { 2800 | "label": "Movie", 2801 | "released": 2003, 2802 | "tagline": "Free your mind", 2803 | "title": "The Matrix Reloaded", 2804 | "votes": 1841 2805 | }, 2806 | "scale_factor": 1, 2807 | "size": [ 2808 | 55, 2809 | 55 2810 | ], 2811 | "styles": { 2812 | "label_styles": { 2813 | "backgroundColor": "rgba(0,0,0,0.7)", 2814 | "color": "#FFFFFF", 2815 | "fontSize": 20, 2816 | "fontWeight": "lighter", 2817 | "maximumWidth": 130, 2818 | "position": "north", 2819 | "textAlignment": "center", 2820 | "wrapping": "word" 2821 | } 2822 | }, 2823 | "type": "#4CAF50" 2824 | }, 2825 | { 2826 | "color": "#4CAF50", 2827 | "id": 10, 2828 | "label": "Title:\nThe Matrix Revolutions", 2829 | "parentId": "GroupNodemovies", 2830 | "position": [ 2831 | 0, 2832 | 0 2833 | ], 2834 | "properties": { 2835 | "label": "Movie", 2836 | "released": 2003, 2837 | "tagline": "Everything that has a beginning has an end", 2838 | "title": "The Matrix Revolutions", 2839 | "votes": 1534 2840 | }, 2841 | "scale_factor": 1, 2842 | "size": [ 2843 | 55, 2844 | 55 2845 | ], 2846 | "styles": { 2847 | "label_styles": { 2848 | "backgroundColor": "rgba(0,0,0,0.7)", 2849 | "color": "#FFFFFF", 2850 | "fontSize": 20, 2851 | "fontWeight": "lighter", 2852 | "maximumWidth": 130, 2853 | "position": "north", 2854 | "textAlignment": "center", 2855 | "wrapping": "word" 2856 | } 2857 | }, 2858 | "type": "#4CAF50" 2859 | }, 2860 | { 2861 | "color": "#cca9ff", 2862 | "id": "GroupNodepeople", 2863 | "label": "people", 2864 | "position": [ 2865 | 0, 2866 | 0 2867 | ], 2868 | "properties": { 2869 | "label": "people" 2870 | }, 2871 | "scale_factor": 1, 2872 | "size": [ 2873 | 55, 2874 | 55 2875 | ], 2876 | "styles": {}, 2877 | "type": "#cca9ff" 2878 | }, 2879 | { 2880 | "color": "#F44336", 2881 | "id": "GroupNodemovies", 2882 | "label": "movies", 2883 | "position": [ 2884 | 0, 2885 | 0 2886 | ], 2887 | "properties": { 2888 | "label": "movies" 2889 | }, 2890 | "scale_factor": 1, 2891 | "size": [ 2892 | 55, 2893 | 55 2894 | ], 2895 | "styles": {}, 2896 | "type": "#F44336" 2897 | } 2898 | ], 2899 | "_overview": { 2900 | "enabled": null, 2901 | "overview_set": false 2902 | }, 2903 | "_selected_graph": [ 2904 | [], 2905 | [] 2906 | ], 2907 | "_sidebar": { 2908 | "enabled": false, 2909 | "start_with": "About" 2910 | }, 2911 | "_view_module_version": "^1.10.2", 2912 | "layout": "IPY_MODEL_dbc205b3693047f4832f11957c0ede1e" 2913 | } 2914 | }, 2915 | "a4c9e65aa82e4824a015a17bf52ba2a5": { 2916 | "model_module": "@jupyter-widgets/base", 2917 | "model_module_version": "2.0.0", 2918 | "model_name": "LayoutModel", 2919 | "state": { 2920 | "height": "500px", 2921 | "width": "100%" 2922 | } 2923 | }, 2924 | "b75d05a06bf5430eb7bcd20497262a02": { 2925 | "model_module": "@jupyter-widgets/base", 2926 | "model_module_version": "2.0.0", 2927 | "model_name": "LayoutModel", 2928 | "state": { 2929 | "height": "630px", 2930 | "width": "100%" 2931 | } 2932 | }, 2933 | "c83fe4af42f84c83b12f829ff46ac16e": { 2934 | "model_module": "yfiles-jupyter-graphs", 2935 | "model_module_version": "^1.10.2", 2936 | "model_name": "GraphModel", 2937 | "state": { 2938 | "_context_pane_mapping": [ 2939 | { 2940 | "id": "Neighborhood", 2941 | "title": "Neighborhood" 2942 | }, 2943 | { 2944 | "id": "Data", 2945 | "title": "Data" 2946 | }, 2947 | { 2948 | "id": "Search", 2949 | "title": "Search" 2950 | }, 2951 | { 2952 | "id": "About", 2953 | "title": "About" 2954 | } 2955 | ], 2956 | "_data_importer": "neo4j", 2957 | "_directed": true, 2958 | "_edges": [ 2959 | { 2960 | "color": "blue", 2961 | "directed": true, 2962 | "end": 0, 2963 | "id": 4, 2964 | "label": "DIRECTED", 2965 | "properties": { 2966 | "label": "DIRECTED" 2967 | }, 2968 | "start": 5, 2969 | "styles": { 2970 | "dashStyle": "dot" 2971 | }, 2972 | "thickness_factor": 1 2973 | }, 2974 | { 2975 | "color": "blue", 2976 | "directed": true, 2977 | "end": 0, 2978 | "id": 5, 2979 | "label": "DIRECTED", 2980 | "properties": { 2981 | "label": "DIRECTED" 2982 | }, 2983 | "start": 6, 2984 | "styles": { 2985 | "dashStyle": "dot" 2986 | }, 2987 | "thickness_factor": 1 2988 | }, 2989 | { 2990 | "color": "#AC94F4", 2991 | "directed": true, 2992 | "end": 0, 2993 | "id": 6, 2994 | "label": "produced", 2995 | "properties": { 2996 | "label": "PRODUCED" 2997 | }, 2998 | "start": 7, 2999 | "styles": { 3000 | "label_styles": { 3001 | "fontSize": 16, 3002 | "fontWeight": "bolder" 3003 | } 3004 | }, 3005 | "thickness_factor": 1 3006 | }, 3007 | { 3008 | "color": "blue", 3009 | "directed": true, 3010 | "end": 9, 3011 | "id": 12, 3012 | "label": "DIRECTED", 3013 | "properties": { 3014 | "label": "DIRECTED" 3015 | }, 3016 | "start": 5, 3017 | "styles": { 3018 | "dashStyle": "dot" 3019 | }, 3020 | "thickness_factor": 1 3021 | }, 3022 | { 3023 | "color": "blue", 3024 | "directed": true, 3025 | "end": 9, 3026 | "id": 13, 3027 | "label": "DIRECTED", 3028 | "properties": { 3029 | "label": "DIRECTED" 3030 | }, 3031 | "start": 6, 3032 | "styles": { 3033 | "dashStyle": "dot" 3034 | }, 3035 | "thickness_factor": 1 3036 | }, 3037 | { 3038 | "color": "#AC94F4", 3039 | "directed": true, 3040 | "end": 9, 3041 | "id": 14, 3042 | "label": "produced", 3043 | "properties": { 3044 | "label": "PRODUCED" 3045 | }, 3046 | "start": 7, 3047 | "styles": { 3048 | "label_styles": { 3049 | "fontSize": 16, 3050 | "fontWeight": "bolder" 3051 | } 3052 | }, 3053 | "thickness_factor": 1 3054 | }, 3055 | { 3056 | "color": "blue", 3057 | "directed": true, 3058 | "end": 10, 3059 | "id": 19, 3060 | "label": "DIRECTED", 3061 | "properties": { 3062 | "label": "DIRECTED" 3063 | }, 3064 | "start": 5, 3065 | "styles": { 3066 | "dashStyle": "dot" 3067 | }, 3068 | "thickness_factor": 1 3069 | } 3070 | ], 3071 | "_graph_layout": { 3072 | "algorithm": "organic", 3073 | "options": {} 3074 | }, 3075 | "_model_module_version": "^1.10.2", 3076 | "_nodes": [ 3077 | { 3078 | "color": "#2196F3", 3079 | "id": 1, 3080 | "label": "Keanu Reeves", 3081 | "parentId": 10, 3082 | "position": [ 3083 | 0, 3084 | 0 3085 | ], 3086 | "properties": { 3087 | "born": 1964, 3088 | "label": "Person", 3089 | "name": "Keanu Reeves" 3090 | }, 3091 | "scale_factor": 1, 3092 | "size": [ 3093 | 100, 3094 | 100 3095 | ], 3096 | "styles": { 3097 | "shape": "rectangle" 3098 | }, 3099 | "type": "#2196F3" 3100 | }, 3101 | { 3102 | "color": "#4CAF50", 3103 | "id": 0, 3104 | "label": "Title:\nThe Matrix", 3105 | "parentId": "GroupNodemovies", 3106 | "position": [ 3107 | 0, 3108 | 0 3109 | ], 3110 | "properties": { 3111 | "label": "Movie", 3112 | "released": 1999, 3113 | "tagline": "Welcome to the Real World", 3114 | "title": "The Matrix", 3115 | "votes": 6345 3116 | }, 3117 | "scale_factor": 1, 3118 | "size": [ 3119 | 55, 3120 | 55 3121 | ], 3122 | "styles": { 3123 | "label_styles": { 3124 | "backgroundColor": "rgba(0,0,0,0.7)", 3125 | "color": "#FFFFFF", 3126 | "fontSize": 20, 3127 | "fontWeight": "lighter", 3128 | "maximumWidth": 130, 3129 | "position": "north", 3130 | "textAlignment": "center", 3131 | "wrapping": "word" 3132 | } 3133 | }, 3134 | "type": "#4CAF50" 3135 | }, 3136 | { 3137 | "color": "#2196F3", 3138 | "id": 2, 3139 | "label": "Carrie-Anne Moss", 3140 | "parentId": 10, 3141 | "position": [ 3142 | 0, 3143 | 0 3144 | ], 3145 | "properties": { 3146 | "born": 1967, 3147 | "label": "Person", 3148 | "name": "Carrie-Anne Moss" 3149 | }, 3150 | "scale_factor": 1, 3151 | "size": [ 3152 | 100, 3153 | 100 3154 | ], 3155 | "styles": { 3156 | "shape": "rectangle" 3157 | }, 3158 | "type": "#2196F3" 3159 | }, 3160 | { 3161 | "color": "#2196F3", 3162 | "id": 3, 3163 | "label": "Laurence Fishburne", 3164 | "parentId": 10, 3165 | "position": [ 3166 | 0, 3167 | 0 3168 | ], 3169 | "properties": { 3170 | "born": 1961, 3171 | "label": "Person", 3172 | "name": "Laurence Fishburne" 3173 | }, 3174 | "scale_factor": 1, 3175 | "size": [ 3176 | 100, 3177 | 100 3178 | ], 3179 | "styles": { 3180 | "shape": "rectangle" 3181 | }, 3182 | "type": "#2196F3" 3183 | }, 3184 | { 3185 | "color": "#2196F3", 3186 | "id": 4, 3187 | "label": "Hugo Weaving", 3188 | "parentId": 10, 3189 | "position": [ 3190 | 0, 3191 | 0 3192 | ], 3193 | "properties": { 3194 | "born": 1960, 3195 | "label": "Person", 3196 | "name": "Hugo Weaving" 3197 | }, 3198 | "scale_factor": 1, 3199 | "size": [ 3200 | 100, 3201 | 100 3202 | ], 3203 | "styles": { 3204 | "shape": "rectangle" 3205 | }, 3206 | "type": "#2196F3" 3207 | }, 3208 | { 3209 | "color": "#2196F3", 3210 | "id": 5, 3211 | "label": "Lilly Wachowski", 3212 | "parentId": "GroupNodepeople", 3213 | "position": [ 3214 | 0, 3215 | 0 3216 | ], 3217 | "properties": { 3218 | "born": 1967, 3219 | "label": "Person", 3220 | "name": "Lilly Wachowski" 3221 | }, 3222 | "scale_factor": 1, 3223 | "size": [ 3224 | 100, 3225 | 100 3226 | ], 3227 | "styles": { 3228 | "shape": "rectangle" 3229 | }, 3230 | "type": "#2196F3" 3231 | }, 3232 | { 3233 | "color": "#2196F3", 3234 | "id": 6, 3235 | "label": "Lana Wachowski", 3236 | "parentId": "GroupNodepeople", 3237 | "position": [ 3238 | 0, 3239 | 0 3240 | ], 3241 | "properties": { 3242 | "born": 1965, 3243 | "label": "Person", 3244 | "name": "Lana Wachowski" 3245 | }, 3246 | "scale_factor": 1, 3247 | "size": [ 3248 | 100, 3249 | 100 3250 | ], 3251 | "styles": { 3252 | "shape": "rectangle" 3253 | }, 3254 | "type": "#2196F3" 3255 | }, 3256 | { 3257 | "color": "#2196F3", 3258 | "id": 7, 3259 | "label": "Joel Silver", 3260 | "parentId": "GroupNodepeople", 3261 | "position": [ 3262 | 0, 3263 | 0 3264 | ], 3265 | "properties": { 3266 | "born": 1952, 3267 | "label": "Person", 3268 | "name": "Joel Silver" 3269 | }, 3270 | "scale_factor": 1, 3271 | "size": [ 3272 | 100, 3273 | 100 3274 | ], 3275 | "styles": { 3276 | "shape": "rectangle" 3277 | }, 3278 | "type": "#2196F3" 3279 | }, 3280 | { 3281 | "color": "#2196F3", 3282 | "id": 8, 3283 | "label": "Emil Eifrem", 3284 | "parentId": 0, 3285 | "position": [ 3286 | 0, 3287 | 0 3288 | ], 3289 | "properties": { 3290 | "born": 1978, 3291 | "label": "Person", 3292 | "name": "Emil Eifrem" 3293 | }, 3294 | "scale_factor": 1, 3295 | "size": [ 3296 | 100, 3297 | 100 3298 | ], 3299 | "styles": { 3300 | "shape": "rectangle" 3301 | }, 3302 | "type": "#2196F3" 3303 | }, 3304 | { 3305 | "color": "#4CAF50", 3306 | "id": 9, 3307 | "label": "Title:\nThe Matrix Reloaded", 3308 | "parentId": "GroupNodemovies", 3309 | "position": [ 3310 | 0, 3311 | 0 3312 | ], 3313 | "properties": { 3314 | "label": "Movie", 3315 | "released": 2003, 3316 | "tagline": "Free your mind", 3317 | "title": "The Matrix Reloaded", 3318 | "votes": 1841 3319 | }, 3320 | "scale_factor": 1, 3321 | "size": [ 3322 | 55, 3323 | 55 3324 | ], 3325 | "styles": { 3326 | "label_styles": { 3327 | "backgroundColor": "rgba(0,0,0,0.7)", 3328 | "color": "#FFFFFF", 3329 | "fontSize": 20, 3330 | "fontWeight": "lighter", 3331 | "maximumWidth": 130, 3332 | "position": "north", 3333 | "textAlignment": "center", 3334 | "wrapping": "word" 3335 | } 3336 | }, 3337 | "type": "#4CAF50" 3338 | }, 3339 | { 3340 | "color": "#4CAF50", 3341 | "id": 10, 3342 | "label": "Title:\nThe Matrix Revolutions", 3343 | "parentId": "GroupNodemovies", 3344 | "position": [ 3345 | 0, 3346 | 0 3347 | ], 3348 | "properties": { 3349 | "label": "Movie", 3350 | "released": 2003, 3351 | "tagline": "Everything that has a beginning has an end", 3352 | "title": "The Matrix Revolutions", 3353 | "votes": 1534 3354 | }, 3355 | "scale_factor": 1, 3356 | "size": [ 3357 | 55, 3358 | 55 3359 | ], 3360 | "styles": { 3361 | "label_styles": { 3362 | "backgroundColor": "rgba(0,0,0,0.7)", 3363 | "color": "#FFFFFF", 3364 | "fontSize": 20, 3365 | "fontWeight": "lighter", 3366 | "maximumWidth": 130, 3367 | "position": "north", 3368 | "textAlignment": "center", 3369 | "wrapping": "word" 3370 | } 3371 | }, 3372 | "type": "#4CAF50" 3373 | }, 3374 | { 3375 | "color": "#cca9ff", 3376 | "id": "GroupNodepeople", 3377 | "label": "people", 3378 | "position": [ 3379 | 0, 3380 | 0 3381 | ], 3382 | "properties": { 3383 | "label": "people" 3384 | }, 3385 | "scale_factor": 1, 3386 | "size": [ 3387 | 55, 3388 | 55 3389 | ], 3390 | "styles": {}, 3391 | "type": "#cca9ff" 3392 | }, 3393 | { 3394 | "color": "#F44336", 3395 | "id": "GroupNodemovies", 3396 | "label": "movies", 3397 | "position": [ 3398 | 0, 3399 | 0 3400 | ], 3401 | "properties": { 3402 | "label": "movies" 3403 | }, 3404 | "scale_factor": 1, 3405 | "size": [ 3406 | 55, 3407 | 55 3408 | ], 3409 | "styles": {}, 3410 | "type": "#F44336" 3411 | } 3412 | ], 3413 | "_overview": { 3414 | "enabled": null, 3415 | "overview_set": false 3416 | }, 3417 | "_selected_graph": [ 3418 | [], 3419 | [] 3420 | ], 3421 | "_sidebar": { 3422 | "enabled": false, 3423 | "start_with": "About" 3424 | }, 3425 | "_view_module_version": "^1.10.2", 3426 | "layout": "IPY_MODEL_5fd3993005a24254b3a3d6b0ee922944" 3427 | } 3428 | }, 3429 | "d5976e6a66da45828c79552aad4df578": { 3430 | "model_module": "@jupyter-widgets/base", 3431 | "model_module_version": "2.0.0", 3432 | "model_name": "LayoutModel", 3433 | "state": { 3434 | "height": "630px", 3435 | "width": "100%" 3436 | } 3437 | }, 3438 | "d59c8897feff427aaf6f106244f5258c": { 3439 | "model_module": "@jupyter-widgets/base", 3440 | "model_module_version": "2.0.0", 3441 | "model_name": "LayoutModel", 3442 | "state": { 3443 | "height": "500px", 3444 | "width": "100%" 3445 | } 3446 | }, 3447 | "dbc205b3693047f4832f11957c0ede1e": { 3448 | "model_module": "@jupyter-widgets/base", 3449 | "model_module_version": "2.0.0", 3450 | "model_name": "LayoutModel", 3451 | "state": { 3452 | "height": "630px", 3453 | "width": "100%" 3454 | } 3455 | }, 3456 | "df8c3d8d361541ab919ea476b8e66e3d": { 3457 | "model_module": "yfiles-jupyter-graphs", 3458 | "model_module_version": "^1.10.2", 3459 | "model_name": "GraphModel", 3460 | "state": { 3461 | "_context_pane_mapping": [ 3462 | { 3463 | "id": "Neighborhood", 3464 | "title": "Neighborhood" 3465 | }, 3466 | { 3467 | "id": "Data", 3468 | "title": "Data" 3469 | }, 3470 | { 3471 | "id": "Search", 3472 | "title": "Search" 3473 | }, 3474 | { 3475 | "id": "About", 3476 | "title": "About" 3477 | } 3478 | ], 3479 | "_data_importer": "neo4j", 3480 | "_directed": true, 3481 | "_edges": [ 3482 | { 3483 | "color": "#AC94F4", 3484 | "directed": true, 3485 | "end": 0, 3486 | "id": 6, 3487 | "label": "produced", 3488 | "properties": { 3489 | "label": "PRODUCED" 3490 | }, 3491 | "start": 7, 3492 | "styles": { 3493 | "label_styles": { 3494 | "fontWeight": "bolder" 3495 | } 3496 | }, 3497 | "thickness_factor": 1 3498 | }, 3499 | { 3500 | "color": "blue", 3501 | "directed": true, 3502 | "end": 0, 3503 | "id": 5, 3504 | "label": "DIRECTED", 3505 | "properties": { 3506 | "label": "DIRECTED" 3507 | }, 3508 | "start": 6, 3509 | "styles": { 3510 | "dashStyle": "dot" 3511 | }, 3512 | "thickness_factor": 1 3513 | }, 3514 | { 3515 | "color": "blue", 3516 | "directed": true, 3517 | "end": 0, 3518 | "id": 4, 3519 | "label": "DIRECTED", 3520 | "properties": { 3521 | "label": "DIRECTED" 3522 | }, 3523 | "start": 5, 3524 | "styles": { 3525 | "dashStyle": "dot" 3526 | }, 3527 | "thickness_factor": 1 3528 | } 3529 | ], 3530 | "_graph_layout": { 3531 | "algorithm": "organic", 3532 | "options": {} 3533 | }, 3534 | "_model_module_version": "^1.10.2", 3535 | "_nodes": [ 3536 | { 3537 | "color": "#2196F3", 3538 | "id": 8, 3539 | "label": "Emil Eifrem", 3540 | "parentId": 0, 3541 | "position": [ 3542 | 0, 3543 | 0 3544 | ], 3545 | "properties": { 3546 | "born": 1978, 3547 | "label": "Person", 3548 | "name": "Emil Eifrem" 3549 | }, 3550 | "scale_factor": 1, 3551 | "size": [ 3552 | 100, 3553 | 100 3554 | ], 3555 | "styles": { 3556 | "shape": "rectangle" 3557 | }, 3558 | "type": "#2196F3" 3559 | }, 3560 | { 3561 | "color": "#4CAF50", 3562 | "id": 0, 3563 | "label": "Title:\nThe Matrix", 3564 | "parentId": "GroupNodemovies", 3565 | "position": [ 3566 | 0, 3567 | 0 3568 | ], 3569 | "properties": { 3570 | "label": "Movie", 3571 | "released": 1999, 3572 | "tagline": "Welcome to the Real World", 3573 | "title": "The Matrix", 3574 | "votes": 6345 3575 | }, 3576 | "scale_factor": 1, 3577 | "size": [ 3578 | 55, 3579 | 55 3580 | ], 3581 | "styles": { 3582 | "label_styles": { 3583 | "backgroundColor": "rgba(0,0,0,0.7)", 3584 | "color": "#FFFFFF", 3585 | "fontSize": 20, 3586 | "fontWeight": "lighter", 3587 | "maximumWidth": 130, 3588 | "position": "north", 3589 | "textAlignment": "center", 3590 | "wrapping": "word" 3591 | } 3592 | }, 3593 | "type": "#4CAF50" 3594 | }, 3595 | { 3596 | "color": "#2196F3", 3597 | "id": 7, 3598 | "label": "Joel Silver", 3599 | "parentId": "GroupNodepeople", 3600 | "position": [ 3601 | 0, 3602 | 0 3603 | ], 3604 | "properties": { 3605 | "born": 1952, 3606 | "label": "Person", 3607 | "name": "Joel Silver" 3608 | }, 3609 | "scale_factor": 1, 3610 | "size": [ 3611 | 100, 3612 | 100 3613 | ], 3614 | "styles": { 3615 | "shape": "rectangle" 3616 | }, 3617 | "type": "#2196F3" 3618 | }, 3619 | { 3620 | "color": "#2196F3", 3621 | "id": 6, 3622 | "label": "Lana Wachowski", 3623 | "parentId": "GroupNodepeople", 3624 | "position": [ 3625 | 0, 3626 | 0 3627 | ], 3628 | "properties": { 3629 | "born": 1965, 3630 | "label": "Person", 3631 | "name": "Lana Wachowski" 3632 | }, 3633 | "scale_factor": 1, 3634 | "size": [ 3635 | 100, 3636 | 100 3637 | ], 3638 | "styles": { 3639 | "shape": "rectangle" 3640 | }, 3641 | "type": "#2196F3" 3642 | }, 3643 | { 3644 | "color": "#2196F3", 3645 | "id": 5, 3646 | "label": "Lilly Wachowski", 3647 | "parentId": "GroupNodepeople", 3648 | "position": [ 3649 | 0, 3650 | 0 3651 | ], 3652 | "properties": { 3653 | "born": 1967, 3654 | "label": "Person", 3655 | "name": "Lilly Wachowski" 3656 | }, 3657 | "scale_factor": 1, 3658 | "size": [ 3659 | 100, 3660 | 100 3661 | ], 3662 | "styles": { 3663 | "shape": "rectangle" 3664 | }, 3665 | "type": "#2196F3" 3666 | }, 3667 | { 3668 | "color": "#2196F3", 3669 | "id": 4, 3670 | "label": "Hugo Weaving", 3671 | "parentId": 0, 3672 | "position": [ 3673 | 0, 3674 | 0 3675 | ], 3676 | "properties": { 3677 | "born": 1960, 3678 | "label": "Person", 3679 | "name": "Hugo Weaving" 3680 | }, 3681 | "scale_factor": 1, 3682 | "size": [ 3683 | 100, 3684 | 100 3685 | ], 3686 | "styles": { 3687 | "shape": "rectangle" 3688 | }, 3689 | "type": "#2196F3" 3690 | }, 3691 | { 3692 | "color": "#2196F3", 3693 | "id": 3, 3694 | "label": "Laurence Fishburne", 3695 | "parentId": 0, 3696 | "position": [ 3697 | 0, 3698 | 0 3699 | ], 3700 | "properties": { 3701 | "born": 1961, 3702 | "label": "Person", 3703 | "name": "Laurence Fishburne" 3704 | }, 3705 | "scale_factor": 1, 3706 | "size": [ 3707 | 100, 3708 | 100 3709 | ], 3710 | "styles": { 3711 | "shape": "rectangle" 3712 | }, 3713 | "type": "#2196F3" 3714 | }, 3715 | { 3716 | "color": "#2196F3", 3717 | "id": 2, 3718 | "label": "Carrie-Anne Moss", 3719 | "parentId": 0, 3720 | "position": [ 3721 | 0, 3722 | 0 3723 | ], 3724 | "properties": { 3725 | "born": 1967, 3726 | "label": "Person", 3727 | "name": "Carrie-Anne Moss" 3728 | }, 3729 | "scale_factor": 1, 3730 | "size": [ 3731 | 100, 3732 | 100 3733 | ], 3734 | "styles": { 3735 | "shape": "rectangle" 3736 | }, 3737 | "type": "#2196F3" 3738 | }, 3739 | { 3740 | "color": "#2196F3", 3741 | "id": 1, 3742 | "label": "Keanu Reeves", 3743 | "parentId": 0, 3744 | "position": [ 3745 | 0, 3746 | 0 3747 | ], 3748 | "properties": { 3749 | "born": 1964, 3750 | "label": "Person", 3751 | "name": "Keanu Reeves" 3752 | }, 3753 | "scale_factor": 1, 3754 | "size": [ 3755 | 100, 3756 | 100 3757 | ], 3758 | "styles": { 3759 | "shape": "rectangle" 3760 | }, 3761 | "type": "#2196F3" 3762 | }, 3763 | { 3764 | "color": "#cca9ff", 3765 | "id": "GroupNodepeople", 3766 | "label": "people", 3767 | "position": [ 3768 | 0, 3769 | 0 3770 | ], 3771 | "properties": { 3772 | "label": "people" 3773 | }, 3774 | "scale_factor": 1, 3775 | "size": [ 3776 | 55, 3777 | 55 3778 | ], 3779 | "styles": {}, 3780 | "type": "#cca9ff" 3781 | }, 3782 | { 3783 | "color": "#F44336", 3784 | "id": "GroupNodemovies", 3785 | "label": "movies", 3786 | "position": [ 3787 | 0, 3788 | 0 3789 | ], 3790 | "properties": { 3791 | "label": "movies" 3792 | }, 3793 | "scale_factor": 1, 3794 | "size": [ 3795 | 55, 3796 | 55 3797 | ], 3798 | "styles": {}, 3799 | "type": "#F44336" 3800 | } 3801 | ], 3802 | "_overview": { 3803 | "enabled": null, 3804 | "overview_set": false 3805 | }, 3806 | "_selected_graph": [ 3807 | [], 3808 | [] 3809 | ], 3810 | "_sidebar": { 3811 | "enabled": false, 3812 | "start_with": "About" 3813 | }, 3814 | "_view_module_version": "^1.10.2", 3815 | "layout": "IPY_MODEL_77f79c1038da486ebdf3db3693fa1df7" 3816 | } 3817 | }, 3818 | "e6099874e34449e1b898bc4e878bee7c": { 3819 | "model_module": "yfiles-jupyter-graphs", 3820 | "model_module_version": "^1.10.2", 3821 | "model_name": "GraphModel", 3822 | "state": { 3823 | "_context_pane_mapping": [ 3824 | { 3825 | "id": "Neighborhood", 3826 | "title": "Neighborhood" 3827 | }, 3828 | { 3829 | "id": "Data", 3830 | "title": "Data" 3831 | }, 3832 | { 3833 | "id": "Search", 3834 | "title": "Search" 3835 | }, 3836 | { 3837 | "id": "About", 3838 | "title": "About" 3839 | } 3840 | ], 3841 | "_data_importer": "neo4j", 3842 | "_directed": true, 3843 | "_edges": [ 3844 | { 3845 | "color": "blue", 3846 | "directed": true, 3847 | "end": 0, 3848 | "id": 4, 3849 | "label": "DIRECTED", 3850 | "properties": { 3851 | "label": "DIRECTED" 3852 | }, 3853 | "start": 5, 3854 | "styles": { 3855 | "dashStyle": "dot" 3856 | }, 3857 | "thickness_factor": 1 3858 | }, 3859 | { 3860 | "color": "blue", 3861 | "directed": true, 3862 | "end": 0, 3863 | "id": 5, 3864 | "label": "DIRECTED", 3865 | "properties": { 3866 | "label": "DIRECTED" 3867 | }, 3868 | "start": 6, 3869 | "styles": { 3870 | "dashStyle": "dot" 3871 | }, 3872 | "thickness_factor": 1 3873 | }, 3874 | { 3875 | "color": "#AC94F4", 3876 | "directed": true, 3877 | "end": 0, 3878 | "id": 6, 3879 | "label": "produced", 3880 | "properties": { 3881 | "label": "PRODUCED" 3882 | }, 3883 | "start": 7, 3884 | "styles": { 3885 | "label_styles": { 3886 | "fontSize": 16, 3887 | "fontWeight": "bolder" 3888 | } 3889 | }, 3890 | "thickness_factor": 1 3891 | }, 3892 | { 3893 | "color": "blue", 3894 | "directed": true, 3895 | "end": 9, 3896 | "id": 12, 3897 | "label": "DIRECTED", 3898 | "properties": { 3899 | "label": "DIRECTED" 3900 | }, 3901 | "start": 5, 3902 | "styles": { 3903 | "dashStyle": "dot" 3904 | }, 3905 | "thickness_factor": 1 3906 | }, 3907 | { 3908 | "color": "blue", 3909 | "directed": true, 3910 | "end": 9, 3911 | "id": 13, 3912 | "label": "DIRECTED", 3913 | "properties": { 3914 | "label": "DIRECTED" 3915 | }, 3916 | "start": 6, 3917 | "styles": { 3918 | "dashStyle": "dot" 3919 | }, 3920 | "thickness_factor": 1 3921 | }, 3922 | { 3923 | "color": "#AC94F4", 3924 | "directed": true, 3925 | "end": 9, 3926 | "id": 14, 3927 | "label": "produced", 3928 | "properties": { 3929 | "label": "PRODUCED" 3930 | }, 3931 | "start": 7, 3932 | "styles": { 3933 | "label_styles": { 3934 | "fontSize": 16, 3935 | "fontWeight": "bolder" 3936 | } 3937 | }, 3938 | "thickness_factor": 1 3939 | }, 3940 | { 3941 | "color": "blue", 3942 | "directed": true, 3943 | "end": 10, 3944 | "id": 19, 3945 | "label": "DIRECTED", 3946 | "properties": { 3947 | "label": "DIRECTED" 3948 | }, 3949 | "start": 5, 3950 | "styles": { 3951 | "dashStyle": "dot" 3952 | }, 3953 | "thickness_factor": 1 3954 | } 3955 | ], 3956 | "_graph_layout": { 3957 | "algorithm": "organic", 3958 | "options": {} 3959 | }, 3960 | "_model_module_version": "^1.10.2", 3961 | "_nodes": [ 3962 | { 3963 | "color": "#2196F3", 3964 | "id": 1, 3965 | "label": "Keanu Reeves", 3966 | "parentId": 10, 3967 | "position": [ 3968 | 0, 3969 | 0 3970 | ], 3971 | "properties": { 3972 | "born": 1964, 3973 | "label": "Person", 3974 | "name": "Keanu Reeves" 3975 | }, 3976 | "scale_factor": 1, 3977 | "size": [ 3978 | 100, 3979 | 100 3980 | ], 3981 | "styles": { 3982 | "shape": "rectangle" 3983 | }, 3984 | "type": "#2196F3" 3985 | }, 3986 | { 3987 | "color": "#4CAF50", 3988 | "id": 0, 3989 | "label": "Title:\nThe Matrix", 3990 | "parentId": "GroupNodemovies", 3991 | "position": [ 3992 | 0, 3993 | 0 3994 | ], 3995 | "properties": { 3996 | "label": "Movie", 3997 | "released": 1999, 3998 | "tagline": "Welcome to the Real World", 3999 | "title": "The Matrix", 4000 | "votes": 6345 4001 | }, 4002 | "scale_factor": 1, 4003 | "size": [ 4004 | 55, 4005 | 55 4006 | ], 4007 | "styles": { 4008 | "label_styles": { 4009 | "backgroundColor": "rgba(0,0,0,0.7)", 4010 | "color": "#FFFFFF", 4011 | "fontSize": 20, 4012 | "fontWeight": "lighter", 4013 | "maximumWidth": 130, 4014 | "position": "north", 4015 | "textAlignment": "center", 4016 | "wrapping": "word" 4017 | } 4018 | }, 4019 | "type": "#4CAF50" 4020 | }, 4021 | { 4022 | "color": "#2196F3", 4023 | "id": 2, 4024 | "label": "Carrie-Anne Moss", 4025 | "parentId": 10, 4026 | "position": [ 4027 | 0, 4028 | 0 4029 | ], 4030 | "properties": { 4031 | "born": 1967, 4032 | "label": "Person", 4033 | "name": "Carrie-Anne Moss" 4034 | }, 4035 | "scale_factor": 1, 4036 | "size": [ 4037 | 100, 4038 | 100 4039 | ], 4040 | "styles": { 4041 | "shape": "rectangle" 4042 | }, 4043 | "type": "#2196F3" 4044 | }, 4045 | { 4046 | "color": "#2196F3", 4047 | "id": 3, 4048 | "label": "Laurence Fishburne", 4049 | "parentId": 10, 4050 | "position": [ 4051 | 0, 4052 | 0 4053 | ], 4054 | "properties": { 4055 | "born": 1961, 4056 | "label": "Person", 4057 | "name": "Laurence Fishburne" 4058 | }, 4059 | "scale_factor": 1, 4060 | "size": [ 4061 | 100, 4062 | 100 4063 | ], 4064 | "styles": { 4065 | "shape": "rectangle" 4066 | }, 4067 | "type": "#2196F3" 4068 | }, 4069 | { 4070 | "color": "#2196F3", 4071 | "id": 4, 4072 | "label": "Hugo Weaving", 4073 | "parentId": 10, 4074 | "position": [ 4075 | 0, 4076 | 0 4077 | ], 4078 | "properties": { 4079 | "born": 1960, 4080 | "label": "Person", 4081 | "name": "Hugo Weaving" 4082 | }, 4083 | "scale_factor": 1, 4084 | "size": [ 4085 | 100, 4086 | 100 4087 | ], 4088 | "styles": { 4089 | "shape": "rectangle" 4090 | }, 4091 | "type": "#2196F3" 4092 | }, 4093 | { 4094 | "color": "#2196F3", 4095 | "id": 5, 4096 | "label": "Lilly Wachowski", 4097 | "parentId": "GroupNodepeople", 4098 | "position": [ 4099 | 0, 4100 | 0 4101 | ], 4102 | "properties": { 4103 | "born": 1967, 4104 | "label": "Person", 4105 | "name": "Lilly Wachowski" 4106 | }, 4107 | "scale_factor": 1, 4108 | "size": [ 4109 | 100, 4110 | 100 4111 | ], 4112 | "styles": { 4113 | "shape": "rectangle" 4114 | }, 4115 | "type": "#2196F3" 4116 | }, 4117 | { 4118 | "color": "#2196F3", 4119 | "id": 6, 4120 | "label": "Lana Wachowski", 4121 | "parentId": "GroupNodepeople", 4122 | "position": [ 4123 | 0, 4124 | 0 4125 | ], 4126 | "properties": { 4127 | "born": 1965, 4128 | "label": "Person", 4129 | "name": "Lana Wachowski" 4130 | }, 4131 | "scale_factor": 1, 4132 | "size": [ 4133 | 100, 4134 | 100 4135 | ], 4136 | "styles": { 4137 | "shape": "rectangle" 4138 | }, 4139 | "type": "#2196F3" 4140 | }, 4141 | { 4142 | "color": "#2196F3", 4143 | "id": 7, 4144 | "label": "Joel Silver", 4145 | "parentId": "GroupNodepeople", 4146 | "position": [ 4147 | 0, 4148 | 0 4149 | ], 4150 | "properties": { 4151 | "born": 1952, 4152 | "label": "Person", 4153 | "name": "Joel Silver" 4154 | }, 4155 | "scale_factor": 1, 4156 | "size": [ 4157 | 100, 4158 | 100 4159 | ], 4160 | "styles": { 4161 | "shape": "rectangle" 4162 | }, 4163 | "type": "#2196F3" 4164 | }, 4165 | { 4166 | "color": "#2196F3", 4167 | "id": 8, 4168 | "label": "Emil Eifrem", 4169 | "parentId": 0, 4170 | "position": [ 4171 | 0, 4172 | 0 4173 | ], 4174 | "properties": { 4175 | "born": 1978, 4176 | "label": "Person", 4177 | "name": "Emil Eifrem" 4178 | }, 4179 | "scale_factor": 1, 4180 | "size": [ 4181 | 100, 4182 | 100 4183 | ], 4184 | "styles": { 4185 | "shape": "rectangle" 4186 | }, 4187 | "type": "#2196F3" 4188 | }, 4189 | { 4190 | "color": "#4CAF50", 4191 | "id": 9, 4192 | "label": "Title:\nThe Matrix Reloaded", 4193 | "parentId": "GroupNodemovies", 4194 | "position": [ 4195 | 0, 4196 | 0 4197 | ], 4198 | "properties": { 4199 | "label": "Movie", 4200 | "released": 2003, 4201 | "tagline": "Free your mind", 4202 | "title": "The Matrix Reloaded", 4203 | "votes": 1841 4204 | }, 4205 | "scale_factor": 1, 4206 | "size": [ 4207 | 55, 4208 | 55 4209 | ], 4210 | "styles": { 4211 | "label_styles": { 4212 | "backgroundColor": "rgba(0,0,0,0.7)", 4213 | "color": "#FFFFFF", 4214 | "fontSize": 20, 4215 | "fontWeight": "lighter", 4216 | "maximumWidth": 130, 4217 | "position": "north", 4218 | "textAlignment": "center", 4219 | "wrapping": "word" 4220 | } 4221 | }, 4222 | "type": "#4CAF50" 4223 | }, 4224 | { 4225 | "color": "#4CAF50", 4226 | "id": 10, 4227 | "label": "Title:\nThe Matrix Revolutions", 4228 | "parentId": "GroupNodemovies", 4229 | "position": [ 4230 | 0, 4231 | 0 4232 | ], 4233 | "properties": { 4234 | "label": "Movie", 4235 | "released": 2003, 4236 | "tagline": "Everything that has a beginning has an end", 4237 | "title": "The Matrix Revolutions", 4238 | "votes": 1534 4239 | }, 4240 | "scale_factor": 1, 4241 | "size": [ 4242 | 55, 4243 | 55 4244 | ], 4245 | "styles": { 4246 | "label_styles": { 4247 | "backgroundColor": "rgba(0,0,0,0.7)", 4248 | "color": "#FFFFFF", 4249 | "fontSize": 20, 4250 | "fontWeight": "lighter", 4251 | "maximumWidth": 130, 4252 | "position": "north", 4253 | "textAlignment": "center", 4254 | "wrapping": "word" 4255 | } 4256 | }, 4257 | "type": "#4CAF50" 4258 | }, 4259 | { 4260 | "color": "#cca9ff", 4261 | "id": "GroupNodepeople", 4262 | "label": "people", 4263 | "position": [ 4264 | 0, 4265 | 0 4266 | ], 4267 | "properties": { 4268 | "label": "people" 4269 | }, 4270 | "scale_factor": 1, 4271 | "size": [ 4272 | 55, 4273 | 55 4274 | ], 4275 | "styles": {}, 4276 | "type": "#cca9ff" 4277 | }, 4278 | { 4279 | "color": "#F44336", 4280 | "id": "GroupNodemovies", 4281 | "label": "movies", 4282 | "position": [ 4283 | 0, 4284 | 0 4285 | ], 4286 | "properties": { 4287 | "label": "movies" 4288 | }, 4289 | "scale_factor": 1, 4290 | "size": [ 4291 | 55, 4292 | 55 4293 | ], 4294 | "styles": {}, 4295 | "type": "#F44336" 4296 | } 4297 | ], 4298 | "_overview": { 4299 | "enabled": null, 4300 | "overview_set": false 4301 | }, 4302 | "_selected_graph": [ 4303 | [], 4304 | [] 4305 | ], 4306 | "_sidebar": { 4307 | "enabled": false, 4308 | "start_with": "About" 4309 | }, 4310 | "_view_module_version": "^1.10.2", 4311 | "layout": "IPY_MODEL_b75d05a06bf5430eb7bcd20497262a02" 4312 | } 4313 | }, 4314 | "ee5c26d1e68147d6a0d613aaf7c9ae0e": { 4315 | "model_module": "@jupyter-widgets/base", 4316 | "model_module_version": "2.0.0", 4317 | "model_name": "LayoutModel", 4318 | "state": { 4319 | "height": "500px", 4320 | "width": "100%" 4321 | } 4322 | }, 4323 | "f3a094e36f354e40827d35b439895f5a": { 4324 | "model_module": "yfiles-jupyter-graphs", 4325 | "model_module_version": "^1.10.2", 4326 | "model_name": "GraphModel", 4327 | "state": { 4328 | "_context_pane_mapping": [ 4329 | { 4330 | "id": "Neighborhood", 4331 | "title": "Neighborhood" 4332 | }, 4333 | { 4334 | "id": "Data", 4335 | "title": "Data" 4336 | }, 4337 | { 4338 | "id": "Search", 4339 | "title": "Search" 4340 | }, 4341 | { 4342 | "id": "About", 4343 | "title": "About" 4344 | } 4345 | ], 4346 | "_directed": false, 4347 | "_model_module_version": "^1.10.2", 4348 | "_overview": { 4349 | "enabled": null, 4350 | "overview_set": false 4351 | }, 4352 | "_sidebar": { 4353 | "enabled": false, 4354 | "start_with": null 4355 | }, 4356 | "_view_module_version": "^1.10.2", 4357 | "layout": "IPY_MODEL_ee5c26d1e68147d6a0d613aaf7c9ae0e" 4358 | } 4359 | }, 4360 | "fff11c7266aa4e2fa93490fad39be98a": { 4361 | "model_module": "yfiles-jupyter-graphs", 4362 | "model_module_version": "^1.10.2", 4363 | "model_name": "GraphModel", 4364 | "state": { 4365 | "_context_pane_mapping": [ 4366 | { 4367 | "id": "Neighborhood", 4368 | "title": "Neighborhood" 4369 | }, 4370 | { 4371 | "id": "Data", 4372 | "title": "Data" 4373 | }, 4374 | { 4375 | "id": "Search", 4376 | "title": "Search" 4377 | }, 4378 | { 4379 | "id": "About", 4380 | "title": "About" 4381 | } 4382 | ], 4383 | "_directed": false, 4384 | "_model_module_version": "^1.10.2", 4385 | "_overview": { 4386 | "enabled": null, 4387 | "overview_set": false 4388 | }, 4389 | "_sidebar": { 4390 | "enabled": false, 4391 | "start_with": null 4392 | }, 4393 | "_view_module_version": "^1.10.2", 4394 | "layout": "IPY_MODEL_34bbd98495ca4f32aae4dbb34758f654" 4395 | } 4396 | } 4397 | }, 4398 | "version_major": 2, 4399 | "version_minor": 0 4400 | } 4401 | } 4402 | }, 4403 | "nbformat": 4, 4404 | "nbformat_minor": 5 4405 | } 4406 | -------------------------------------------------------------------------------- /examples/feature_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "8778641ccdd52ee5", 6 | "metadata": {}, 7 | "source": [ 8 | "# Features \"Open\n", 9 | "\n", 10 | "This notebook showcases some of the various features of `yfiles-jupyter-graphs-for-neo4j`. \n", 11 | "\n", 12 | "For a detailed description for the different mappings, check out the widget [documentation](https://yworks.github.io/yfiles-jupyter-graphs/)\n" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "id": "547d100c-0e8c-4600-875d-33877fbea626", 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "%pip install yfiles_jupyter_graphs_for_neo4j --quiet\n", 23 | "%pip install neo4j --quiet" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "id": "698b0bf0-118e-4f23-95b5-a8f1c7b2774f", 29 | "metadata": {}, 30 | "source": [ 31 | "You can also open this notebook in Google Colab when Google Colab's custom widget manager is enabled:" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": null, 37 | "id": "91c4e84f-a1b5-43c2-ad7f-80581e3ae26a", 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "try:\n", 42 | " import google.colab\n", 43 | " from google.colab import output\n", 44 | " output.enable_custom_widget_manager()\n", 45 | "except:\n", 46 | " pass" 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "id": "da7913db-4807-4631-a82c-a09ab6999383", 52 | "metadata": {}, 53 | "source": [ 54 | "\"Open" 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "id": "4f84e6a7-616d-400c-a297-c9d6c67932b9", 60 | "metadata": {}, 61 | "source": [ 62 | "## Connect to the database" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "id": "1b30c433-5541-4bb5-8dc6-631987280e5f", 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [ 72 | "from yfiles_jupyter_graphs_for_neo4j import Neo4jGraphWidget\n", 73 | "from neo4j import GraphDatabase\n", 74 | "\n", 75 | "NEO4J_URI = \"neo4j+ssc://demo.neo4jlabs.com\" \n", 76 | "NEO4J_USERNAME = \"fincen\"\n", 77 | "NEO4J_PASSWORD = \"fincen\"\n", 78 | "driver = GraphDatabase.driver(uri = NEO4J_URI, auth = (NEO4J_USERNAME, NEO4J_PASSWORD), database = \"fincen\")\n", 79 | "\n", 80 | "g = Neo4jGraphWidget(driver)" 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "id": "2c8fb293-c638-4a5a-b321-eeb4907b6432", 86 | "metadata": {}, 87 | "source": [ 88 | "## Use heat mapping" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": null, 94 | "id": "ebdabe1b-6503-49a7-8039-8d469b4caeea", 95 | "metadata": {}, 96 | "outputs": [], 97 | "source": [ 98 | "max_amount = 120000000\n", 99 | "min_amount = 50000\n", 100 | "\n", 101 | "def heat_mapping(element):\n", 102 | " if \"amount\" in element[\"properties\"]:\n", 103 | " amount = element[\"properties\"][\"amount\"]\n", 104 | " normalized_value = (amount - min_amount) / (max_amount - min_amount)\n", 105 | " transformed_value = -1 * (1 - normalized_value) ** 2 + 1\n", 106 | " return max(0, min(1, transformed_value))\n", 107 | "\n", 108 | "g.add_node_configuration(\"Filing\", heat=heat_mapping)\n", 109 | "\n", 110 | "g.show_cypher(\"MATCH (s)-[r]->(t) RETURN s,r,t LIMIT 25\")" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "id": "41002892-a638-4544-842b-1881287d04e0", 116 | "metadata": {}, 117 | "source": [ 118 | "## Visualize geospatial data" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "id": "3f9de7f7-bacc-4c5b-989e-ed4211584725", 125 | "metadata": {}, 126 | "outputs": [], 127 | "source": [ 128 | "def node_coordinate_mapping(node):\n", 129 | " return (node[\"properties\"][\"location\"][\"y\"], node[\"properties\"][\"location\"][\"x\"]) if \"location\" in node[\"properties\"].keys() else None\n", 130 | "\n", 131 | "def filing_coordinate_mapping(node):\n", 132 | " return (node[\"properties\"][\"beneficiary_lat\"], (node[\"properties\"][\"beneficiary_lng\"])) if \"beneficiary_lat\" in node[\"properties\"].keys() else None\n", 133 | "\n", 134 | "g.add_node_configuration([\"Country\", \"Entity\"], coordinate=node_coordinate_mapping)\n", 135 | "g.add_node_configuration(\"Filing\", coordinate=filing_coordinate_mapping)\n", 136 | "\n", 137 | "g.show_cypher(\"MATCH (s)-[r]->(t) RETURN s,r,t LIMIT 50\", layout=\"map\")" 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "id": "3879ccf9-4223-41bd-ae38-d4b726097413", 143 | "metadata": {}, 144 | "source": [ 145 | "## Configure item visualization" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": null, 151 | "id": "de1ca154-7735-476e-920b-d5b45b61a5ac", 152 | "metadata": {}, 153 | "outputs": [], 154 | "source": [ 155 | "\n", 156 | "g.add_relationship_configuration(\"CONCERNS\", thickness_factor= 0.5)\n", 157 | "g.add_relationship_configuration(\"FILED\", thickness_factor= 2)\n", 158 | "g.del_node_configuration(\"Entity\")\n", 159 | "g.add_node_configuration(\"Filing\", size= lambda node: (55 * (1 + heat_mapping(node)), 55 * (1 + heat_mapping(node))))\n", 160 | "\n", 161 | "g.show_cypher(\"MATCH (s)-[r]->(t) RETURN s,r,t LIMIT 25\")" 162 | ] 163 | }, 164 | { 165 | "cell_type": "markdown", 166 | "id": "7484387b-5b1e-429d-afa2-7df01bd3b4e2", 167 | "metadata": {}, 168 | "source": [ 169 | "## Configure grouping\n", 170 | "\n", 171 | "The widget supports various grouping options, see [grouping.ipynb](./grouping.ipynb) for more details." 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": null, 177 | "id": "c70e5897-c369-4132-8c30-5e7a2c712ed9", 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "# replaces \"COUNTRY\" relationships with a grouped hierarchy\n", 182 | "g.add_parent_relationship_configuration(\"COUNTRY\")\n", 183 | "\n", 184 | "g.show_cypher(\"MATCH (s)-[r]->(t) RETURN s,r,t LIMIT 25\")" 185 | ] 186 | }, 187 | { 188 | "cell_type": "markdown", 189 | "id": "58927c27-4a76-4835-bd6e-f0dd0f2fce04", 190 | "metadata": {}, 191 | "source": [ 192 | "## Configure node-to-cell mapping\n", 193 | "\n", 194 | "The node-to-cell mapping allows to fine-tune layout results by assigning preferred cell constraints for specific nodes.\n", 195 | "\n", 196 | "This is particularly useful to highlight specific items structurally aside from visual features like color or size." 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "id": "77d47bf2-5f34-4034-ad40-cb0c32a63fee", 203 | "metadata": {}, 204 | "outputs": [], 205 | "source": [ 206 | "g.del_parent_relationship_configuration(\"COUNTRY\")\n", 207 | "\n", 208 | "# highlight Bank of New York and China Construction Bank\n", 209 | "def get_cell_mapping(node):\n", 210 | " name = node[\"properties\"].get(\"name\")\n", 211 | " if name == \"The Bank of New York Mellon Corp.\" or name == \"China Construction Bank Corporation\":\n", 212 | " return (0,0)\n", 213 | " return (1,0)\n", 214 | "\n", 215 | "g.node_cell_mapping = get_cell_mapping\n", 216 | "\n", 217 | "# layouts interpret node-to-cell mapping differently\n", 218 | "g.show_cypher(\"MATCH (s)-[r]->(t) RETURN s,r,t LIMIT 25\", layout='hierarchic')" 219 | ] 220 | } 221 | ], 222 | "metadata": { 223 | "kernelspec": { 224 | "display_name": "Python 3 (ipykernel)", 225 | "language": "python", 226 | "name": "python3" 227 | }, 228 | "language_info": { 229 | "codemirror_mode": { 230 | "name": "ipython", 231 | "version": 3 232 | }, 233 | "file_extension": ".py", 234 | "mimetype": "text/x-python", 235 | "name": "python", 236 | "nbconvert_exporter": "python", 237 | "pygments_lexer": "ipython3", 238 | "version": "3.9.19" 239 | } 240 | }, 241 | "nbformat": 4, 242 | "nbformat_minor": 5 243 | } 244 | -------------------------------------------------------------------------------- /examples/selection_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "3e6c94df-2ee0-40ac-a0eb-97ddb6c18556", 6 | "metadata": {}, 7 | "source": [ 8 | "# Obtain selection from widget \"Open" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "7e709b40-0119-498d-879f-cc324b992320", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "%pip install yfiles_jupyter_graphs_for_neo4j --quiet\n", 19 | "%pip install neo4j --quiet\n", 20 | "from yfiles_jupyter_graphs_for_neo4j import Neo4jGraphWidget\n", 21 | "from neo4j import GraphDatabase" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "id": "56afeb89-1e79-4318-a000-67f80e1f4983", 27 | "metadata": {}, 28 | "source": [ 29 | "You can also open this notebook in Google Colab when Google Colab's custom widget manager is enabled:" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": null, 35 | "id": "4932f2d4-ad5e-49e8-a9f3-d72a74f21cd4", 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "try:\n", 40 | " import google.colab\n", 41 | " from google.colab import output\n", 42 | " output.enable_custom_widget_manager()\n", 43 | "except:\n", 44 | " pass" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "id": "1e7fcf65-a062-4d84-9888-11793857c4ab", 50 | "metadata": {}, 51 | "source": [ 52 | "## Connect with Neo4j driver" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "id": "6660c53f-3041-4931-919b-18789dcd0667", 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "NEO4J_URI = \"neo4j+ssc://demo.neo4jlabs.com\" \n", 63 | "NEO4J_USERNAME = \"movies\"\n", 64 | "NEO4J_PASSWORD = \"movies\"\n", 65 | "driver = GraphDatabase.driver(uri = NEO4J_URI, auth = (NEO4J_USERNAME, NEO4J_PASSWORD), database = 'movies')\n", 66 | "\n", 67 | "g = Neo4jGraphWidget(driver)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "id": "cf79e4f2-7a6b-4197-9f94-902f38c303bd", 73 | "metadata": {}, 74 | "source": [ 75 | "## Query database and interactively select nodes\n", 76 | "\n", 77 | "Select your nodes in the following diagram:" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "id": "a4c2eac8-3547-4db8-b72d-c0a0ed987b4b", 84 | "metadata": {}, 85 | "outputs": [], 86 | "source": [ 87 | "g.show_cypher(\"MATCH (s)-[r]->(t) RETURN s,r,t LIMIT 20\")" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "id": "8725e3b8-9d09-40a3-b728-fecb962a6aa4", 93 | "metadata": {}, 94 | "source": [ 95 | "## Use interactively selected nodes\n", 96 | "\n", 97 | "Recompile the following code cell to update your ids with your selection:" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "id": "4f56b914-4ad5-4cfe-ad9b-f8785a86c561", 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "ids = g.get_selected_node_ids()" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "id": "d6263574-7dfc-4977-95ed-e66677ceeb8c", 113 | "metadata": {}, 114 | "source": [ 115 | "Now, `ids` should contain a list of the currently selected nodes in the widget, otherwise make sure to (click-)select elements in the above diagram and recompile the `get_selected_node_ids()` cell:" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "id": "52292a3d-823b-47dd-a105-890f7a636079", 122 | "metadata": {}, 123 | "outputs": [], 124 | "source": [ 125 | "print(ids)" 126 | ] 127 | }, 128 | { 129 | "cell_type": "markdown", 130 | "id": "b7d427c8-a467-4a40-9094-a0fd62894d5f", 131 | "metadata": {}, 132 | "source": [ 133 | "Make sure not to restart the whole notebook as your selection is being reset as well." 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": null, 139 | "id": "f4e0de71-069d-4a74-98c1-3e100cdd05ed", 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "g.show_cypher(\"MATCH (s)-[r]->(t) WHERE ID(s) IN $ids RETURN s,r,t LIMIT 20\", ids=ids)" 144 | ] 145 | } 146 | ], 147 | "metadata": { 148 | "kernelspec": { 149 | "display_name": "Python 3 (ipykernel)", 150 | "language": "python", 151 | "name": "python3" 152 | }, 153 | "language_info": { 154 | "codemirror_mode": { 155 | "name": "ipython", 156 | "version": 3 157 | }, 158 | "file_extension": ".py", 159 | "mimetype": "text/x-python", 160 | "name": "python", 161 | "nbconvert_exporter": "python", 162 | "pygments_lexer": "ipython3", 163 | "version": "3.9.19" 164 | } 165 | }, 166 | "nbformat": 4, 167 | "nbformat_minor": 5 168 | } 169 | -------------------------------------------------------------------------------- /images/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yWorks/yfiles-jupyter-graphs-for-neo4j/f5a463dddb57aa778dbc0f0e30dafbf5ce2acb02/images/example.png -------------------------------------------------------------------------------- /images/features/grouping_feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yWorks/yfiles-jupyter-graphs-for-neo4j/f5a463dddb57aa778dbc0f0e30dafbf5ce2acb02/images/features/grouping_feature.png -------------------------------------------------------------------------------- /images/features/heat_feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yWorks/yfiles-jupyter-graphs-for-neo4j/f5a463dddb57aa778dbc0f0e30dafbf5ce2acb02/images/features/heat_feature.png -------------------------------------------------------------------------------- /images/features/map_feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yWorks/yfiles-jupyter-graphs-for-neo4j/f5a463dddb57aa778dbc0f0e30dafbf5ce2acb02/images/features/map_feature.png -------------------------------------------------------------------------------- /images/features/size_feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yWorks/yfiles-jupyter-graphs-for-neo4j/f5a463dddb57aa778dbc0f0e30dafbf5ce2acb02/images/features/size_feature.png -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "yfiles_jupyter_graphs_for_neo4j" 3 | version = "1.7.0" 4 | authors = [ 5 | {name = "yWorks Support Team", email= "yfileshtml@yworks.com"}, 6 | ] 7 | description = "A Neo4j graph visualization package that uses the yfiles-jupyter-graphs widget" 8 | readme = "README.md" 9 | requires-python = ">=3.8" 10 | classifiers = [ 11 | "Development Status :: 5 - Production/Stable", 12 | "Framework :: IPython", 13 | "Intended Audience :: Developers", 14 | "Intended Audience :: Science/Research", 15 | "Programming Language :: Python :: 3", 16 | "Operating System :: OS Independent", 17 | "Framework :: Jupyter", 18 | "Framework :: Jupyter :: JupyterLab", 19 | "Framework :: Jupyter :: JupyterLab :: 3", 20 | "Framework :: Jupyter :: JupyterLab :: Extensions", 21 | "Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt", 22 | ] 23 | license = {file = "LICENSE.md"} 24 | dependencies = [ 25 | "yfiles_jupyter_graphs>=1.10.0" 26 | ] 27 | 28 | [project.urls] 29 | License = "https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/blob/main/LICENSE.md" 30 | "Bug Tracker" = "https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/issues" 31 | Documentation = "https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j/" 32 | Repository = "https://github.com/yWorks/yfiles-jupyter-graphs-for-neo4j.git" 33 | 34 | [build-system] 35 | requires = ["setuptools>=61.0"] 36 | build-backend = "setuptools.build_meta" 37 | -------------------------------------------------------------------------------- /src/yfiles_jupyter_graphs_for_neo4j/Yfiles_Neo4j_Graphs.py: -------------------------------------------------------------------------------- 1 | """Jupyter (ipy)widget powered by yFiles. 2 | 3 | The main Neo4jGraphWidget class is defined in this module. 4 | 5 | """ 6 | from typing import Any, Callable, Dict, Union, Type, Optional, List 7 | from types import FunctionType, MethodType 8 | import inspect 9 | 10 | from yfiles_jupyter_graphs import GraphWidget 11 | 12 | # TODO maybe change to get dynamically when adding bindings 13 | 14 | POSSIBLE_NODE_BINDINGS = {'coordinate', 'color', 'size', 'type', 'styles', 'scale_factor', 'position', 15 | 'layout', 'property', 'label'} 16 | POSSIBLE_EDGE_BINDINGS = {'color', 'thickness_factor', 'styles', 'property', 'label'} 17 | NEO4J_LABEL_KEYS = ['name', 'title', 'text', 'description', 'caption', 'label'] 18 | 19 | class Neo4jGraphWidget: 20 | """ 21 | A yFiles Graphs for Jupyter widget that is tailored to visualize Cypher queries resolved against a Neo4j database. 22 | """ 23 | 24 | # noinspection PyShadowingBuiltins 25 | def __init__(self, driver: Optional[Any] = None, widget_layout: Optional[Any] = None, 26 | overview_enabled: Optional[bool] = None, context_start_with: Optional[str] = None, 27 | license: Optional[Dict] = None, 28 | autocomplete_relationships: Optional[bool] = False, layout: Optional[str] = 'organic'): 29 | """ 30 | Initializes a new instance of the Neo4jGraphWidget class. 31 | 32 | Args: 33 | driver (Optional[neo4j._sync.driver.Neo4jDriver]): The Neo4j driver to resolve the Cypher queries. 34 | widget_layout (Optional[ipywidgets.Layout]): Can be used to specify general widget appearance through css attributes. 35 | See ipywidgets documentation for the available keywords. 36 | overview_enabled (Optional[bool]): Whether the graph overview is enabled or not. 37 | context_start_with (Optional[str]): Start with a specific side-panel opened in the interactive widget. Starts with closed side-panel by default. 38 | license (Optional[Dict]): The widget works on common public domains without a specific license. 39 | For unknown domains, a license can be obtained by the creators of the widget. 40 | autocomplete_relationships (Optional[bool]): Whether missing relationships in the Cypher's return value are automatically added. 41 | layout (Optional[str]): Specifies the default automatic graph arrangement. Can be overwritten for each 42 | cypher separately. By default, an "organic" layout is used. Supported values are: 43 | - "circular" 44 | - "circular_straight_line" 45 | - "hierarchic" 46 | - "organic" 47 | - "interactive_organic" 48 | - "orthogonal" 49 | - "radial" 50 | - "tree" 51 | - "map" 52 | - "orthogonal_edge_router" 53 | - "organic_edge_router" 54 | """ 55 | 56 | self._widget = GraphWidget() 57 | self._driver = driver 58 | self._session = driver.session() 59 | self._license = license 60 | self._overview = overview_enabled 61 | self._layout = widget_layout 62 | self._context_start_with = context_start_with 63 | self.set_autocomplete_relationships(autocomplete_relationships) 64 | self._graph_layout = layout 65 | 66 | self._node_configurations = {} 67 | self._edge_configurations = {} 68 | self._parent_configurations = set() 69 | 70 | def set_driver(self, driver: Any) -> None: 71 | """ 72 | The Neo4j driver that is used to resolve the Cypher queries. A new session is created when set. 73 | 74 | Args: 75 | driver (neo4j._sync.driver.Neo4jDriver): The Neo4j driver to resolve the Cypher queries. 76 | 77 | Returns: 78 | None 79 | """ 80 | self._driver = driver 81 | self._session = driver.session() 82 | 83 | def get_driver(self) -> Any: 84 | """ 85 | Gets the configured Neo4j driver. 86 | 87 | Returns: 88 | neo4j._sync.driver.Neo4jDriver 89 | """ 90 | return self._driver 91 | 92 | def set_autocomplete_relationships(self, autocomplete_relationships: Union[bool, str, list[str]]) -> None: 93 | """ 94 | Sets the flag to enable or disable autocomplete for relationships. 95 | When autocomplete is enabled, relationships are automatically completed in the graph, 96 | similar to the behavior in Neo4j Browser. 97 | This can be set to True/False to enable or disable for all relationships, 98 | or a single relationship type or a list of relationship types to enable for specific relationships. 99 | 100 | Args: 101 | autocomplete_relationships (Union[bool, str, list[str]]): Enable autocompletion for relationships 102 | in general, or for a single type, or for multiple types. 103 | 104 | Returns: 105 | None 106 | """ 107 | if not isinstance(autocomplete_relationships, (bool, str, list)): 108 | raise ValueError("autocomplete_relationships must be a bool, a string, or a list of strings") 109 | if isinstance(autocomplete_relationships, str): 110 | self._autocomplete_relationships = [autocomplete_relationships] 111 | else: 112 | self._autocomplete_relationships = autocomplete_relationships 113 | 114 | def _is_autocomplete_enabled(self) -> bool: 115 | if isinstance(self._autocomplete_relationships, bool): 116 | return self._autocomplete_relationships 117 | return len(self._autocomplete_relationships) > 0 118 | 119 | def _get_relationship_types_expression(self) -> str: 120 | if isinstance(self._autocomplete_relationships, list) and len(self._autocomplete_relationships) > 0: 121 | return "AND type(rel) IN $relationship_types" 122 | return "" 123 | 124 | def show_cypher(self, cypher: str, layout: Optional[str] = None, **kwargs: Dict[str, Any]) -> None: 125 | """ 126 | Displays the given Cypher query as interactive graph. 127 | 128 | Args: 129 | cypher (str): The Cypher query whose result should be visualized as graph. 130 | layout (Optional[str]): The graph layout for this request. Overwrites the general default `layout` that was 131 | specified when initializing the class. Supported values are: 132 | - "circular" 133 | - "circular_straight_line" 134 | - "hierarchic" 135 | - "organic" 136 | - "interactive_organic" 137 | - "orthogonal" 138 | - "radial" 139 | - "tree" 140 | - "map" 141 | - "orthogonal_edge_router" 142 | - "organic_edge_router" 143 | **kwargs (Dict[str, Any]): Additional parameters that should be passed to the Cypher query. 144 | 145 | Returns: 146 | None 147 | 148 | Raises: 149 | Exception: If no driver was specified. 150 | """ 151 | if self._driver is not None: 152 | if self._is_autocomplete_enabled(): 153 | nodes = self._session.run(cypher, **kwargs).graph().nodes 154 | node_ids = [node.element_id for node in nodes] 155 | reltypes_expr = self._get_relationship_types_expression() 156 | cypher = f""" 157 | MATCH (n) WHERE elementId(n) IN $node_ids 158 | RETURN n as start, NULL as rel, NULL as end 159 | UNION ALL 160 | MATCH (n)-[rel]-(m) 161 | WHERE elementId(n) IN $node_ids 162 | AND elementId(m) IN $node_ids 163 | {reltypes_expr} 164 | RETURN n as start, rel, m as end 165 | """ 166 | kwargs = {"node_ids": node_ids} 167 | if reltypes_expr: 168 | kwargs["relationship_types"] = self._autocomplete_relationships 169 | widget = GraphWidget(overview_enabled=self._overview, context_start_with=self._context_start_with, 170 | widget_layout=self._layout, license=self._license, 171 | graph=self._session.run(cypher, **kwargs).graph()) 172 | self.__create_group_nodes(self._node_configurations, widget) 173 | self.__apply_node_mappings(widget) 174 | self.__apply_edge_mappings(widget) 175 | self.__apply_heat_mapping({**self._node_configurations, **self._edge_configurations}, widget) 176 | self.__apply_parent_mapping(widget) 177 | if layout is None: 178 | widget.set_graph_layout(self._graph_layout) 179 | else: 180 | widget.set_graph_layout(layout) 181 | 182 | widget.node_cell_mapping = self.node_cell_mapping 183 | 184 | self._widget = widget 185 | widget.show() 186 | else: 187 | raise Exception("no driver specified") 188 | 189 | @staticmethod 190 | def __get_neo4j_item_text(element: Dict) -> Union[str, None]: 191 | lowercase_element_props = {key.lower(): value for key, value in element.get('properties', {}).items()} 192 | for key in NEO4J_LABEL_KEYS: 193 | if key in lowercase_element_props: 194 | return str(lowercase_element_props[key]) 195 | return None 196 | 197 | @staticmethod 198 | def __configuration_mapper_factory(binding_key: str, configurations: Dict[str, Dict[str, str]], 199 | default_mapping: Callable) -> Callable[[int, Dict], Union[Dict, str]]: 200 | """ 201 | This is called once for each POSSIBLE_NODE_BINDINGS or POSSIBLE_EDGE_BINDINGS (as `binding_key` argument) and 202 | sets the returned mapping function for the `binding_key` on the core yFiles Graphs for Jupyter widget. 203 | 204 | Args: 205 | binding_key (str): One of POSSIBLE_NODE_BINDINGS or POSSIBLE_EDGE_BINDINGS 206 | configurations (Dict): All configured node or relationship configurations by the user, keyed by the node label or relationship type. 207 | For example, a dictionary built like: 208 | { 209 | "Movie": { "color": "red", ... }, 210 | "Person": { "color": "blue", ... }, 211 | "*": { "color": "gray", ... } 212 | } 213 | default_mapping (MethodType): A reference to the default binding of the yFiles Graphs for Jupyter core widget that should be used when the binding_key is not specified otherwise. 214 | 215 | Returns: 216 | FunctionType: A mapping function that can used in the yFiles Graphs for Jupyter core widget. 217 | """ 218 | 219 | def mapping(index: int, item: Dict) -> Union[Dict, str]: 220 | label = item["properties"]["label"] # yjg stores the neo4j node/relationship type in properties["label"] 221 | if ((label in configurations or '*' in configurations) 222 | and binding_key in configurations.get(label, configurations.get('*'))): 223 | type_configuration = configurations.get(label, configurations.get('*')) 224 | if binding_key == 'parent_configuration': 225 | # the binding may be a lambda that must be resolved first 226 | binding = type_configuration.get(binding_key) 227 | if callable(binding): 228 | binding = binding(item) 229 | # parent_configuration binding may either resolve to a dict or a string 230 | if isinstance(binding, dict): 231 | group_label = binding.get('text', '') 232 | else: 233 | group_label = binding 234 | result = 'GroupNode' + group_label 235 | # mapping 236 | elif callable(type_configuration[binding_key]): 237 | result = type_configuration[binding_key](item) 238 | # property name 239 | elif (not isinstance(type_configuration[binding_key], dict) and 240 | type_configuration[binding_key] in item["properties"]): 241 | result = item["properties"][type_configuration.get(binding_key)] 242 | # constant value 243 | else: 244 | result = type_configuration.get(binding_key) 245 | 246 | return result 247 | 248 | if binding_key == "label": 249 | return Neo4jGraphWidget.__get_neo4j_item_text(item) 250 | else: 251 | # call default mapping 252 | # some default mappings do not support "index" as first parameter 253 | parameters = inspect.signature(default_mapping).parameters 254 | if len(parameters) > 1 and parameters[list(parameters)[0]].annotation == int: 255 | return default_mapping(index, item) 256 | else: 257 | return default_mapping(item) 258 | 259 | return mapping 260 | 261 | def __apply_heat_mapping(self, configuration, widget: GraphWidget) -> None: 262 | setattr(widget, "_heat_mapping", 263 | Neo4jGraphWidget.__configuration_mapper_factory('heat', configuration, 264 | getattr(widget, 'default_heat_mapping'))) 265 | 266 | def __create_group_nodes(self, configurations, widget: GraphWidget) -> None: 267 | group_node_properties = set() 268 | group_node_values = set() 269 | key = 'parent_configuration' 270 | for node in widget.nodes: 271 | label = node['properties']['label'] 272 | if label in configurations and key in configurations.get(label): 273 | group_node = configurations.get(label).get(key) 274 | 275 | if callable(group_node): 276 | group_node = group_node(node) 277 | 278 | if isinstance(group_node, str): 279 | # string or property value 280 | if group_node in node["properties"]: 281 | group_node_properties.add(str(node["properties"][group_node])) 282 | else: 283 | group_node_values.add(group_node) 284 | else: 285 | # dictionary with values 286 | text = group_node.get('text', '') 287 | group_node_values.add(text) 288 | configuration = {k: v for k, v in group_node.items() if k != 'text'} 289 | self.add_node_configuration(text, **configuration) 290 | 291 | for group_label in group_node_properties.union(group_node_values): 292 | node = {'id': 'GroupNode' + group_label, 'properties': {'label': group_label}} 293 | widget.nodes = [*widget.nodes, node] 294 | 295 | def __apply_parent_mapping(self, widget: GraphWidget) -> None: 296 | node_to_parent = {} 297 | edge_ids_to_remove = set() 298 | for edge in widget.edges[:]: 299 | rel_type = edge["properties"]["label"] 300 | for (parent_type, is_reversed) in self._parent_configurations: 301 | if rel_type == parent_type: 302 | start = edge['start'] # child node id 303 | end = edge['end'] # parent node id 304 | if is_reversed: 305 | node_to_parent[end] = start 306 | else: 307 | node_to_parent[start] = end 308 | edge_ids_to_remove.add(edge['id']) 309 | break 310 | 311 | # use list comprehension to filter out the edges to automatically trigger model sync with the frontend 312 | widget.edges = [edge for edge in widget.edges if edge['id'] not in edge_ids_to_remove] 313 | current_parent_mapping = getattr(widget, '_node_parent_mapping') 314 | setattr(widget, "_node_parent_mapping", 315 | lambda index, node: node_to_parent.get(node['id'], current_parent_mapping(index, node))) 316 | 317 | def __apply_node_mappings(self, widget: GraphWidget) -> None: 318 | for key in POSSIBLE_NODE_BINDINGS: 319 | default_mapping = getattr(widget, f"default_node_{key}_mapping") 320 | setattr(widget, f"_node_{key}_mapping", 321 | Neo4jGraphWidget.__configuration_mapper_factory(key, self._node_configurations, default_mapping)) 322 | # manually set parent configuration 323 | setattr(widget, f"_node_parent_mapping", 324 | Neo4jGraphWidget.__configuration_mapper_factory('parent_configuration', 325 | self._node_configurations, lambda node: None)) 326 | 327 | def __apply_edge_mappings(self, widget: GraphWidget) -> None: 328 | for key in POSSIBLE_EDGE_BINDINGS: 329 | default_mapping = getattr(widget, f"default_edge_{key}_mapping") 330 | setattr(widget, f"_edge_{key}_mapping", 331 | Neo4jGraphWidget.__configuration_mapper_factory(key, self._edge_configurations, default_mapping)) 332 | 333 | def add_node_configuration(self, label: Union[str, list[str]], **kwargs: Dict[str, Any]) -> None: 334 | """ 335 | Adds a configuration object for the given node `label`(s). 336 | 337 | Args: 338 | label (Union[str, list[str]]): The node label(s) for which this configuration should be used. Supports `*` to address all labels. 339 | **kwargs (Dict[str, Any]): Visualization configuration for the given node label. The following arguments are supported: 340 | 341 | - `text` (Union[str, Callable]): The text to be displayed on the node. By default, the node's label is used. 342 | - `color` (Union[str, Callable]): A convenience color binding for the node (see also styles kwarg). 343 | - `size` (Union[str, Callable]): The size of the node. 344 | - `styles` (Union[Dict, Callable]): A dictionary that may contain the following attributes color, shape (one of 'ellipse', ' hexagon', 'hexagon2', 'octagon', 'pill', 'rectangle', 'round-rectangle' or 'triangle'), image. 345 | - `property` (Union[Dict, Callable]): Allows to specify additional properties on the node, which may be bound by other bindings. 346 | - `type` (Union[Dict, Callable]): Defines a specific "type" for the node which affects the automatic positioning of nodes (same "type"s are preferred to be placed next to each other). 347 | - `parent_configuration` (Union[str, Callable]): Configure grouping for this node label. 348 | 349 | Returns: 350 | None 351 | """ 352 | # this wrapper uses "text" as text binding in the graph 353 | # in contrast to "label" which is used in yfiles-jupyter-graphs 354 | text_binding = kwargs.pop("text", None) 355 | config = kwargs 356 | if text_binding is not None: 357 | config["label"] = text_binding 358 | 359 | cloned_config = {key: value for key, value in config.items()} 360 | if isinstance(label, list): 361 | for l in label: 362 | self._node_configurations[l] = cloned_config 363 | else: 364 | self._node_configurations[label] = cloned_config 365 | 366 | # noinspection PyShadowingBuiltins 367 | def add_relationship_configuration(self, type: Union[str, list[str]], **kwargs: Dict[str, Any]) -> None: 368 | """ 369 | Adds a configuration object for the given relationship `type`(s). 370 | 371 | Args: 372 | type (Union[str, list[str]]): The relationship type(s) for which this configuration should be used. Supports `*` to address all labels. 373 | **kwargs (Dict): Visualization configuration for the given node label. The following arguments are supported: 374 | 375 | - `text` (Union[str, Callable]): The text to be displayed on the node. By default, the relationship's type is used. 376 | - `color` (Union[str, Callable]): The relationship's color. 377 | - `thickness_factor` (Union[str, Callable]): The relationship's stroke thickness factor. By default, 1. 378 | - `property` (Union[Dict, Callable]): Allows to specify additional properties on the relationship, which may be bound by other bindings. 379 | 380 | Returns: 381 | None 382 | """ 383 | # this wrapper uses "text" as text binding in the graph 384 | # in contrast to "label" which is used in yfiles-jupyter-graphs 385 | text_binding = kwargs.pop("text", None) 386 | config = kwargs 387 | if text_binding is not None: 388 | config["label"] = text_binding 389 | 390 | cloned_config = {key: value for key, value in config.items()} 391 | if isinstance(type, list): 392 | for t in type: 393 | self._edge_configurations[t] = cloned_config 394 | else: 395 | self._edge_configurations[type] = cloned_config 396 | 397 | # noinspection PyShadowingBuiltins 398 | def add_parent_relationship_configuration(self, type: Union[str, list[str]], reverse: Optional[bool] = False) -> None: 399 | """ 400 | Configure specific relationship types to visualize as nested hierarchies. This removes these relationships from 401 | the graph and instead groups the related nodes (source and target) as parent-child. 402 | 403 | Args: 404 | type (Union[str, list[str]]): The relationship type(s) that should be visualized as node grouping hierarchy instead of the actual relationship. 405 | reverse (bool): Which node should be considered as parent. By default, the target node is considered as parent which can be reverted with this argument. 406 | 407 | Returns: 408 | None 409 | """ 410 | if isinstance(type, list): 411 | for t in type: 412 | self._parent_configurations.add((t, reverse)) 413 | else: 414 | self._parent_configurations.add((type, reverse)) 415 | 416 | # noinspection PyShadowingBuiltins 417 | def del_node_configuration(self, label: Union[str, list[str]]) -> None: 418 | """ 419 | Deletes the configuration object for the given node `label`(s). 420 | 421 | Args: 422 | label (Union[str, list[str]]): The node label(s) for which the configuration should be deleted. Supports `*` to address all labels. 423 | 424 | Returns: 425 | None 426 | """ 427 | if isinstance(label, list): 428 | for l in label: 429 | Neo4jGraphWidget.__safe_delete_configuration(l, self._node_configurations) 430 | else: 431 | Neo4jGraphWidget.__safe_delete_configuration(label, self._node_configurations) 432 | 433 | # noinspection PyShadowingBuiltins 434 | def del_relationship_configuration(self, type: Union[str, list[str]]) -> None: 435 | """ 436 | Deletes the configuration object for the given relationship `type`(s). 437 | 438 | Args: 439 | type (Union[str, list[str]]): The relationship type(s) for which the configuration should be deleted. Supports `*` to address all types. 440 | 441 | Returns: 442 | None 443 | """ 444 | if isinstance(type, list): 445 | for t in type: 446 | Neo4jGraphWidget.__safe_delete_configuration(t, self._edge_configurations) 447 | else: 448 | Neo4jGraphWidget.__safe_delete_configuration(type, self._edge_configurations) 449 | 450 | @staticmethod 451 | def __safe_delete_configuration(key: str, configurations: Dict[str, Any]) -> None: 452 | if key == "*": 453 | configurations.clear() 454 | if key in configurations: 455 | del configurations[key] 456 | 457 | # noinspection PyShadowingBuiltins 458 | def del_parent_relationship_configuration(self, type: Union[str, list[str]]) -> None: 459 | """ 460 | Deletes the relationship configuration for the given `type`(s). 461 | 462 | Args: 463 | type (Union[str, list[str]]): The relationship type(s) for which the configuration should be deleted. 464 | 465 | Returns: 466 | None 467 | """ 468 | if isinstance(type, list): 469 | self._parent_configurations = { 470 | rel_type for rel_type in self._parent_configurations if rel_type[0] not in type 471 | } 472 | else: 473 | self._parent_configurations = { 474 | rel_type for rel_type in self._parent_configurations if rel_type[0] != type 475 | } 476 | 477 | def get_selected_node_ids(self, widget: Optional[Type["Neo4jGraphWidget"]] = None) -> List[str]: 478 | """ 479 | Returns the list of node ids that are currently selected in the most recently shown widget, or in the given `widget`. 480 | 481 | Args: 482 | widget (Optional[Type["Neo4jGraphWidget"]]): The widget from which the selected ids should be retrieved. 483 | If not specified, the most recently shown widget will be used. 484 | 485 | Returns: 486 | List[str]: The list of node ids currently selected in the widget. 487 | """ 488 | graph = widget if widget is not None else self._widget 489 | nodes, edges = graph.get_selection() 490 | return list(map(lambda node: node['id'], nodes)) 491 | 492 | def get_selected_relationship_ids(self, widget: Optional[Type["Neo4jGraphWidget"]] = None) -> List[str]: 493 | """ 494 | Returns the list of relationship ids that are currently selected in the most recently shown widget, or in the given `widget`. 495 | 496 | Args: 497 | widget (Optional[Type["Neo4jGraphWidget"]]): The widget from which the selected ids should be retrieved. 498 | If not specified, the most recently shown widget will be used. 499 | 500 | Returns: 501 | List[str]: The list of relationship ids currently selected in the widget. 502 | """ 503 | graph = widget if widget is not None else self._widget 504 | nodes, edges = graph.get_selection() 505 | return list(map(lambda edge: edge['id'], edges)) 506 | 507 | def get_node_cell_mapping(self) -> Union[str, Callable, None]: 508 | """ 509 | Returns the currently specified node cell mapping. 510 | 511 | Returns: 512 | Union[str, Callable, None]: The currently specified node cell mapping. 513 | """ 514 | return self._node_cell_mapping if hasattr(self, '_node_cell_mapping') else None 515 | 516 | def set_node_cell_mapping(self, node_cell_mapping: Union[str, Callable]) -> None: 517 | """ 518 | Specify a node to cell mapping to fine-tune automatic layout algorithms. The mapping should resolve to a row, 519 | column tuple that is used as a cell into which the node is placed. 520 | 521 | Args: 522 | node_cell_mapping (Union[str, Callable]): Specifies a node to cell mapping. Must resolve to a row, column tuple or None. 523 | 524 | Returns: 525 | None 526 | """ 527 | # noinspection PyAttributeOutsideInit 528 | self._node_cell_mapping = node_cell_mapping 529 | 530 | def del_node_cell_mapping(self) -> None: 531 | """ 532 | Deletes the node cell mapping. 533 | 534 | Returns: 535 | None 536 | """ 537 | if hasattr(self, '_node_cell_mapping'): 538 | delattr(self, '_node_cell_mapping') 539 | 540 | node_cell_mapping = property(get_node_cell_mapping, set_node_cell_mapping, del_node_cell_mapping) -------------------------------------------------------------------------------- /src/yfiles_jupyter_graphs_for_neo4j/__init__.py: -------------------------------------------------------------------------------- 1 | # see Yfiles_Neo4j_Graphs.py 2 | 3 | from .Yfiles_Neo4j_Graphs import Neo4jGraphWidget 4 | --------------------------------------------------------------------------------