cognite-neat 0.93.0__py3-none-any.whl → 0.94.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cognite-neat might be problematic. Click here for more details.

@@ -1,11 +1,16 @@
1
+ import random
1
2
  from typing import Any, cast
2
3
 
3
4
  import networkx as nx
4
5
  from ipycytoscape import CytoscapeWidget # type: ignore
5
6
  from IPython.display import display
6
7
 
8
+ from cognite.neat._rules._constants import EntityTypes
7
9
  from cognite.neat._rules.models.dms._rules import DMSRules
8
- from cognite.neat._rules.models.entities._single_value import ViewEntity
10
+ from cognite.neat._rules.models.entities._single_value import ClassEntity, ViewEntity
11
+ from cognite.neat._rules.models.information._rules import InformationRules
12
+ from cognite.neat._session.exceptions import NeatSessionError
13
+ from cognite.neat._utils.rdf_ import remove_namespace_from_uri
9
14
 
10
15
  from ._state import SessionState
11
16
 
@@ -14,6 +19,119 @@ class ShowAPI:
14
19
  def __init__(self, state: SessionState) -> None:
15
20
  self._state = state
16
21
  self.data_model = ShowDataModelAPI(self._state)
22
+ self.instances = ShowInstanceAPI(self._state)
23
+
24
+
25
+ class ShowInstanceAPI:
26
+ def __init__(self, state: SessionState) -> None:
27
+ self._state = state
28
+
29
+ def __call__(self) -> Any:
30
+ if not self._state.store.graph:
31
+ raise NeatSessionError("No instances available. Try using [bold].read[/bold] to load instances.")
32
+
33
+ widget = CytoscapeWidget()
34
+ widget.layout.height = "700px"
35
+
36
+ NxGraph, types = self._generate_instance_di_graph_and_types()
37
+ widget_style = self._generate_cytoscape_widget_style(types)
38
+ widget.set_style(widget_style)
39
+
40
+ widget.graph.add_graph_from_networkx(NxGraph)
41
+ print("Max of 100 nodes and edges are displayed, which are randomly selected.")
42
+
43
+ return display(widget)
44
+
45
+ def _generate_instance_di_graph_and_types(self) -> tuple[nx.DiGraph, set[str]]:
46
+ query = """
47
+ SELECT ?s ?p ?o ?ts ?to WHERE {
48
+ ?s ?p ?o .
49
+ FILTER(isIRI(?o)) # Example filter to check if ?o is an IRI (object type)
50
+ FILTER(BOUND(?o))
51
+ FILTER(?p != rdf:type)
52
+
53
+ ?s a ?ts .
54
+ ?o a ?to .
55
+ }
56
+ LIMIT 100
57
+ """
58
+
59
+ NxGraph = nx.DiGraph()
60
+
61
+ types = set()
62
+
63
+ for ( # type: ignore
64
+ subject,
65
+ property_,
66
+ object,
67
+ subject_type,
68
+ object_type,
69
+ ) in self._state.store.graph.query(query):
70
+ subject = remove_namespace_from_uri(subject)
71
+ property_ = remove_namespace_from_uri(property_)
72
+ object = remove_namespace_from_uri(object)
73
+ subject_type = remove_namespace_from_uri(subject_type)
74
+ object_type = remove_namespace_from_uri(object_type)
75
+
76
+ NxGraph.add_node(subject, label=subject, type=subject_type)
77
+ NxGraph.add_node(object, label=object, type=object_type)
78
+ NxGraph.add_edge(subject, object, label=property_)
79
+
80
+ types.add(subject_type)
81
+ types.add(object_type)
82
+
83
+ return NxGraph, types
84
+
85
+ def _generate_cytoscape_widget_style(self, types: set[str]) -> list[dict]:
86
+ widget_style = [
87
+ {
88
+ "selector": "edge",
89
+ "style": {
90
+ "width": 1,
91
+ "target-arrow-shape": "triangle",
92
+ "curve-style": "bezier",
93
+ "label": "data(label)",
94
+ "font-size": "8px",
95
+ "line-color": "black",
96
+ "target-arrow-color": "black",
97
+ },
98
+ },
99
+ ]
100
+
101
+ colors = self._generate_hex_colors(len(types))
102
+
103
+ for i, type_ in enumerate(types):
104
+ widget_style.append(self._generate_node_cytoscape_style(type_, colors[i]))
105
+
106
+ return widget_style
107
+
108
+ @staticmethod
109
+ def _generate_hex_colors(n: int) -> list[str]:
110
+ """Generate a list of N random HEX color codes."""
111
+ random.seed(42) # Set a seed for deterministic behavior
112
+ hex_colors = []
113
+ for _ in range(n):
114
+ color = f"#{random.randint(0, 0xFFFFFF):06x}"
115
+ hex_colors.append(color)
116
+ return hex_colors
117
+
118
+ @staticmethod
119
+ def _generate_node_cytoscape_style(type_: str, color: str) -> dict:
120
+ template = {
121
+ "css": {
122
+ "content": "data(label)",
123
+ "text-valign": "center",
124
+ "color": "black",
125
+ "font-size": "10px",
126
+ "width": "mapData(score, 0, 1, 10, 50)",
127
+ "height": "mapData(score, 0, 1, 10, 50)",
128
+ },
129
+ }
130
+
131
+ template["selector"] = f'node[type = "{type_}"]' # type: ignore
132
+ template["css"]["background-color"] = color
133
+
134
+ return template
17
135
 
18
136
 
19
137
  class ShowDataModelAPI:
@@ -21,50 +139,90 @@ class ShowDataModelAPI:
21
139
  self._state = state
22
140
 
23
141
  def __call__(self) -> Any:
142
+ if not self._state.last_verified_dms_rules and not self._state.last_verified_information_rules:
143
+ raise NeatSessionError(
144
+ "No verified data model available. Try using [bold].verify()[/bold] to verify data model."
145
+ )
146
+
24
147
  if self._state.last_verified_dms_rules:
25
- digraph = self._generate_dms_di_graph()
26
- widget = self._generate_widget()
27
- widget.graph.add_graph_from_networkx(digraph)
28
- return display(widget)
148
+ NxGraph = self._generate_dms_di_graph()
149
+ elif self._state.last_verified_information_rules:
150
+ NxGraph = self._generate_info_di_graph()
151
+
152
+ widget = self._generate_widget()
153
+ widget.graph.add_graph_from_networkx(NxGraph)
154
+ return display(widget)
29
155
 
30
156
  def _generate_dms_di_graph(self) -> nx.DiGraph:
31
157
  """Generate a DiGraph from the last verified DMS rules."""
32
- G = nx.DiGraph()
158
+ NxGraph = nx.DiGraph()
33
159
 
34
- nodes, edges = self._generate_dms_rules_nodes_and_edges()
35
- G.add_nodes_from(nodes)
36
- G.add_edges_from(edges)
37
- for node in G.nodes:
38
- G.nodes[node]["label"] = node
39
-
40
- return G
160
+ # Add nodes and edges from Views sheet
161
+ for view in cast(DMSRules, self._state.last_verified_dms_rules).views:
162
+ # if possible use human readable label coming from the view name
163
+ if not NxGraph.has_node(view.view.suffix):
164
+ NxGraph.add_node(view.view.suffix, label=view.name or view.view.suffix)
41
165
 
42
- def _generate_dms_rules_nodes_and_edges(self) -> tuple[list[str], list[tuple[str, str, dict]]]:
43
- """Generate nodes and edges for the last verified DMS rules for DiGraph."""
166
+ # add implements as edges
167
+ if view.implements:
168
+ for implement in view.implements:
169
+ if not NxGraph.has_node(implement.suffix):
170
+ NxGraph.add_node(implement.suffix, label=implement.suffix)
44
171
 
45
- nodes = []
46
- edges = []
172
+ NxGraph.add_edge(view.view.suffix, implement.suffix, label="implements")
47
173
 
174
+ # Add nodes and edges from Properties sheet
48
175
  for prop_ in cast(DMSRules, self._state.last_verified_dms_rules).properties:
49
- nodes.append(prop_.view.suffix)
50
-
51
176
  if prop_.connection and isinstance(prop_.value_type, ViewEntity):
177
+ if not NxGraph.has_node(prop_.view.suffix):
178
+ NxGraph.add_node(prop_.view.suffix, label=prop_.view.suffix)
179
+
52
180
  label = f"{prop_.property_} [{0 if prop_.nullable else 1}..{ '' if prop_.is_list else 1}]"
53
- edges.append((prop_.view.suffix, prop_.value_type.suffix, {"label": label}))
181
+ NxGraph.add_edge(prop_.view.suffix, prop_.value_type.suffix, label=label)
54
182
 
55
- for view in cast(DMSRules, self._state.last_verified_dms_rules).views:
56
- nodes.append(view.view.suffix)
183
+ return NxGraph
57
184
 
58
- if view.implements:
59
- for implement in view.implements:
60
- edges.append((view.view.suffix, implement.suffix, {"label": "implements"}))
185
+ def _generate_info_di_graph(self) -> nx.DiGraph:
186
+ """Generate nodes and edges for the last verified Information rules for DiGraph."""
187
+
188
+ NxGraph = nx.DiGraph()
189
+
190
+ # Add nodes and edges from Views sheet
191
+ for class_ in cast(InformationRules, self._state.last_verified_information_rules).classes:
192
+ # if possible use human readable label coming from the view name
193
+ if not NxGraph.has_node(class_.class_.suffix):
194
+ NxGraph.add_node(
195
+ class_.class_.suffix,
196
+ label=class_.name or class_.class_.suffix,
197
+ )
198
+
199
+ # add implements as edges
200
+ if class_.parent:
201
+ for parent in class_.parent:
202
+ if not NxGraph.has_node(parent.suffix):
203
+ NxGraph.add_node(parent.suffix, label=parent.suffix)
61
204
 
62
- return nodes, edges
205
+ NxGraph.add_edge(class_.class_.suffix, parent.suffix, label="subClassOf")
206
+
207
+ # Add nodes and edges from Properties sheet
208
+ for prop_ in cast(InformationRules, self._state.last_verified_information_rules).properties:
209
+ if prop_.type_ == EntityTypes.object_property:
210
+ if not NxGraph.has_node(prop_.class_.suffix):
211
+ NxGraph.add_node(prop_.class_.suffix, label=prop_.class_.suffix)
212
+
213
+ label = f"{prop_.property_} [{1 if prop_.is_mandatory else 0}..{ '' if prop_.is_list else 1}]"
214
+ NxGraph.add_edge(
215
+ prop_.class_.suffix,
216
+ cast(ClassEntity, prop_.value_type).suffix,
217
+ label=label,
218
+ )
219
+
220
+ return NxGraph
63
221
 
64
222
  def _generate_widget(self):
65
223
  """Generates an empty a CytoscapeWidget."""
66
224
  widget = CytoscapeWidget()
67
- widget.layout.height = "500px"
225
+ widget.layout.height = "700px"
68
226
 
69
227
  widget.set_style(
70
228
  [
@@ -88,6 +246,26 @@ class ShowDataModelAPI:
88
246
  "curve-style": "bezier",
89
247
  "label": "data(label)",
90
248
  "font-size": "8px",
249
+ "line-color": "black",
250
+ "target-arrow-color": "black",
251
+ },
252
+ },
253
+ {
254
+ "selector": 'edge[label = "subClassOf"]',
255
+ "style": {
256
+ "line-color": "grey",
257
+ "target-arrow-color": "grey",
258
+ "line-style": "dashed",
259
+ "font-size": "8px",
260
+ },
261
+ },
262
+ {
263
+ "selector": 'edge[label = "implements"]',
264
+ "style": {
265
+ "line-color": "grey",
266
+ "target-arrow-color": "grey",
267
+ "line-style": "dashed",
268
+ "font-size": "8px",
91
269
  },
92
270
  },
93
271
  ]
@@ -3,7 +3,7 @@ import warnings
3
3
  from collections.abc import Iterable
4
4
  from datetime import datetime, timezone
5
5
  from pathlib import Path
6
- from typing import Any, cast
6
+ from typing import cast
7
7
 
8
8
  import pandas as pd
9
9
  from pandas import Index
@@ -383,6 +383,6 @@ class NeatGraphStore:
383
383
  ],
384
384
  ignore_index=True,
385
385
  )
386
- shorter_summary.index = cast(Index[Any], indexes)
386
+ shorter_summary.index = cast(Index, indexes)
387
387
 
388
388
  return shorter_summary
cognite/neat/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.93.0"
1
+ __version__ = "0.94.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cognite-neat
3
- Version: 0.93.0
3
+ Version: 0.94.0
4
4
  Summary: Knowledge graph transformation
5
5
  Home-page: https://cognite-neat.readthedocs-hosted.com/
6
6
  License: Apache-2.0
@@ -215,14 +215,14 @@ cognite/neat/_session/__init__.py,sha256=fxQ5URVlUnmEGYyB8Baw7IDq-uYacqkigbc4b-P
215
215
  cognite/neat/_session/_base.py,sha256=9QgOUeizAwG9P7xy5J8zOsRd5cMMkncYgv6PTeWgd_k,3564
216
216
  cognite/neat/_session/_prepare.py,sha256=u7dJ4nZqB9j6JWoBx6em9ABKc_PA_yaRQWfiI1n3iks,2484
217
217
  cognite/neat/_session/_read.py,sha256=JQyxG1-QyX8fbiUnwVexKzlgWMg9VUeTJvC0uFgAg_U,4401
218
- cognite/neat/_session/_show.py,sha256=0xzXx8fzM1CWxflWwQK0QYE3KU0ZDJUYL8W5Pg-21b0,3286
218
+ cognite/neat/_session/_show.py,sha256=q1cuqpDRaNS1hCwgvpxk-nR1V3pcYPyQdyRn5zUMGWQ,10217
219
219
  cognite/neat/_session/_state.py,sha256=ef7OiCxavk4_asIivENaWrvC3HcXZNV6wGldus55JD0,2488
220
220
  cognite/neat/_session/_to.py,sha256=u--yGD2y9JKV-sf34PYsMf-nc9Qs2yibpPsv6IG0CLA,2125
221
221
  cognite/neat/_session/_wizard.py,sha256=Rdld2eZ-Q5BYbmAwW8FlfAYebdlw_P6L6V2WSDk-dHI,1306
222
222
  cognite/neat/_session/exceptions.py,sha256=qT0Mq3h-0NaDatvyr2D476LkSjmvyZtNmmLXtd1SLVg,1106
223
223
  cognite/neat/_shared.py,sha256=RSaHm2eJceTlvb-hMMe4nHgoHdPYDfN3XcxDXo24k3A,1530
224
224
  cognite/neat/_store/__init__.py,sha256=G-VG_YwfRt1kuPao07PDJyZ3w_0-eguzLUM13n-Z_RA,64
225
- cognite/neat/_store/_base.py,sha256=W-xcxfmlAUG-7JKcL2JwUuPG5xA4KugHT2x_FdZXJQY,14215
225
+ cognite/neat/_store/_base.py,sha256=xi9uxV12X5XcGW-fzTEeDfaTM6Rkt-KpGaeyLXqep4Q,14205
226
226
  cognite/neat/_store/_provenance.py,sha256=mD14UnETX6YkR8RO60Oxz7vBPm2Dm8m2xwthhLIxqSc,4122
227
227
  cognite/neat/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
228
228
  cognite/neat/_utils/auth.py,sha256=hyDnVBUbbgVANzayxbh9uTWlYb924hmzPYkVwwLfDIg,13241
@@ -240,7 +240,7 @@ cognite/neat/_utils/text.py,sha256=PvTEsEjaTu8SE8yYaKUrce4msboMj933dK7-0Eey_rE,3
240
240
  cognite/neat/_utils/time_.py,sha256=O30LUiDH9TdOYz8_a9pFqTtJdg8vEjC3qHCk8xZblG8,345
241
241
  cognite/neat/_utils/upload.py,sha256=X5GGWHswnW0BrL2ulmm5MnKKtn-t1C8Ps3gb9Byc914,4016
242
242
  cognite/neat/_utils/xml_.py,sha256=FQkq84u35MUsnKcL6nTMJ9ajtG9D5i1u4VBnhGqP2DQ,1710
243
- cognite/neat/_version.py,sha256=W-KEJT0wpRrG8XJ2aDG4NSyzaUucgZR9y6mwfCTlku4,23
243
+ cognite/neat/_version.py,sha256=BbCpQB0IaKmq_fOtysTb_iVtvqbH-vHS1DoS1eLd4w8,23
244
244
  cognite/neat/_workflows/__init__.py,sha256=S0fZq7kvoqDKodHu1UIPsqcpdvXoefUWRPt1lqeQkQs,420
245
245
  cognite/neat/_workflows/base.py,sha256=O1pcmfbme2gIVF2eOGrKZSUDmhZc8L9rI8UfvLN2YAM,26839
246
246
  cognite/neat/_workflows/cdf_store.py,sha256=3pebnATPo6In4-1srpa3wzstynTOi3T6hwFX5uaie4c,18050
@@ -269,8 +269,8 @@ cognite/neat/_workflows/tasks.py,sha256=dr2xuIb8P5e5e9p_fjzRlvDbKsre2xGYrkc3wnRx
269
269
  cognite/neat/_workflows/triggers.py,sha256=u69xOsaTtM8_WD6ZeIIBB-XKwvlZmPHAsZQh_TnyHcM,7073
270
270
  cognite/neat/_workflows/utils.py,sha256=gKdy3RLG7ctRhbCRwaDIWpL9Mi98zm56-d4jfHDqP1E,453
271
271
  cognite/neat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
272
- cognite_neat-0.93.0.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
273
- cognite_neat-0.93.0.dist-info/METADATA,sha256=7LtcqYVhejVdcOylDNH0joitMI2PEGd-Dn6JJkKVDuQ,9668
274
- cognite_neat-0.93.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
275
- cognite_neat-0.93.0.dist-info/entry_points.txt,sha256=SsQlnl8SNMSSjE3acBI835JYFtsIinLSbVmHmMEXv6E,51
276
- cognite_neat-0.93.0.dist-info/RECORD,,
272
+ cognite_neat-0.94.0.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
273
+ cognite_neat-0.94.0.dist-info/METADATA,sha256=aKSpijqnnPjjnO0NTC98tdm4YBbP67wwGz8tM_DSnus,9668
274
+ cognite_neat-0.94.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
275
+ cognite_neat-0.94.0.dist-info/entry_points.txt,sha256=SsQlnl8SNMSSjE3acBI835JYFtsIinLSbVmHmMEXv6E,51
276
+ cognite_neat-0.94.0.dist-info/RECORD,,