Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add constructor to main widget #258

Merged
merged 8 commits into from
Nov 27, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
210 changes: 210 additions & 0 deletions examples/Graph Initialization.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "everyday-colonial",
"metadata": {},
"source": [
"# Some examples of how to initialise the Graph Widget\n",
"The CytoscapeWidget accepts an optional graph parameter, using this we can pass the graph's data and initialise a graph. We can pass data as:\n",
"- A json file (wither the filename or the json object itself)\n",
"- A networkx graph\n",
"- A pandas Dataframe\n",
"- A neo4j graph\n",
"- A ipycytoscape Graph"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "nominated-closing",
"metadata": {},
"outputs": [],
"source": [
"import ipycytoscape"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "waiting-brunswick",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "385ac265c37a4b35ada50b5f39c54028",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"CytoscapeWidget(cytoscape_layout={'name': 'cola'}, cytoscape_style=[{'selector': 'node', 'css': {'background-c…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 1. a cytoscape graph from json file\n",
"json_from_filename = ipycytoscape.CytoscapeWidget(\"concentricData.json\")\n",
"json_from_filename"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "dominant-locking",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "4c7176cff03b45c9b587e810b1bda8fe",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"CytoscapeWidget(cytoscape_layout={'name': 'cola'}, cytoscape_style=[{'selector': 'node', 'css': {'background-c…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 1. a cytoscape graph from json object\n",
"\n",
"import json\n",
"with open(\"concentricData.json\") as fi:\n",
" json_file = json.load(fi)\n",
"\n",
"json_from_object = ipycytoscape.CytoscapeWidget(json_file)\n",
"json_from_object"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "stupid-mayor",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "3ccae77ecfac48ab90b110b0aff16960",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"CytoscapeWidget(cytoscape_layout={'name': 'cola'}, cytoscape_style=[{'selector': 'node', 'css': {'background-c…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# A networkx graph\n",
"import networkx as nx\n",
"\n",
"G = nx.complete_graph(5)\n",
"graph_from_nx = ipycytoscape.CytoscapeWidget(G)\n",
"graph_from_nx"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "conceptual-sunday",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "cc1f647957b140d1ba6bfbcd5d7c7132",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"CytoscapeWidget(cytoscape_layout={'name': 'cola'}, cytoscape_style=[{'selector': 'node', 'css': {'background-c…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# A pandas Dataframe\n",
"\n",
"import pandas as pd\n",
"\n",
"graphFrame = pd.read_csv(\"https://raw.githubusercontent.com/nextstrain/ncov/fe5a7ed1f92af63d6d1d43d0307e4b2620108aaa/data/metadata.tsv\", sep = '\\t')\n",
"ipycytoscape.CytoscapeWidget(graphFrame[:30], groupby_cols=['country'], attribute_list=['age', 'virus'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "undefined-store",
"metadata": {},
"outputs": [],
"source": [
"# A neo4j graph\n",
"\n",
"from py2neo import Graph, Node, Relationship\n",
"\n",
"g = graph = Graph(\"bolt://132.249.238.185:7687\", user=\"reader\", password=\"demo\")\n",
"\n",
"ipycytoscape.CytoscapeWidget(g)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "instrumental-aggregate",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "1b636bbf760c435a896967b2b9736884",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"CytoscapeWidget(cytoscape_layout={'name': 'cola'}, cytoscape_style=[{'selector': 'node', 'css': {'background-c…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# A ipycytoscape graph\n",
"ipycytoscape.CytoscapeWidget(json_from_object.graph)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
51 changes: 49 additions & 2 deletions ipycytoscape/cytoscape.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
#
# The full license is in the file LICENSE, distributed with this software.

from os import path

import copy
import json

from spectate import mvc
from traitlets import TraitType, TraitError
Expand All @@ -28,6 +31,19 @@

import networkx as nx

try:
import pandas as pd

except ImportError:
pd = None

try:
import py2neo

except ImportError:
pass
ianhi marked this conversation as resolved.
Show resolved Hide resolved


"""TODO: Remove this after this is somewhat done"""
import logging

Expand Down Expand Up @@ -507,11 +523,19 @@ def add_graph_from_json(self, json_file, directed=False, multiple_edges=False):

Parameters
----------
json_file : dict
json_file : dict or string
If a dict is passed, it will be parsed as a JSON object,
a file path (to the json graph file) can also be passed as a
string, the file will be loaded it's content parsed as JSON an
object.
directed : bool
If True all edges will be given 'directed' as a class if
they do not already have it.
"""
if path.isfile(str(json_file)):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this fully protect us if the user passes in a dict?

with open(json_file) as f:
json_file = json.load(f)

node_list = list()
for node in json_file["nodes"]:
node_instance = Node()
Expand Down Expand Up @@ -814,12 +838,35 @@ class CytoscapeWidget(DOMWidget):

graph = Instance(Graph, args=tuple()).tag(sync=True, **widget_serialization)

def __init__(self, **kwargs):
def __init__(self, graph=None, **kwargs):
"""
Initializes the graph widget.

Parameters
----------
graph: string or dict or pandas DataFrame object or networkx Graph
object or neo4j Graph object or Graph object, optional (defaults
vaniisgh marked this conversation as resolved.
Show resolved Hide resolved
to None)
Checked to be of one of the declared types, and graph object
corresponding to it is added as a Graph attribute to the
CytoscapeWidget DOM.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Checked to be of one of the declared types, and graph object
corresponding to it is added as a Graph attribute to the
CytoscapeWidget DOM.
The graph to initialize with. Equivalent to calling the appropriate ``CytoscapeWidget.graph.add_graph_from_` method.

Is this clearer? We maybe should stay away from using words like DOM as I suspect that isn't a super clear term to most python users.

"""
super(CytoscapeWidget, self).__init__(**kwargs)

self.on_msg(self._handle_interaction)
self.graph = Graph()

if isinstance(graph, nx.Graph):
self.graph.add_graph_from_networkx(graph)
elif isinstance(graph, (dict, str)):
self.graph.add_graph_from_json(graph)
elif pd and isinstance(graph, pd.DataFrame):
self.graph.add_graph_from_df(graph, **kwargs)
elif isinstance(graph, Graph):
self.graph = graph
elif py2neo and isinstance(graph, py2neo.Graph):
self.graph.add_graph_from_neo4j(graph)

# Make sure we have a callback dispatcher for this widget and event type;
# since _interaction_handlers is synced with the frontend and changes to
# mutable values don't automatically propagate, we need to explicitly set
Expand Down