diff --git a/CHANGELOG.md b/CHANGELOG.md index f14d0c40..b159970b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed +* `utils.Tree`: v0.1.1 broke compatibility with Python 2. Therefore, modified code to be compatible + with Python 2. Added `props` and `edge_props` properties to accept arguments passed directly to + the node's and edge's dictionaries, respectively (e.g., 'classes', 'positions', etc.). +* Removed `Tree`'s method `add_child`, because it is redundant with `add_children` called with an + argument of length 1. + ## [0.1.1] - 2019-04-05 ### Fixed diff --git a/README.md b/README.md index 5bb6273c..860aa5ff 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Dash Cytoscape [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/plotly/dash-cytoscape/blob/master/LICENSE) [![PyPi Version](https://img.shields.io/pypi/v/dash-cytoscape.svg)](https://pypi.org/project/dash-cytoscape/) +[![CircleCI](https://circleci.com/gh/plotly/dash-cytoscape.svg?style=svg)](https://circleci.com/gh/plotly/dash-cytoscape) A Dash component library for creating interactive and customizable networks in Python, wrapped around [Cytoscape.js](http://js.cytoscape.org/). diff --git a/dash_cytoscape/utils/Tree.py b/dash_cytoscape/utils/Tree.py index 5af0e0c2..618010e7 100644 --- a/dash_cytoscape/utils/Tree.py +++ b/dash_cytoscape/utils/Tree.py @@ -2,26 +2,41 @@ class Tree(object): - def __init__(self, node_id, children=None, data=None, edge_data=None): + def __init__(self, + node_id, + children=None, + data=None, + props=None, + edge_data=None, + edge_props=None): """ A class to facilitate tree manipulation in Cytoscape. :param node_id: The ID of this tree, passed to the node data dict :param children: The children of this tree, also Tree objects :param data: Dictionary passed to this tree's node data dict + :param props: Dictionary passed to this tree's node dict, containing the node's props :param edge_data: Dictionary passed to the data dict of the edge connecting this tree to its parent + :param edge_props: Dictionary passed to the dict of the edge connecting this tree to its + parent """ - if not children: + if children is None: children = [] - if not data: + if data is None: data = {} - if not edge_data: + if props is None: + props = {} + if edge_data is None: edge_data = {} + if edge_props is None: + edge_props = {} self.node_id = node_id self.children = children self.data = data + self.props = props self.edge_data = edge_data + self.edge_props = edge_props self.index = {} def _dfs(self, search_id): @@ -58,17 +73,10 @@ def is_leaf(self): """ return not self.children - def add_child(self, child): - """ - Add a single child to the children of a Tree. - :param child: Tree object - """ - self.children.append(child) - def add_children(self, children): """ - Add a list of children to the current children of a Tree. - :param children: List of Tree objects + Add one or more children to the current children of a Tree. + :param children: List of Tree objects (one object or more) """ self.children.extend(children) @@ -77,16 +85,18 @@ def get_edges(self): Get all the edges of the tree in Cytoscape JSON format. :return: List of dictionaries, each specifying an edge """ - edges = [ - { + edges = [] + + for child in self.children: + di = { 'data': { 'source': self.node_id, - 'target': child.node_id, - **self.edge_data + 'target': child.node_id } } - for child in self.children - ] + di['data'].update(child.edge_data) + di.update(child.edge_props) + edges.append(di) for child in self.children: edges.extend(child.get_edges()) @@ -98,14 +108,15 @@ def get_nodes(self): Get all the nodes of the tree in Cytoscape JSON format. :return: List of dictionaries, each specifying a node """ - nodes = [ - { - 'data': { - 'id': self.node_id, - **self.data - } + di = { + 'data': { + 'id': self.node_id } - ] + } + + di['data'].update(self.data) + di.update(self.props) + nodes = [di] for child in self.children: nodes.extend(child.get_nodes()) @@ -155,3 +166,17 @@ def create_index(self): stack.append(child) return self.index + + +if __name__ == '__main__': + import pprint + + t1 = Tree('a', data={'hello': 'goodbye'}, children=[ + Tree('b', edge_data={'foo': 'bar'}, edge_props={'classes': 'directed'}), + Tree('c', props={'selected': True}) + ]) + + print("Nodes:") + pprint.pprint(t1.get_nodes()) + print('\nEdges:') + pprint.pprint(t1.get_edges())