The GraphGroup
Contents
The GraphGroup
#
The GraphGroup
is specialized on managing and handling graph-related data.
The group defines a graph via data groups and data containers that store nodes, edges, and optionally their properties.
Creating a GraphGroup#
The GraphGroup
holds the following, customizable variables that describe in which containers or attributes to find the info on the nodes and edges:
_GG_node_container = "nodes"
: The name of the container or group (node_container
) containing the node data_GG_edge_container = "edges"
: The name of the container or group (edge_container
) containing the edge data_GG_attr_directed = "directed"
: TheGraphGroup
attribute (boolean) describing whether the graph is directed or not_GG_attr_parallel = "parallel"
: TheGraphGroup
attribute (boolean) describing whether the graph allows for parallel edges or not_GG_attr_edge_container_is_transposed = "edge_container_is_transposed"
: TheGraphGroup
attribute (boolean) describing whether the edge container is transposed, i.e., has the shape(edge-tuple-size, edge-number)
_GG_attr_keep_dim = "keep_dim"
: TheGraphGroup
attribute (iterable) describing which dimensions are not to be squeezed during data selection.
If you do not change anything, the default values are taken.
The GraphGroup
only holds and manages graph data but itself is not a graph, in the sense that no functionality such as finding the neighborhood of a node is implemented there.
Instead, the GraphGroup
uses the networkx library and its interface for creating Graph
objects.
In the following, an overview is given how graphs can be created from a GraphGroup
.
Creating Graphs from a GraphGroup#
The GraphGroup
contains the create_graph()
method that creates a graph from the containers and groups that are part of the GraphGroup
together with information provided by the GraphGroup
attributes.
However, the function also allows you to explicitly set graph properties such as whether the graph should be directed or allow for parallel edges.
The function returns a networkx graph object corresponding to the provided data and information.
The create_graph()
function further allows you to optionally set node and edge properties by specifying node_props
or edge_props
lists.
Any data can be pre-selected using the sel
and isel
arguments.
The selectors are applied to all data involved, i.e., to node, edge, as well as property data.
It is also possible to provide both sel
and isel
as long as the intersection of both key-sets is empty.
Warning
Invalid keys in sel
and isel
are ignored silently. This means that the node, edge, and property data need not have the same set of dimensions in order to apply a selection.
Moreover, all dimensions of size 1 are squeezed, hence no selection has to be specified in such scenarios, i.e. when the selection is unambiguous.
If you have node/edge data that changes over time, you can select along the time
dimension directly via the at_times
or the at_time_idx
argument.
This sets or overwrites the respective entry in the sel
or isel
dicts.
The following example demonstrates the graph creation: Let us assume that we have a graph with static nodes and dynamic edges, each with dynamic properties.
The dynamic data, stored as TimeSeriesGroup
, is given for two points in time.
The resulting data tree looks as follows:
# graph_group <GraphGroup, 4 members, 2 attributes>
# └┬ nodes <XrDataContainer, ..., shape (10,), 0 attributes>
# ├ some_node_prop <XrDataContainer, ..., shape (2,10), 0 attributes>
# ├ edges <TimeSeriesGroup, 2 members, 0 attributes>
# └┬ 0 <XrDataContainer, ..., shape (9,2), 0 attributes>
# └ 10 <XrDataContainer, ..., shape (6,2), 0 attributes>
# ├ some_edge_prop <TimeSeriesGroup, 2 members, 0 attributes>
# └┬ 0 <XrDataContainer, ..., shape (9,), 0 attributes>
# └ 10 <XrDataContainer, ..., shape (6,), 0 attributes>
# └ other_edge_prop <XrDataContainer, ..., shape (6,), 0 attributes>
Let’s now create a graph from the GraphGroup
:
# Create the initial graph from the graph group without node/edge properties
g = graph_group.create_graph(at_time=0) # time specified by value
# Now, create the final graph with `some_node_prop` as node property and
# `some_edge_prop` as edge property.
g = graph_group.create_graph(at_time_idx=-1, # time specified via index
node_props=["some_node_prop"],
edge_props=["some_edge_prop"])
Hint
Graph creation might fail for graphs with a single node (edge) due to the node (edge) dimension (of size 1) being squeezed out. It is therefore strongly recommended to specify the node and edge dimension names in the _GG_attr_keep_dim
group attribute. Alternatively, they can be specified via the keep_dim
argument in create_graph()
, set_node_property()
, and set_edge_property()
.
Setting Graph Properties#
If you already have a networkx
graph object, you can set node or edge properties using the set_node_property()
or set_edge_property()
function.
Properties can be added from:
data stored inside the
GraphGroup
: Here, thename
argument specifies the name of the data container or group which stores the property.external data: see Loading External Data as Graph Property
In both cases, name
will be the name of the node or edge property in the networkx
graph.
Again, the data can be pre-selected using the sel
, isel
, at_time
, and at_time_idx
arguments.
In the example below, the other_edge_prop
data stored inside the graph group is added as edge property.
Note that time specification is required here, even though other_edge_prop
is one-dimensional, because edge_container
contains edge data for multiple times.
# Set the edge property manually from the `other_edge_prop` data container
# and select the data of the last time step
graph_group.set_edge_property(g=g, name="other_edge_prop", at_time_idx=-1)
Node properties can be added analogously.
Note
Node (edge) properties can only be added for those nodes (edges) that are available in the node_container
(edge_container
).
By default, property data is assumed to be aligned with the GraphGroup
s node (edge) data.
However, it can be aligned with the latter via xarray.align by setting align
to True
in set_node_property()
(set_edge_property()
).
The indexes of the node_container
(edge_container
) are used for the alignment in each dimension.
If the class variable _GG_WARN_UPON_BAD_ALIGN
is set to True
(default: True
), warnings on possible pitfalls are given.
Loading External Data as Graph Property#
If you want to add a graph property from data that is not stored inside the GraphGroup
(e.g., you have pre-processed some data), this can be realized in two different ways:
- Making use of the
property_maps
. After registering external data with a key using
register_property_map()
, it will be permanently available via the provided key, i.e., the key can be passed asname
in theset_*_property
functions.
- Making use of the
- Loading the external data directly by passing it via the
data
argument in the respectiveset_*_property
function. The
name
argument then sets the name of the property.
- Loading the external data directly by passing it via the
Have a look at a small example where some external data ext_data
is added to the graph as a node property:
# Make the external data available in the graph group under the given key
graph_group.register_property_map("my_ext_node_prop", data=ext_data)
# Use the newly created key to set the external data as node property
graph_group.set_node_property(g=g, name="my_ext_node_prop")
# Alternatively, load the external data directly via the `data` argument
graph_group.set_node_property(g=g, name="my_ext_node_prop", data=ext_data)