Source code for xgi.convert.hypergraph_dict
"""Method for converting from a standardized dictionary."""
from collections import Counter
from ..exception import XGIError
from ..generators import empty_hypergraph
from ..utils import get_network_type
__all__ = ["to_hypergraph_dict", "from_hypergraph_dict"]
[docs]def to_hypergraph_dict(H):
"""A method to convert a hypergraph into a standard dictionary format.
Parameters
----------
H : Hypergraph
The hypergraph to convert
Returns
-------
dict
A dictionary of the form described in https://github.com/xgi-org/xgi-data.
Raises
------
XGIError
If node IDs will be collapsed when casting to a string.
XGIError
If edge Ids will be collapsed when casting to a string.
See Also
--------
~xgi.readwrite.json.read_json
~xgi.readwrite.json.write_json
"""
data = {}
data["type"] = get_network_type(H)
# name always gets written (default is an empty string)
data["hypergraph-data"] = {}
data["hypergraph-data"].update(H._net_attr)
# get node data
data["node-data"] = {str(idx): H.nodes[idx] for idx in H.nodes}
if len(data["node-data"]) != H.num_nodes:
dups = [
item
for item, count in Counter([str(n) for n in H.nodes]).items()
if count > 1
]
raise XGIError(
f"When casting node IDs to strings, ID(s) {', '.join(dups)} have conflicting IDs!"
)
data["edge-data"] = {str(idx): H.edges[idx] for idx in H.edges}
if len(data["edge-data"]) != H.num_edges:
dups = [
item
for item, count in Counter([str(n) for n in H.edges]).items()
if count > 1
]
raise XGIError(
f"When casting edge IDs to strings, ID(s) {', '.join(dups)} have conflicting IDs!"
)
# hyperedge dict
data["edge-dict"] = {
str(idx): [str(n) for n in sorted(H.edges.members(idx))] for idx in H.edges
}
return data
[docs]def from_hypergraph_dict(data, nodetype=None, edgetype=None, max_order=None):
"""
A function to read a file in a standardized JSON format.
Parameters
----------
data: dict
A dictionary in the hypergraph JSON format
nodetype: type, optional
Type that the node IDs will be cast to
edgetype: type, optional
Type that the edge IDs will be cast to
max_order: int, optional
Maximum order of edges to add to the hypergraph
Returns
-------
A Hypergraph object
The loaded hypergraph
Raises
------
XGIError
If the JSON is not in a format that can be loaded.
See Also
--------
~xgi.readwrite.json.read_json
~xgi.readwrite.json.write_json
"""
H = empty_hypergraph()
try:
H._net_attr.update(data["hypergraph-data"])
except KeyError:
raise XGIError("Failed to get hypergraph data attributes.")
try:
for idx, dd in data["node-data"].items():
if nodetype is not None:
try:
idx = nodetype(idx)
except ValueError as e:
raise TypeError(
f"Failed to convert edge IDs to type {nodetype}."
) from e
H.add_node(idx, **dd)
except KeyError:
raise XGIError("Failed to import node attributes.")
try:
for idx, edge in data["edge-dict"].items():
if max_order and len(edge) > max_order + 1:
continue
if edgetype is not None:
try:
idx = edgetype(idx)
except ValueError as e:
raise TypeError(
f"Failed to convert the edge with ID {idx} to type {edgetype}."
) from e
if nodetype is not None:
try:
edge = {nodetype(n) for n in edge}
except ValueError as e:
raise TypeError(
f"Failed to convert nodes to type {nodetype}."
) from e
H.add_edge(edge, idx)
except KeyError as e:
raise XGIError("Failed to import edge dictionary.") from e
try:
if edgetype is None:
edge_data = {
key: val for key, val in data["edge-data"].items() if key in H.edges
}
else:
edge_data = {
edgetype(e): dd
for e, dd in data["edge-data"].items()
if edgetype(e) in H.edges
}
H.set_edge_attributes(edge_data)
except KeyError as e:
raise XGIError("Failed to import edge attributes.") from e
return H