1"""
2Generate a visualisation using matplotlib or pyvis from Raphtory graphs.
3"""
4from pyvis.network import Network
5import networkx as nx
6import pandas as pd
7
8
[docs]
9def to_pyvis(
10 graph,
11 explode_edges=False,
12 edge_color="#000000",
13 shape=None,
14 node_image=None,
15 edge_weight=None,
16 edge_label=None,
17 colour_nodes_by_type=False,
18 type_property="type",
19 notebook=True,
20 **kwargs,
21):
22 r"""Draw a graph with Pyvis.
23
24 .. note::
25
26 Pyvis is a required dependency.
27 If you intend to use this function make sure that
28 you install Pyvis with ``pip install pyvis``
29
30 :param graph: A Raphtory graph.
31 :param explode_edges: A boolean that is set to True if you want to explode the edges in the graph. By default this is set to False.
32 :param str edge_color: A string defining the colour of the edges in the graph. By default ``#000000`` (black) is set.
33 :param str shape: An optional string defining what the node looks like.
34 There are two types of nodes. One type has the label inside of it and the other type has the label underneath it.
35 The types with the label inside of it are: ellipse, circle, database, box, text.
36 The ones with the label outside of it are: image, circularImage, diamond, dot, star, triangle, triangleDown, square and icon.
37 By default ``"dot"`` is set.
38 :param str node_image: An optional string defining the url of a custom node image. By default an image of a circle is set.
39 :param str edge_weight: An optional string defining the name of the property where edge weight is set on your Raphtory graph. By default ``1`` is set.
40 :param str edge_label: An optional string defining the name of the property where edge label is set on your Raphtory graph. By default, an empty string as the label is set.
41 :param bool notebook: A boolean that is set to True if using jupyter notebook. By default this is set to True.
42 :param kwargs: Additional keyword arguments that are passed to the pyvis Network class.
43
44 :returns: A pyvis network
45
46 For Example:
47
48 .. code-block:: python
49
50 from raphtory import Graph
51 from raphtory import export
52
53 g = Graph()
54 g.add_node(1, src, properties={"image": "image.png"})
55 g.add_edge(1, 1, 2, {"title": "edge", "weight": 1})
56 g.add_edge(1, 2, 1, {"title": "edge", "weight": 3})
57
58 export.to_pyvis(graph=g, edge_color="#FF0000", edge_weight= "weight", shape="image", node_image="image", edge_label="title")
59
60 """
61 visGraph = Network(notebook=notebook, **kwargs)
62 if colour_nodes_by_type:
63 groups = {
64 value: index + 1
65 for index, value in enumerate(
66 set(graph.nodes.properties.get(type_property))
67 )
68 }
69
70 for v in graph.nodes:
71 image = (
72 v.properties.get(node_image)
73 if node_image != None
74 else "https://cdn-icons-png.flaticon.com/512/7584/7584620.png"
75 )
76 shape = shape if shape is not None else "dot"
77 if colour_nodes_by_type:
78 visGraph.add_node(
79 v.id,
80 label=v.name,
81 shape=shape,
82 image=image,
83 group=groups[v.properties.get(type_property)],
84 )
85 else:
86 visGraph.add_node(v.id, label=v.name, shape=shape, image=image)
87
88 edges = graph.edges.explode() if explode_edges else graph.edges.explode_layers()
89 for e in edges:
90 weight = e.properties.get(edge_weight) if edge_weight is not None else 1
91 if weight is None:
92 weight = 1
93 label = e.properties.get(edge_label) if edge_label is not None else ""
94 if label is None:
95 label = ""
96 visGraph.add_edge(
97 e.src.id,
98 e.dst.id,
99 value=weight,
100 color=edge_color,
101 title=label,
102 arrowStrikethrough=False,
103 )
104
105 return visGraph
106
107
[docs]
108def to_networkx(
109 graph,
110 explode_edges=False,
111 include_node_properties=True,
112 include_edge_properties=True,
113 include_update_history=True,
114 include_property_histories=True,
115):
116 r"""Returns a graph with NetworkX.
117
118 .. note::
119
120 Network X is a required dependency.
121 If you intend to use this function make sure that
122 you install Network X with ``pip install networkx``
123
124 :param Graph graph: A Raphtory graph.
125 :param bool explode_edges: A boolean that is set to True if you want to explode the edges in the graph. By default this is set to False.
126 :param bool include_node_properties: A boolean that is set to True if you want to include the node properties in the graph. By default this is set to True.
127 :param bool include_edge_properties: A boolean that is set to True if you want to include the edge properties in the graph. By default this is set to True.
128 :param bool include_update_history: A boolean that is set to True if you want to include the update histories in the graph. By default this is set to True.
129 :param bool include_property_histories: A boolean that is set to True if you want to include the histories in the graph. By default this is set to True.
130
131 :returns: A Networkx MultiDiGraph.
132 """
133
134 networkXGraph = nx.MultiDiGraph()
135
136 node_tuples = []
137 for v in graph.nodes:
138 properties = {}
139 if include_node_properties:
140 if include_property_histories:
141 properties.update(v.properties.constant.as_dict())
142 properties.update(v.properties.temporal.histories())
143 else:
144 properties = v.properties.as_dict()
145 if include_update_history:
146 properties.update({"update_history": v.history()})
147 node_tuples.append((v.name, properties))
148 networkXGraph.add_nodes_from(node_tuples)
149
150 edge_tuples = []
151 edges = graph.edges.explode() if explode_edges else graph.edges.explode_layers()
152 for e in edges:
153 properties = {}
154 src = e.src.name
155 dst = e.dst.name
156 if include_edge_properties:
157 if include_property_histories:
158 properties.update(e.properties.constant.as_dict())
159 properties.update(e.properties.temporal.histories())
160 else:
161 properties = e.properties.as_dict()
162 layer = e.layer_name
163 if layer is not None:
164 properties.update({"layer": layer})
165 if include_update_history:
166 if explode_edges:
167 properties.update({"update_history": e.time})
168 else:
169 properties.update({"update_history": e.history()})
170 edge_tuples.append((src, dst, properties))
171
172 networkXGraph.add_edges_from(edge_tuples)
173
174 return networkXGraph
175
176
[docs]
177def to_edge_df(
178 graph,
179 explode_edges=False,
180 include_edge_properties=True,
181 include_update_history=True,
182 include_property_histories=True,
183):
184 r"""Returns an edge list pandas dataframe for the given graph.
185
186 .. note::
187
188 Pandas is a required dependency.
189 If you intend to use this function make sure that
190 you install pandas with ``pip install pandas``
191
192 :param Graph graph: A Raphtory graph.
193 :param bool explode_edges: A boolean that is set to True if you want to explode the edges in the graph. By default this is set to False.
194 :param bool include_edge_properties: A boolean that is set to True if you want to include the edge properties in the graph. By default this is set to True.
195 :param bool include_update_history: A boolean that is set to True if you want to include the update histories in the graph. By default this is set to True.
196 :param bool include_property_histories: A boolean that is set to True if you want to include the histories in the graph. By default this is set to True.
197
198 :returns: A pandas dataframe.
199 """
200 edge_tuples = []
201
202 columns = ["src", "dst", "layer"]
203 if include_edge_properties:
204 columns.append("properties")
205 if include_update_history:
206 columns.append("update_history")
207
208 edges = graph.edges.explode() if explode_edges else graph.edges.explode_layers()
209 for e in edges:
210 tuple = [e.src.name, e.dst.name, e.layer_name]
211 if include_edge_properties:
212 properties = {}
213 if include_property_histories:
214 properties.update(e.properties.constant.as_dict())
215 properties.update(e.properties.temporal.histories())
216 else:
217 properties = e.properties.as_dict()
218 tuple.append(properties)
219
220 if include_update_history:
221 if explode_edges:
222 tuple.append(e.time)
223 else:
224 tuple.append(e.history())
225
226 edge_tuples.append(tuple)
227
228 return pd.DataFrame(edge_tuples, columns=columns)
229
230
[docs]
231def to_node_df(
232 graph,
233 include_node_properties=True,
234 include_update_history=True,
235 include_property_histories=True,
236):
237 r"""Returns an node list pandas dataframe for the given graph.
238
239 .. note::
240
241 Pandas is a required dependency.
242 If you intend to use this function make sure that
243 you install pandas with ``pip install pandas``
244
245 :param Graph graph: A Raphtory graph.
246 :param bool include_node_properties: A boolean that is set to True if you want to include the node properties in the graph. By default this is set to True.
247 :param bool include_update_history: A boolean that is set to True if you want to include the update histories in the graph. By default this is set to True.
248 :param bool include_property_histories: A boolean that is set to True if you want to include the histories in the graph. By default this is set to True.
249
250 :returns: A pandas dataframe.
251
252 """
253 node_tuples = []
254 columns = ["id"]
255 if include_node_properties:
256 columns.append("properties")
257 if include_update_history:
258 columns.append("update_history")
259
260 for v in graph.nodes:
261 tuple = [v.name]
262 if include_node_properties:
263 properties = {}
264 if include_property_histories:
265 properties.update(v.properties.constant.as_dict())
266 properties.update(v.properties.temporal.histories())
267 else:
268 properties = v.properties.as_dict()
269 tuple.append(properties)
270 if include_update_history:
271 tuple.append(v.history())
272 node_tuples.append(tuple)
273 return pd.DataFrame(node_tuples, columns=columns)