schrodinger.ui.qt.network_visualizer module

network_visualizer.py

Description: This package is meant to help with the visualization of network- connection data, in conjunction with network_views.py. A good example of the type of data this is meant to visualize is at: http://networkx.lanl.gov/index.html

The Graph class is meant as a wrapper for networkx.Graph objects, which can then act as a model for AbstractNetworkView and the associated network view classes defined in network_views.py.

Copyright Schrodinger, LLC. All rights reserved.

class schrodinger.ui.qt.network_visualizer.SyncLevels

Bases: IntEnum

Network view manages synchronization between the graph and the view. When the graph changes, the view is updated to ensure the node, edges and the selection state are the same.

When synchronizing multiple views with the graph, if a view triggers another graph synchronization then the views can reach an inconsistent state because not all views were updated the first time. To prevent this, we use synchronization levels to catch nested illegal synchronization attempts. Synchronization actions are assigned a level with the constraint that when sync level N is in progress then only sync level N+1 or higher actions can be triggered.

Synchronization actions:

* Nodes (add, delete, change)
* Edges (add, delete)

Network view also has superset methods for synchronizing the entire graph.

RECURSIVE = 0
ALL = 1
MODEL = 2
NODES = 3
NODES_ADDED = 4
NODES_DELETED = 4
NODES_CHANGED = 4
EDGES = 5
EDGES_ADDED = 6
EDGES_DELETED = 6
class schrodinger.ui.qt.network_visualizer.GraphSignals(*args, **kwargs)

Bases: QObject

selectionChanged

A pyqtSignal emitted by instances of the class.

positionChanged

A pyqtSignal emitted by instances of the class.

nodesChanged

A pyqtSignal emitted by instances of the class.

nodesAdded

A pyqtSignal emitted by instances of the class.

nodesDeleted

A pyqtSignal emitted by instances of the class.

edgesChanged

A pyqtSignal emitted by instances of the class.

graphChanged

A pyqtSignal emitted by instances of the class.

undoPointSet

A pyqtSignal emitted by instances of the class.

__init__(*args, **kwargs)
schrodinger.ui.qt.network_visualizer.restrict_nested_syncing(func, level: Union[int, SyncLevels] = 0, *args, **kwargs)

A decorator for restricting illegal nested syncing. Level should be greater than the current sync level.

class schrodinger.ui.qt.network_visualizer.Graph(ggraph=None, node_class=None, edge_class=None)

Bases: object

A model class for an undirected graph. This wraps around the NetworkX Graph class and provides QT signals, a easier-to-use API, and access control.

All persistent data should be stored in self._ggraph.

Note that Graph itself cannot be pickled; Graph has Graph.signals, which is a QObject and cannot be pickled. For this reason selection information (which contains references to Graph) is not placed in self._ggraph, so that self._ggraph can be pickled.

__init__(ggraph=None, node_class=None, edge_class=None)

Constructs a new Graph object

Parameters:
  • ggraph (networkx.Graph) – The graph underlying this graph.

  • node_class (class) – The class to represent the graph’s nodes (should be subclass of Node)

  • edge_class (class) – The class to represent the graph’s edges (should be subclass of Edge)

property ggraph
update()

Update any derived aspects of the graph after changes.

setEdgeValidator(validator)

Set an edge validator that will be run when adding edges between nodes. :param validator: the validator :type validator: ConnectionValidator

toNetworkX()

Return a copy of the underlying NetworkX graph.

getData(key)

Return the requested item from the graph’s data dictionary. Returns None if the key is not found.

setData(key, value, signal=True)

Set the value of an item in the graph’s data dictionary.

isConnected()

Checks whether the graph is connected, that is, whether every node is connected by some path to every other node.

Returns:

Whether the graph is connected rtype: bool

nodeCount()
Returns:

the number of nodes in the graph

Return type:

int

getIsolates()
Returns:

a complete set of nodes in the graph that have degree 0

Return type:

set(Node)

getConnectedComponents(nodes=None)

Return a set of nodes for each connected component in the graph.

Parameters:

nodes (set(Node) or NoneType) – optionally, a set of nodes to filter the returned components. If provided, this method will only return components for which at least one node is in nodes

Returns:

a generater over each connected component in the graph

Return type:

Generator[set[Node], None, None]

getNodeConnectedComponent(node)

Return a set of nodes that are part of the same connected component as node.

Parameters:

node (Node) – a node

Returns:

a set of nodes connected to node through any path of edges

Return type:

set(Node)

getNode(node_key)

Retrieve a node via its name. Retrieved nodes are cached, so getting the same Node again will return the same instance. Returns None if no matching Node exists.

Parameters:

node_key (object) – a node, gnode, or string that corresponds to the desired node

Returns:

a node if found, else None

Return type:

Node or NoneType

getNodes(node_keys=None)

Retrieve a set of nodes optionally indicated by a list of keys. If none is provided, return all nodes.

Parameters:

node_keys (list(object) or NoneType) – optionally, a list of nodes, gnodes, or strings that correspond to the desired nodes

Returns:

a set of nodes

Return type:

set(Node)

getNeighbors(node)

Return a set of all nodes connected to a specified node

Parameters:

node (Node) – center node

Returns:

neighboring nodes

Return type:

set of Node

addNodes(nodes, signal=True)

Add a list of nodes to this graph. The nodes argument can either be a list of Node objects or a list of hashable objects that can be used as new gnodes.

Note that any time a new gnode is created for use in this graph, its string representation must be unique among the other nodes in this graph: nodes are keyed in the node_objects dictionary by the string representation of their corresponding gnode.

Parameters:
  • nodes (list(object) or list(Node)) – list of gnodes or nodes

  • signal (bool) – whether the addNodes signal should be emitted when done

Returns:

a set of added nodes

Return type:

set(Node)

addNode(node, signal=True)

Convenience method for adding a single node to the graph. See addNodes() for full documentation.

Parameters:
  • node (hashable or Node) – gnode or node

  • signal (bool) – whether the addNodes signal should be emitted when done

Returns:

the added node

Return type:

Node

removeNodes(nodes, signal=True)

Remove specified nodes from the graph and optionally emit a signal.

Parameters:
  • nodes (list(Node)) – a list of nodes to be removed

  • signal (bool) – whether to emit a nodesDeleted signal when done

removeNode(node, signal=True)

Convenience function for removing a single node. See removeNode() for full documentation.

Parameters:
  • node (object or Node) – a gnode or node to remove

  • signal (bool) – whether to emit a nodesDeleted signal when done

setMultipleNodePos(pos_dict, signal=True)

Set the positions of nodes from a dictionary.

Parameters:

pos_dict (dict {Node : (int, int)}) – A dictionary mapping nodes to (x,y) tuples.

edgeCount()
Returns:

the number of edges in the graph

Return type:

int

hasEdge(node1, node2)

Return whether there is an edge between the supplied nodes.

Parameters:
  • node1 (Node) – a node from this graph

  • node2 (Node) – a node from this graph

Returns:

whether there exists an edge between the two supplied nodes

Return type:

bool

getGEdge(node0, node1)

Return the underlying gedge object corresponding to two supplied nodes. This can be overwritten in subclasses, but the returned class should define a consistent edge ordering that is independent of the order of the supplied node parameters.

Parameters:
  • node0 (Node) – a node

  • node1 (Node) – a node

Returns:

the underlying gedge between the two nodes, if it exists

Return type:

tuple(networkx.Node) or NoneType

getEdge(node0, node1)

Given two nodes, return the corresponding edge if it exists.

Parameters:
  • node0 (Node) – a node

  • node1 (Node) – a node

Returns:

the edge connecting the two nodes if it exists

Return type:

Edge or NoneType

getEdges(nodes=None)

Return all edges connected to a node or set of nodes. If no node is specified, all the edges in the graph are returned.

Parameters:

nodes (iterable(Node), Node, or None) – optionally a node or iterable of nodes

Returns:

a set of edges connected to at least one of the supplied nodes, or a set of all edges if nodes is not specified

Return type:

set(Edge)

addEdges(edge_tuples, signal=True)

Add edges to graph.

Parameters:
  • edge_tuples (list(tuple(Node, Node, dict)) or list(tuple(Node, Node, None))) – list of tuples indicating the edges to add, containing two gnodes or nodes and an edge attribute dictionary (or None)

  • signal (bool) – whether edgesChanged signal should be emitted when done

addEdge(node1, node2, signal=True, data=None)

Convenience function to add a single edge to the graph given two nodes. The order of the nodes does not matter.

Parameters:
  • node1 (object or Node) – a gnode or node connected by the edge

  • node2 (object or Node) – a gnode or node connected by the edge

  • signal (bool) – whether edgesChanged signal should be emitted when done

removeEdges(edges, signal=True)

Removes specified edges from the graph.

Parameters:
  • edges (list(Edge)) – a list of edges

  • signal (bool) – whether edgesChanged signal should be emitted when done

removeEdge(edge, signal=True)

Convenience function to remove a single edge from the graph.

Parameters:
  • edge (Edge) – an edge

  • signal (bool) – whether edgesChanged signal should be emitted when done

getEdgeApproval(node1, node2)

Test whether a new edge can be added between two nodes. Doesn’t actually add an edge, just returns whether it is allowable to add.

selectedNodes()

Return the currently selected nodes.

Return type:

set of Nodes

selectedEdges()
Returns:

the set of selected edges

Return type:

set(Edge)

setSelectedObjs(objs, source=None, signal=True)

Specify the current selection.

Parameters:
  • objs (list(Node or Edge)) – a list of objects (nodes or edges) to be selected

  • source (object) – the class instance calling this method (used to avoid infinite recursion when updating selection state)

  • signal (bool) – whether to emit a signal when changing selection state

springLayout(signal=True)

Performs a spring layout on the current graph.

minCrossingSpringLayout(num_iterations=100, fixed_nodes=None, fraction=1.0)

Perform multiple spring layouts and keep the one with the fewest edge intersections, keeping the original positions if the layout could not be improved.

Parameters:
  • num_iterations (int) – number of spring layouts to try

  • fixed (iterable of Node) – nodes for which the position should be fixed

  • signal (bool) – whether to emit the positionChanged signal

  • fraction (float) – stop iterating if no reduction in crossings is found within this fraction of num_iterations

hasPositions(accept_partial=False)

Determines whether the nodes in this graph have x-y coordinates.

Parameters:

accept_partial (bool) – if set to True, the method will check whether at least one node has coordinates. Otherwise it requires that all nodes have coordinates.

getState()

Get the current state of the Graph

setState(state)

Set the current state of the Graph

setUndoPoint(signal=True)

Store the current state to the undo stack. Also wipes out the redo stack.

undo()

Revert to the last state on the undo stack.

redo()

Undo the undo

clearUndoHistory()

Clears both undo and redo stacks

merge(g)

Merge data from another graph into this graph. Nodes with duplicate names will be considered to be the same ligand.

Parameters:

g (Graph) – graph from which data is being merged.

deleteSelectedItems(include_edges=True, include_nodes=True)

Delete selected nodes and/or selected edges.

Parameters:
  • include_edges (bool) – whether selected edges should be deleted

  • include_nodes (bool) – whether selected nodes should be deleted

deleteItems(nodes=None, edges=None)

Delete specified nodes and edges from the FEP map.

Parameters:
  • nodes (Set[Node]) – nodes to delete

  • edges (Set[Tuple[Node, Node]]) – edges to delete

class schrodinger.ui.qt.network_visualizer.Node(name, graph=None)

Bases: object

Model class for Node. Wraps the NetworkX Graph.node dictionary.

x_key = 'storedX'
y_key = 'storedY'
__init__(name, graph=None)

Construct a Node object. Most of the time, this will be constructed around an existing NetworkX node (i.e. an entry in the networkx.Graph.node dict). If a graph is specified, a node of the same name must exist in the graph, or a ValueError will result.

QT signals will only be emitted if a graph is specified.

Parameters:
  • name (hashable) – a unique identifier for this node

  • graph (Graph) – the graph object to which this node belongs

Variables:
  • _gnode – the underlying graph node that this node wraps. In this class, we use the node name as the graph node, but any hashable object can be used.

  • _gdata – dictionary that stores data belonging to the underlying graph node.

property gnode

Return the underlying graph node object wrapped by this Node instance (not the data dictionary _gdata).

property name

Return unique string associated with this node. Convert to string for subclasses which do not necessarily use strings as graph nodes.

x()
y()
pos()

Returns the Node’s current position coordinates. Returns None if there are no coordinates.

Return type:

tuple (float, float)

setX(x, signal=True)
setY(y, signal=True)
setPos(x, y, signal=True)

Set the node’s position coordinates

Parameters:
  • x (float) – x coordinate

  • y (float) – y coordinate

gdata()

Directly access the node data dictionary. Use this object carefully, as directly altering its contents can lead to internal inconsistencies.

This may be wrapped to restrict access.

getData(key)

Return the requested item from the node’s data dictionary. Returns None if the key is not found.

setData(key, value, signal=True)

Set the value of an item in the node’s data dictionary.

property degree
Returns:

the degree (number of edges) of the node

Return type:

int

class schrodinger.ui.qt.network_visualizer.Edge(gedge, graph)

Bases: object

__init__(gedge, graph)
Parameters:
  • gedge (object) – the underlying edge object wrapped by this object

  • graph (Graph) – the graph object to which this edge belongs

property gedge
Returns:

the underlying edge object wrapped by this object

Return type:

fep.graph.Edge

property graph
Returns:

the graph to which this edge belongs

Return type:

Graph

property nodes
Returns:

the nodes connected by this edge in a consistent order, as determined by the underlying graph edge

Return type:

tuple(Node, Node)

data()
Returns:

the data dictionary associated with this edge

Return type:

dict(str, object)

getData(key)

Return the requested item from the edge’s data dictionary. Returns None if the key is not found.

Parameters:

key (str) – the data item key

Returns:

the value stored under the specified key in the edge’s data dictionary, or None if it is not found

Return type:

object

setData(key, value, signal=True)

Set the specified item in the edge’s data dictionary.

Parameters:
  • key (str) – the data item key

  • value (object) – the value to set for the data item

property name
Returns:

the name of the edge, a composite of the connected node names

Return type:

str

class schrodinger.ui.qt.network_visualizer.ConnectionValidator

Bases: object

Create a subclass of this and assign it using NetworkViewer.setConnectionValidator( ) to do extra work making sure node’s are compatible to connect. val1 and val2 are node1.val and node2.val

__init__()
validate(node1, node2)
firstNode()
setFirstNode(node)
validateSecondVal(val)
class schrodinger.ui.qt.network_visualizer.AbstractNetworkView

Bases: object

A base class for views on Graph models. Use setModel to replace the model object. Signals from the model are automatically connected to appropriate synchronization slots.

The abstract view does not provide any built-in support for effecting changes back into the model (ex. deleting nodes, changing selection). Any such operations should be implemented in the subclass by making calls directly to the model. These changes will then be automatically synchronized forward to all views.

self.nodes is a dictionary mapping model node objects to view node objects.

self.edges is a dictionary mapping pairs of model node objects to view edge objects. There is no such thing as a edge model object.

Note that all references to the word node and edge in method names refer to view objects. For example, makeNode() will make a view node, addEdge() will add an edge view object to the view.

Variables:
  • MODEL_CLASS (Graph or subclass of Graph) – an instance of this class will be created as the default model when setModel

  • _sync_with_model (bool) – whether to automatically synchronize this view (and its subviews) with the model

MODEL_CLASS

alias of Graph

__init__()
syncAll()

Synchronize the full model and selection state.

syncRecursive()

Synchronize the full model and selection state on this view and all subviews.

setModelSyncEnabled(enable, sync_all=True)

Enable or disable automatic synchronization with the model for this view and all subviews.

setModel(model)

Set the model for this view and synchronize to it. Any subviews will have the model set on them as well.

Parameters:

model (Graph) – the graph model

getSignalsAndSlots(model)

Get a list of signal/slot pairs for a model. This list will be used when setting a new model to disconnect the old model signals from their slots and connect the new model’s signals to those slots.

Override this method to modify or extend signals/slots in derived classes.

Parameters:

model (Graph) – the graph model

addSubview(subview)

Add a subview to this view. A subview is another AbstractNetworkView that should always have the same model as its parent view (this view).

Adding will automatically set its model to the current model. Changing the model on this view will result in all its subviews getting the new model set

Parameters:

subview (AbstractNetworkView) – the new subview to add to this view

removeSubview(subview)

Removes the specified subview. The subview is not deleted or altered, and the model remains set.

Parameters:

subview

syncModel()
syncNodes()
syncNodesDeleted(nodes)
syncNodesAdded(nodes)
syncNodesChanged(nodes)
syncEdges()
syncSelection(selection, source)
makeNodes(nodes)

Create new view nodes and return a dictionary mapping supplied model nodes to corresponding view nodes. Do not add new view nodes to the view.

By default this method returns an “identity dictionary” that maps nodes to themselves. Subclasses should override this method to implement their own view nodes.

Parameters:

nodes (list(Node)) – model nodes

Returns:

a dictionary mapping supplied nodes to view nodes

Return type:

dict(Node, object)

makeNode(node)

Convenience method for calling makeNodes() with a single node. Rather than returning a dictionary mapping nodes to view nodes, returns the view node corresponding to the supplied node.

Parameters:

node (Node) – the model node

Returns:

the view node

Return type:

object

addNode(viewnode)

A convenience function for calling addNodes() for a single node.

Parameters:

viewnode (object) – a view node

removeNode(viewnode)

Convenience method for calling removeNode() for a single node.

Parameters:

viewnode (object) – a view node

updateNode(node)

Convenience method for calling updateNodes() for a single node.

Parameters:

node (Node) – the model node to update to

getModelNodes(node_keys=None)

Retrieve a set of model nodes optionally indicated by a list of keys. If none is provided, return all nodes.

Parameters:

node_keys (list(object) or NoneType) – optionally, a list of nodes, gnodes, or strings that correspond to the desired model nodes

Returns:

a set of nodes

Return type:

set(Node)

getNode(node)
Parameters:

node (Node) – a model node

Returns:

corresponding view node, if available

Return type:

object or None

makeEdges(edges)

Given a list of model edges, return a dictionary mapping them to corresponding view edges. Does not add view edges to the view.

By default this method returns an identity dictionary, mapping model edges to themselves. Subclasses should override this method if they want to implement their own view edges.

Parameters:

edges – a list model nodes

Returns:

a dictionary mapping model edges to view edges

Return type:

dict(Edge, object)

makeEdge(edge)

Convenience method for calling makeEdges() for a single edge. Rather than return a dictionary mapping model edges to view edges, returns a singe view edge. Does not add a view edge to the view.

Parameters:

edge (Edge) – a model edge

Returns:

a view edge

Return type:

object

addEdge(viewedge)

Convenience method for calling addEdges() for a single edge.

Parameters:

viewedge (object) – the view edge to add to the view

removeEdge(viewedge)

Convenience method for calling removeEdges() for a single edge.

Parameters:

viewedge (object) – the view edge to remove from the view

updateEdge(edge)

A convenience method for calling updateEdges() for a single edge.

Parameters:

edge (Edge) – the model edge corresponding to the view edge to update

getModelEdges(nodes=None)

Return all model edges connected to a model node or set of model nodes. If no node is specified, all the edges in the graph are returned. This method acts like Graph.getEdges(), but it filters for model edges that are available in this view.

Parameters:

nodes (list(Node), Node, or None) – optionally a node or list of nodes

Returns:

a list of model edges

Return type:

list(Edge)

getEdge(edge)

Return the view edge corresponding to the supplied model edge.

Parameters:

edge (Edge) – a model edge

Returns:

the corresponding view edge if available

Return type:

object or None

getEdges(nodes=None)

Return a list of view edges, filtering the list so that the edges are connected to the optionally-supplied node or iterable of nodes.

Parameters:

nodes (iterable[Node] or Node or NoneType) – a node or iterable of nodes

Returns:

list of view edges

Return type:

list[NetworkEdge or NoneType]

addNodes(viewnodes)

Takes view nodes and adds them to the view if that makes sense (eg. add graphics items to scene, add rows to table, etc.) It should not add the view node to self.nodes; that is handled in _addNodes().

Parameters:

viewnodes (list(object)) – view nodes to add to the view

removeNodes(viewnodes)

Removes view nodes from the view if that makes sense (eg. remove graphics items from scene, remove table rows, etc.) It should not remove view nodes from self.nodes; that is handled in _removeNodes().

Parameters:

viewnodes (list(object)) – a list of view nodes

updateNodes(nodes)

Performs any operations necessary to update the view to the current model state. Note that this method takes model nodes, not view nodes.

Parameters:

nodes (list(Node)) – model nodes which must have their views updated

addEdges(viewedges)

Adds view edges to the view. Does not add view edges to self.edges.

Parameters:

viewedges (list(object)) – view edges to add to the view

removeEdges(viewedges)

Removes view edges from the view. Does not remove view edges from self.edges.

Parameters:

viewedges (list(object)) – view edges to remove from the view

updateEdges(edges)

Performs any operations necessary to update the view to the current model state.

Parameters:

edges (list(Edge)) – a list of model edges corresponding to view edges that should be updated

selectItems(selected_view_objects)

Selects view objects in the view. Currently only view nodes will be requested, but may be expanded to allow a combination of nodes and edges to be selected.

Parameters:

selected_view_objects (list(object)) – a list of view objects to be selected

schrodinger.ui.qt.network_visualizer.perp(a)
schrodinger.ui.qt.network_visualizer.seg_intersect(a1, a2, b1, b2)

Checks whether two line segments cross each other.

Parameters:
  • a1 (numpy.array) – first endpoint of line segment a

  • a2 (numpy.array) – second endpoint of line segment a

  • b1 (numpy.array) – first endpoint of line segment b

  • b2 (numpy.array) – second endpoint of line segment b

Returns:

whether the line segments intersect

Return type:

bool

schrodinger.ui.qt.network_visualizer.fruchterman_reingold_layout(G, dim=2, pos=None, fixed=None, iterations=50, weight='weight', scale=1)

Position nodes using Fruchterman-Reingold force-directed algorithm.

Parameters:
  • G – NetworkX graph

  • dim (int) – Dimension of layout

  • pos (dict) – Initial positions for nodes as a dictionary with node as keys and values as a list or tuple. If None, then use random initial positions.

  • fixed (list) – Nodes to keep fixed at initial position. optional

  • iterations (int) – Number of iterations of spring-force relaxation

  • weight (str or None) – The edge attribute that holds the numerical value used for the edge weight. If None, then all edge weights are 1.

  • scale (float) – Scale factor for positions

Return type:

dict

Returns:

A dictionary of positions keyed by gnode

Examples:

>>> G=nx.path_graph(4)
>>> pos=nx.spring_layout(G)

# The same using longer function name
>>> pos=nx.fruchterman_reingold_layout(G)
schrodinger.ui.qt.network_visualizer.spring_layout(G, dim=2, pos=None, fixed=None, iterations=50, weight='weight', scale=1)

Position nodes using Fruchterman-Reingold force-directed algorithm.

Parameters:
  • G – NetworkX graph

  • dim (int) – Dimension of layout

  • pos (dict) – Initial positions for nodes as a dictionary with node as keys and values as a list or tuple. If None, then use random initial positions.

  • fixed (list) – Nodes to keep fixed at initial position. optional

  • iterations (int) – Number of iterations of spring-force relaxation

  • weight (str or None) – The edge attribute that holds the numerical value used for the edge weight. If None, then all edge weights are 1.

  • scale (float) – Scale factor for positions

Return type:

dict

Returns:

A dictionary of positions keyed by gnode

Examples:

>>> G=nx.path_graph(4)
>>> pos=nx.spring_layout(G)

# The same using longer function name
>>> pos=nx.fruchterman_reingold_layout(G)