howso-visuals 2.0.10__py3-none-any.whl → 2.1.1__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.
howso/visuals/__init__.py CHANGED
@@ -1,3 +1,4 @@
1
+ from . import graph
1
2
  from .visuals import (
2
3
  compose_figures,
3
4
  plot_anomalies,
@@ -12,6 +13,7 @@ from .visuals import (
12
13
 
13
14
  __all__ = [
14
15
  "compose_figures",
16
+ "graph",
15
17
  "plot_anomalies",
16
18
  "plot_dataset",
17
19
  "plot_drift",
howso/visuals/graph.py ADDED
@@ -0,0 +1,221 @@
1
+ from collections.abc import Callable, Mapping
2
+ from typing import Any, SupportsInt, TypeAlias
3
+
4
+ import networkx as nx
5
+ import numpy as np
6
+ import plotly.graph_objects as go
7
+ from sklearn.preprocessing import minmax_scale
8
+
9
+ LayoutMapping: TypeAlias = Mapping[Any, tuple[float, float]]
10
+
11
+
12
+ def _create_edge_annotations(
13
+ G: nx.Graph, # noqa: N803
14
+ pos: LayoutMapping,
15
+ edge_attr: str | None = None,
16
+ edge_attr_sigfigs: SupportsInt | None = 4,
17
+ label_edges: bool = True,
18
+ ) -> tuple[list[go.layout.Annotation], list[dict[str, Any]]]:
19
+ # Annotations are created to show the edges between nodes,
20
+ # while invisible shapes with labels are created to label them with the edge weight.
21
+ annotations = []
22
+ shapes = []
23
+ directed = nx.is_directed(G)
24
+
25
+ widths = None
26
+ unscaled_widths = None
27
+ if edge_attr is not None:
28
+ unscaled_widths = [d[edge_attr] for _, _, d in G.edges(data=True)]
29
+ widths = minmax_scale(np.array(unscaled_widths).reshape(-1, 1), (2, 5))
30
+ widths = widths.reshape(-1)
31
+
32
+ edge_blacklist = set()
33
+
34
+ for i, (s, d) in enumerate(G.edges()):
35
+ if (s, d) in edge_blacklist:
36
+ continue
37
+
38
+ x0, y0 = pos[s]
39
+ x1, y1 = pos[d]
40
+ width = widths[i] if widths is not None else 2
41
+
42
+ if directed and G.has_edge(d, s):
43
+ edge_blacklist.add((d, s))
44
+ arrowside = "end+start"
45
+ elif not directed:
46
+ arrowside = "none"
47
+ else:
48
+ arrowside = "end"
49
+
50
+ annotations.append(
51
+ go.layout.Annotation(
52
+ ax=x0,
53
+ ay=y0,
54
+ axref="x",
55
+ ayref="y",
56
+ x=x1,
57
+ y=y1,
58
+ xref="x",
59
+ yref="y",
60
+ showarrow=True,
61
+ arrowhead=4,
62
+ standoff=40.5,
63
+ startstandoff=37.5,
64
+ arrowside=arrowside,
65
+ arrowwidth=width,
66
+ opacity=0.8,
67
+ captureevents=True,
68
+ )
69
+ )
70
+
71
+ if label_edges:
72
+ if edge_attr_sigfigs is not None and unscaled_widths is not None:
73
+ shape_label = f"{round(unscaled_widths[i], edge_attr_sigfigs)}"
74
+ elif unscaled_widths is not None:
75
+ shape_label = f"{unscaled_widths[i]}"
76
+ else:
77
+ shape_label = ""
78
+ else:
79
+ shape_label = ""
80
+
81
+ shape_label = (
82
+ '<span style="text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff;">'
83
+ f"{shape_label}</span>"
84
+ )
85
+
86
+ shapes.append(
87
+ dict(
88
+ type="line",
89
+ x0=x0,
90
+ y0=y0,
91
+ x1=x1,
92
+ y1=y1,
93
+ xref="x",
94
+ yref="y",
95
+ label=dict(text=shape_label),
96
+ opacity=0,
97
+ )
98
+ )
99
+
100
+ return annotations, shapes
101
+
102
+
103
+ def plot_graph(
104
+ G: nx.Graph, # noqa: N803
105
+ *,
106
+ edge_attr_sigfigs: SupportsInt | None = 4,
107
+ edge_attr: str | None = None,
108
+ label_edges: bool = True,
109
+ layout: Callable[[nx.Graph], LayoutMapping] = nx.shell_layout,
110
+ node_color: list[float] | None = None,
111
+ subtitle: str | None = None,
112
+ title: str = "Causal Graph",
113
+ ) -> go.Figure:
114
+ """
115
+ Plot a ``networkx`` graph using `Plotly`.
116
+
117
+ Parameters
118
+ ----------
119
+ G : nx.Graph
120
+ The graph to plot.
121
+ edge_attr : str, optional
122
+ The name of the edge attribute to use when scaling the size of the edges. This should
123
+ be an attribute that is contained within ``G``.
124
+ edge_attr_sigfigs : SupportsInt | None, default 4
125
+ The number of significant figures to round to when labelling each edge. If None, no rounding
126
+ will be performed.
127
+ label_edges : bool, default True
128
+ Whether to label plotted edges.
129
+ layout : Callable[nx.Graph, Mapping[Any, tuple[float, float]]], default nx.shell_layout
130
+ A callable which generates a mapping of nodes to ``(x, y)`` coordinates.
131
+ node_color : list[float], optional
132
+ The data to use when determining the color for each node.
133
+ title : str, default "Causal Graph"
134
+ The title of the plot.
135
+ subtitle : str, optional
136
+ The subtitle of the plot.
137
+
138
+ Returns
139
+ -------
140
+ go.Figure
141
+ The resultant `Plotly` figure.
142
+ """
143
+ pos = layout(G, center=(1, 1))
144
+
145
+ text = []
146
+ node_x = []
147
+ node_y = []
148
+ for node in G.nodes():
149
+ text.append(node)
150
+ x, y = pos[node]
151
+ node_x.append(x)
152
+ node_y.append(y)
153
+
154
+ # This places a 1px black border around the node labels.
155
+ text = [
156
+ f'<span style="text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;">{t}</span>'
157
+ for t in text
158
+ ]
159
+ hovertemplate = "<b>%{text}</b>"
160
+ if node_color is not None:
161
+ hovertemplate += "<br>Destination MIR: %{customdata[0]:.4f}</br>"
162
+
163
+ node_trace = go.Scatter(
164
+ x=node_x,
165
+ y=node_y,
166
+ text=text,
167
+ textposition="middle center",
168
+ mode="markers+text",
169
+ marker=dict(
170
+ color=node_color,
171
+ coloraxis="coloraxis",
172
+ size=75,
173
+ ),
174
+ zorder=999,
175
+ textfont=dict(color="white"),
176
+ name="Nodes",
177
+ customdata=[[x] for x in node_color] if node_color is not None else None,
178
+ hovertemplate=hovertemplate,
179
+ )
180
+
181
+ annotations, shapes = _create_edge_annotations(
182
+ G,
183
+ pos,
184
+ edge_attr=edge_attr,
185
+ edge_attr_sigfigs=edge_attr_sigfigs,
186
+ label_edges=label_edges,
187
+ )
188
+ fig = go.Figure(
189
+ layout=go.Layout(
190
+ title=dict(text="<br>Network graph made with Python", font=dict(size=16)),
191
+ showlegend=False,
192
+ hovermode="closest",
193
+ margin=dict(b=20, l=5, r=5, t=40),
194
+ xaxis=dict(showgrid=False, zeroline=False, showticklabels=False, constrain="domain"),
195
+ yaxis=dict(showgrid=False, zeroline=False, showticklabels=False, constrain="domain"),
196
+ annotations=annotations,
197
+ )
198
+ )
199
+ fig.update_layout(
200
+ coloraxis=dict(
201
+ colorscale="Bluered_r",
202
+ cmin=1,
203
+ cmax=30,
204
+ cmid=15,
205
+ colorbar=dict(
206
+ title="Missing Information Ratio", tickvals=[1, 3, 15, 30], ticktext=["1", "3", "15", "≥30"]
207
+ ),
208
+ reversescale=True,
209
+ ),
210
+ )
211
+
212
+ for s in shapes:
213
+ fig.add_shape(**s)
214
+ fig.add_trace(node_trace)
215
+
216
+ fig.update_layout(
217
+ title=dict(text=title, subtitle=dict(text=subtitle)),
218
+ width=1000,
219
+ height=750,
220
+ )
221
+ return fig
@@ -17,33 +17,27 @@ def iris() -> pd.DataFrame:
17
17
  iris_path = iris_path.resolve()
18
18
 
19
19
  df = pd.read_csv(iris_path / "iris.csv")
20
- df = df.sample(frac=1).reset_index(drop=True)
21
-
22
- yield df
20
+ return df.sample(frac=1).reset_index(drop=True)
23
21
 
24
22
 
25
23
  @pytest.fixture(scope="session")
26
24
  def iris_train(iris) -> pd.DataFrame:
27
- iris_train = iris.truncate(after=75)
28
-
29
- yield iris_train
25
+ return iris.truncate(after=75)
30
26
 
31
27
 
32
28
  @pytest.fixture(scope="session")
33
29
  def iris_test(iris, iris_train) -> pd.DataFrame:
34
- iris_test = iris[~iris.index.isin(iris_train.index)]
35
-
36
- yield iris_test
30
+ return iris[~iris.index.isin(iris_train.index)]
37
31
 
38
32
 
39
33
  @pytest.fixture(scope="session")
40
34
  def iris_features(iris_train) -> FeatureAttributesBase:
41
35
  features = infer_feature_attributes(iris_train)
42
- for _, f_value in features.items():
36
+ for f_value in features.values():
43
37
  if f_value["type"] in ["nominal", "ordinal"]:
44
38
  f_value["non_sensitive"] = True
45
39
 
46
- yield features
40
+ return features
47
41
 
48
42
 
49
43
  @pytest.fixture(scope="session")
@@ -52,4 +46,4 @@ def iris_trainee(iris_train, iris_features) -> Trainee:
52
46
  t.train(iris_train)
53
47
  t.analyze()
54
48
 
55
- yield t
49
+ return t
@@ -0,0 +1,35 @@
1
+ import networkx as nx
2
+ import pytest
3
+
4
+ from howso.visuals.graph import _create_edge_annotations, plot_graph
5
+
6
+
7
+ @pytest.fixture
8
+ def G(): # noqa: N802
9
+ return nx.random_geometric_graph(10, 0.5)
10
+
11
+
12
+ @pytest.fixture
13
+ def pos(G): # noqa: N803
14
+ return nx.shell_layout(G)
15
+
16
+
17
+ def test_create_edge_annotations(G, pos): # noqa: N803
18
+ annotations, shapes = _create_edge_annotations(G, pos)
19
+
20
+ n_edges = len(G.edges())
21
+ assert len(annotations) == n_edges
22
+ assert len(shapes) == n_edges
23
+
24
+
25
+ @pytest.mark.parametrize("layout", [nx.shell_layout, nx.spring_layout])
26
+ @pytest.mark.parametrize("title", ["Causal Graph", "My Causal Graph"])
27
+ @pytest.mark.parametrize("subtitle", ["A subtitle", None])
28
+ def test_plot_graph(G, layout, title, subtitle): # noqa: N803
29
+ fig = plot_graph(G, layout=layout, title=title, subtitle=subtitle)
30
+
31
+ assert fig.layout.title["text"] == title
32
+ if subtitle is not None:
33
+ assert fig.layout.title["subtitle"]["text"] == subtitle
34
+
35
+ assert len(fig.data[-1].x) == len(G.nodes())
@@ -37,9 +37,7 @@ def test_plot_interpretable_prediction_react(
37
37
  react = iris_trainee.react(
38
38
  action_features=[action_feature],
39
39
  contexts=predict_case[context_features],
40
- details={
41
- "influential_cases": True
42
- },
40
+ details={"influential_cases": True},
43
41
  )
44
42
 
45
43
  if do_actual_value:
@@ -62,7 +60,9 @@ def test_plot_interpretable_prediction_react(
62
60
  generative_reacts = None
63
61
 
64
62
  if do_residual:
65
- residual = iris_trainee.get_prediction_stats(details={"prediction_stats": True, "selected_prediction_stats": ["mae"]})
63
+ residual = iris_trainee.get_prediction_stats(
64
+ details={"prediction_stats": True, "selected_prediction_stats": ["mae"]}
65
+ )
66
66
  residual = residual[action_feature].iloc[0]
67
67
  else:
68
68
  residual = None
@@ -125,9 +125,7 @@ def test_plot_dataset(
125
125
  if do_boundary_cases and highlight_cases is not None:
126
126
  context_features = iris_features.get_names(without=["target"])
127
127
  boundary_cases = iris_trainee.react(
128
- contexts=highlight_cases[context_features],
129
- action_features=["target"],
130
- details={"boundary_cases": True}
128
+ contexts=highlight_cases[context_features], action_features=["target"], details={"boundary_cases": True}
131
129
  )
132
130
  boundary_cases = pd.concat(
133
131
  [pd.DataFrame(bcs) for bcs in boundary_cases["details"]["boundary_cases"]]
@@ -141,7 +139,9 @@ def test_plot_dataset(
141
139
  num_expected_traces += 1
142
140
 
143
141
  fig = plot_dataset(
144
- iris_test, x, y,
142
+ iris_test,
143
+ x,
144
+ y,
145
145
  boundary_cases=boundary_cases,
146
146
  most_similar_cases=most_similar_cases,
147
147
  highlight_index=highlight_index,
@@ -157,12 +157,16 @@ def outliers_convictions(iris_trainee, iris_features):
157
157
  iris_trainee.react_into_features(familiarity_conviction_addition=True, distance_contribution=True)
158
158
  outliers = iris_trainee.get_cases(
159
159
  session=iris_trainee.active_session,
160
- features=iris_features.get_names() + [
161
- "familiarity_conviction_addition", ".session_training_index", ".session", "distance_contribution"
162
- ]
160
+ features=[
161
+ *iris_features.get_names(),
162
+ "familiarity_conviction_addition",
163
+ ".session_training_index",
164
+ ".session",
165
+ "distance_contribution",
166
+ ],
163
167
  )
164
168
 
165
- outliers_indices = outliers[['.session', '.session_training_index']].values
169
+ outliers_indices = outliers[[".session", ".session_training_index"]].values
166
170
  convictions = iris_trainee.react(
167
171
  case_indices=outliers_indices,
168
172
  preserve_feature_values=iris_features.get_names(),
@@ -171,20 +175,15 @@ def outliers_convictions(iris_trainee, iris_features):
171
175
  "boundary_cases": True,
172
176
  "influential_cases": True,
173
177
  "feature_full_residual_convictions_for_case": True,
174
- }
175
- )
176
- convictions = pd.DataFrame(
177
- convictions["details"]["feature_full_residual_convictions_for_case"]
178
+ },
178
179
  )
180
+ convictions = pd.DataFrame(convictions["details"]["feature_full_residual_convictions_for_case"])
179
181
 
180
- yield outliers, convictions
182
+ return outliers, convictions
181
183
 
182
184
 
183
185
  @pytest.mark.parametrize("num_cases_to_plot", [1, 5, 10])
184
- def test_plot_anomalies(
185
- outliers_convictions,
186
- num_cases_to_plot
187
- ):
186
+ def test_plot_anomalies(outliers_convictions, num_cases_to_plot):
188
187
  outliers, convictions = outliers_convictions
189
188
  fig = plot_anomalies(outliers, convictions, num_cases_to_plot=num_cases_to_plot)
190
189
  assert len(fig.data[0].y) == num_cases_to_plot
@@ -223,11 +222,11 @@ def test_plot_feature_importances(feature_residuals):
223
222
  @pytest.mark.parametrize("x_tickangle", [True, False, 45])
224
223
  def test_plot_fairness_disparity(x_tickangle):
225
224
  fairness_results = {
226
- 'Dataset1': {'Male': 0.8, 'Female': 0.7, 'Other': 0.9},
227
- 'Dataset2': {'Male': 0.6, 'Female': 0.9, 'Other': 0.5},
228
- 'Dataset3': {'Male': 0.7, 'Female': 0.4, 'Other': 0.6}
225
+ "Dataset1": {"Male": 0.8, "Female": 0.7, "Other": 0.9},
226
+ "Dataset2": {"Male": 0.6, "Female": 0.9, "Other": 0.5},
227
+ "Dataset3": {"Male": 0.7, "Female": 0.4, "Other": 0.6},
229
228
  }
230
- fig = plot_fairness_disparity(fairness_results, reference_class='Male', x_tickangle=x_tickangle)
229
+ fig = plot_fairness_disparity(fairness_results, reference_class="Male", x_tickangle=x_tickangle)
231
230
 
232
231
  assert fig is not None
233
232
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howso-visuals
3
- Version: 2.0.10
3
+ Version: 2.1.1
4
4
  Summary: Visualization utilities for use with Howso Engine.
5
5
  License: GNU AFFERO GENERAL PUBLIC LICENSE
6
6
  Version 3, 19 November 2007
@@ -675,7 +675,8 @@ Requires-Python: >=3.10
675
675
  Description-Content-Type: text/markdown
676
676
  License-File: LICENSE-3RD-PARTY.txt
677
677
  License-File: LICENSE.txt
678
- Requires-Dist: howso-engine~=42.0
678
+ Requires-Dist: howso-engine>=42.0
679
+ Requires-Dist: networkx
679
680
  Requires-Dist: plotly[kaleido]~=6.0
680
681
  Requires-Dist: scipy
681
682
  Requires-Dist: seaborn
@@ -0,0 +1,22 @@
1
+ bin/build.sh,sha256=NUvva4qCMEfYKYGP6_Hxc5f1gItZ_hTJw9NBJjB396E,274
2
+ config/latest-mt-debug-howso.yml,sha256=sUdffc_XSiJZNRoovCYARZ2rQrSzMScNNK2M1uyTA-s,225
3
+ config/latest-mt-howso.yml,sha256=hB6fKQ3_ys_URygFUKl7fiL2vgMZwmpzWU7uwKHzN5E,144
4
+ config/latest-mt-noavx-debug-howso.yml,sha256=x0JuKpy0JzwVeeNsLRYbOo5BVVZnYUCI-ky9Kdqmis4,231
5
+ config/latest-st-debug-howso.yml,sha256=2eZm__DtD3-uszwjRA5ABE6h6gQznSca0-c7Zc_bIGs,226
6
+ config/latest-st-howso.yml,sha256=gfi7VNoAJ8QWh6eVlffks_QLPEYsnoUX7wS6UNx_nKc,145
7
+ config/powershell/Download-Tzdata.ps1,sha256=uGNszw3t3quz1ClN3PWlPr4cKMar9KxxFf4Ws8_JdrM,1505
8
+ config/powershell/Helper-Functions.ps1,sha256=oLEunSYLr-zxtG9kqYuOGG8v3kSxTQEpqeERWQ4jC8I,990
9
+ howso/visuals/__init__.py,sha256=OL9LT4186YIXkEmM4qc21maRnfrtxBmFUHnalcKzGWA,507
10
+ howso/visuals/colors.py,sha256=2ChjT4MUjA4ZqITR_K1j3fUKNRBd8M9iyJ4ZT10cNlw,1709
11
+ howso/visuals/graph.py,sha256=DvBx28IER95HRTEuowuBo1aWWPS7wx3KWrvPZejRnlo,6661
12
+ howso/visuals/visuals.py,sha256=fElgT6lc4KWG9qCY-mUqNL3gsZwcb56YUZJL_QUuMto,30409
13
+ howso/visuals/data/iris.csv,sha256=73iTb6rB42LgZwf89er-tEbuyjlvEAx6WywMPwt0GjU,2757
14
+ howso/visuals/tests/conftest.py,sha256=BcvCVDWbwaQKSstzJzN9G48KoDnCgTtVdgYo2CJZTWM,1293
15
+ howso/visuals/tests/test_graph.py,sha256=gfuJNpsNBLx2tDXDIR-ClbCZUSOQCmk8Dx2X-NhN2yM,1014
16
+ howso/visuals/tests/test_plot.py,sha256=M0YYqDzY4GYmDXcak2QUWn9Zehr5u8pR0SqhxiCUDbY,8111
17
+ howso_visuals-2.1.1.dist-info/licenses/LICENSE-3RD-PARTY.txt,sha256=IZ0jE6Q4mRGPplwo7uW_bQcxm-jBhe8Ol5s-sNphxnw,364089
18
+ howso_visuals-2.1.1.dist-info/licenses/LICENSE.txt,sha256=2xqHuoHohba7gpcZZKtOICRjzeKsQANXG8WoV9V35KM,33893
19
+ howso_visuals-2.1.1.dist-info/METADATA,sha256=OyjRrxKbeK4Iel2raDM2_1j9hcgMzfXY8d2Vw6_joT8,41051
20
+ howso_visuals-2.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ howso_visuals-2.1.1.dist-info/top_level.txt,sha256=4ltSHx7mNsXczuoCPkz1irjq1x1JZir2QrX-ZwRNWXU,22
22
+ howso_visuals-2.1.1.dist-info/RECORD,,
@@ -1,10 +1,10 @@
1
1
  Faker
2
- 37.5.3
2
+ 37.6.0
3
3
  MIT License
4
4
  joke2k
5
5
  https://github.com/joke2k/faker
6
6
  Faker is a Python package that generates fake data for you.
7
- /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/faker-37.5.3.dist-info/licenses/LICENSE.txt
7
+ /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/faker-37.6.0.dist-info/licenses/LICENSE.txt
8
8
  Copyright (c) 2012 Daniele Faraglia
9
9
 
10
10
  Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -243,12 +243,12 @@ SOFTWARE.
243
243
 
244
244
 
245
245
  choreographer
246
- 1.0.9
246
+ 1.0.10
247
247
  UNKNOWN
248
248
  Andrew Pikul <ajpikul@gmail.com>, Neyberson Atencio <neyberatencio@gmail.com>
249
249
  https://github.com/plotly/choreographer
250
250
  Devtools Protocol implementation for chrome.
251
- /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/choreographer-1.0.9.dist-info/licenses/LICENSE.md
251
+ /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/choreographer-1.0.10.dist-info/licenses/LICENSE.md
252
252
  # MIT License
253
253
 
254
254
  Copyright (c) Plotly, Inc.
@@ -608,12 +608,12 @@ A library to handle automated deprecations
608
608
 
609
609
 
610
610
  fonttools
611
- 4.59.1
611
+ 4.59.2
612
612
  MIT
613
613
  Just van Rossum
614
614
  http://github.com/fonttools/fonttools
615
615
  Tools to manipulate font files
616
- /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/fonttools-4.59.1.dist-info/licenses/LICENSE
616
+ /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/fonttools-4.59.2.dist-info/licenses/LICENSE
617
617
  MIT License
618
618
 
619
619
  Copyright (c) 2017 Just van Rossum
@@ -638,12 +638,12 @@ SOFTWARE.
638
638
 
639
639
 
640
640
  humanize
641
- 4.12.3
641
+ 4.13.0
642
642
  UNKNOWN
643
643
  Jason Moiron <jmoiron@jmoiron.net>
644
644
  https://github.com/python-humanize/humanize
645
645
  Python humanize utilities
646
- /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/humanize-4.12.3.dist-info/licenses/LICENCE
646
+ /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/humanize-4.13.0.dist-info/licenses/LICENCE
647
647
  Copyright (c) 2010-2020 Jason Moiron and Contributors
648
648
 
649
649
  Permission is hereby granted, free of charge, to any person obtaining
@@ -707,12 +707,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
707
707
 
708
708
 
709
709
  joblib
710
- 1.5.1
710
+ 1.5.2
711
711
  BSD License
712
712
  Gael Varoquaux <gael.varoquaux@normalesup.org>
713
713
  https://joblib.readthedocs.io
714
714
  Lightweight pipelining with Python functions
715
- /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/joblib-1.5.1.dist-info/licenses/LICENSE.txt
715
+ /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/joblib-1.5.2.dist-info/licenses/LICENSE.txt
716
716
  BSD 3-Clause License
717
717
 
718
718
  Copyright (c) 2008-2021, The joblib developers.
@@ -1160,12 +1160,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1160
1160
  SOFTWARE.
1161
1161
 
1162
1162
  narwhals
1163
- 2.1.2
1163
+ 2.2.0
1164
1164
  MIT License
1165
1165
  Marco Gorelli <hello_narwhals@proton.me>
1166
1166
  https://github.com/narwhals-dev/narwhals
1167
1167
  Extremely lightweight compatibility layer between dataframe libraries
1168
- /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/narwhals-2.1.2.dist-info/licenses/LICENSE.md
1168
+ /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/narwhals-2.2.0.dist-info/licenses/LICENSE.md
1169
1169
  MIT License
1170
1170
 
1171
1171
  Copyright (c) 2024, Marco Gorelli
@@ -1189,6 +1189,52 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1189
1189
  SOFTWARE.
1190
1190
 
1191
1191
 
1192
+ networkx
1193
+ 3.5
1194
+ BSD License
1195
+ Aric Hagberg <hagberg@lanl.gov>
1196
+ https://networkx.org/
1197
+ Python package for creating and manipulating graphs and networks
1198
+ /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/networkx-3.5.dist-info/licenses/LICENSE.txt
1199
+ NetworkX is distributed with the 3-clause BSD license.
1200
+
1201
+ ::
1202
+
1203
+ Copyright (c) 2004-2025, NetworkX Developers
1204
+ Aric Hagberg <hagberg@lanl.gov>
1205
+ Dan Schult <dschult@colgate.edu>
1206
+ Pieter Swart <swart@lanl.gov>
1207
+ All rights reserved.
1208
+
1209
+ Redistribution and use in source and binary forms, with or without
1210
+ modification, are permitted provided that the following conditions are
1211
+ met:
1212
+
1213
+ * Redistributions of source code must retain the above copyright
1214
+ notice, this list of conditions and the following disclaimer.
1215
+
1216
+ * Redistributions in binary form must reproduce the above
1217
+ copyright notice, this list of conditions and the following
1218
+ disclaimer in the documentation and/or other materials provided
1219
+ with the distribution.
1220
+
1221
+ * Neither the name of the NetworkX Developers nor the names of its
1222
+ contributors may be used to endorse or promote products derived
1223
+ from this software without specific prior written permission.
1224
+
1225
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1226
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1227
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1228
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1229
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1230
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1231
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1232
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1233
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1234
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1235
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1236
+
1237
+
1192
1238
  numba
1193
1239
  0.61.2
1194
1240
  BSD License
@@ -2203,12 +2249,12 @@ License: LGPL-2.1-or-later
2203
2249
 
2204
2250
 
2205
2251
  orjson
2206
- 3.11.2
2252
+ 3.11.3
2207
2253
  Apache Software License; MIT License
2208
2254
  UNKNOWN
2209
2255
  https://github.com/ijl/orjson
2210
- UNKNOWN
2211
- /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/orjson-3.11.2.dist-info/licenses/LICENSE-APACHE
2256
+ Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy
2257
+ /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/orjson-3.11.3.dist-info/licenses/LICENSE-APACHE
2212
2258
  Apache License
2213
2259
  Version 2.0, January 2004
2214
2260
  http://www.apache.org/licenses/
@@ -2425,12 +2471,12 @@ under the terms of *both* these licenses.
2425
2471
 
2426
2472
 
2427
2473
  pandas
2428
- 2.3.1
2474
+ 2.3.2
2429
2475
  BSD License
2430
2476
  The Pandas Development Team <pandas-dev@python.org>
2431
2477
  https://pandas.pydata.org
2432
2478
  Powerful data structures for data analysis, time series, and statistics
2433
- /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/pandas-2.3.1.dist-info/LICENSE
2479
+ /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/pandas-2.3.2.dist-info/LICENSE
2434
2480
  BSD 3-Clause License
2435
2481
 
2436
2482
  Copyright (c) 2008-2011, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
@@ -7011,12 +7057,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7011
7057
 
7012
7058
 
7013
7059
  typing_extensions
7014
- 4.14.1
7060
+ 4.15.0
7015
7061
  UNKNOWN
7016
7062
  "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee" <levkivskyi@gmail.com>
7017
7063
  https://github.com/python/typing_extensions
7018
7064
  Backported and Experimental Type Hints for Python 3.9+
7019
- /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/typing_extensions-4.14.1.dist-info/licenses/LICENSE
7065
+ /home/runner/.pyenv/versions/3.13.7/lib/python3.13/site-packages/typing_extensions-4.15.0.dist-info/licenses/LICENSE
7020
7066
  A. HISTORY OF THE SOFTWARE
7021
7067
  ==========================
7022
7068
 
@@ -1,20 +0,0 @@
1
- bin/build.sh,sha256=NUvva4qCMEfYKYGP6_Hxc5f1gItZ_hTJw9NBJjB396E,274
2
- config/latest-mt-debug-howso.yml,sha256=sUdffc_XSiJZNRoovCYARZ2rQrSzMScNNK2M1uyTA-s,225
3
- config/latest-mt-howso.yml,sha256=hB6fKQ3_ys_URygFUKl7fiL2vgMZwmpzWU7uwKHzN5E,144
4
- config/latest-mt-noavx-debug-howso.yml,sha256=x0JuKpy0JzwVeeNsLRYbOo5BVVZnYUCI-ky9Kdqmis4,231
5
- config/latest-st-debug-howso.yml,sha256=2eZm__DtD3-uszwjRA5ABE6h6gQznSca0-c7Zc_bIGs,226
6
- config/latest-st-howso.yml,sha256=gfi7VNoAJ8QWh6eVlffks_QLPEYsnoUX7wS6UNx_nKc,145
7
- config/powershell/Download-Tzdata.ps1,sha256=uGNszw3t3quz1ClN3PWlPr4cKMar9KxxFf4Ws8_JdrM,1505
8
- config/powershell/Helper-Functions.ps1,sha256=oLEunSYLr-zxtG9kqYuOGG8v3kSxTQEpqeERWQ4jC8I,990
9
- howso/visuals/__init__.py,sha256=n6lBHs39jLo1n46-8o8-cI2G-eHSeX5vNSK3fjbGZ_s,474
10
- howso/visuals/colors.py,sha256=2ChjT4MUjA4ZqITR_K1j3fUKNRBd8M9iyJ4ZT10cNlw,1709
11
- howso/visuals/visuals.py,sha256=fElgT6lc4KWG9qCY-mUqNL3gsZwcb56YUZJL_QUuMto,30409
12
- howso/visuals/data/iris.csv,sha256=73iTb6rB42LgZwf89er-tEbuyjlvEAx6WywMPwt0GjU,2757
13
- howso/visuals/tests/conftest.py,sha256=bV0s_LxtJJIzFOUuSI3ybHZIocG6RGP3vHF5V9Qdlh4,1359
14
- howso/visuals/tests/test_plot.py,sha256=W1KQMN3MIeLuTXCIDIZtZBTlIjL-k1wBQ4aKqq42fYo,8090
15
- howso_visuals-2.0.10.dist-info/licenses/LICENSE-3RD-PARTY.txt,sha256=gTrRPD9wYv4ZDA9rQ6o-m_bPglAJkYi2LYw1BnADGFQ,361998
16
- howso_visuals-2.0.10.dist-info/licenses/LICENSE.txt,sha256=2xqHuoHohba7gpcZZKtOICRjzeKsQANXG8WoV9V35KM,33893
17
- howso_visuals-2.0.10.dist-info/METADATA,sha256=bMTzH8pui3c4Yrap6XoqT9YzO7ut6v1yQUrZFvwkGPY,41028
18
- howso_visuals-2.0.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
- howso_visuals-2.0.10.dist-info/top_level.txt,sha256=4ltSHx7mNsXczuoCPkz1irjq1x1JZir2QrX-ZwRNWXU,22
20
- howso_visuals-2.0.10.dist-info/RECORD,,