moderne-visualizations-misc 0.76.0__py3-none-any.whl → 1.0.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.
@@ -31,8 +31,9 @@
31
31
  "# Filter the data frame to only include rows where repositoryWithBranch contain\n",
32
32
  "# a term in the repository_filter (case insensitive)\n",
33
33
  "if len(repository_filter) > 0:\n",
34
- " df = df[df[\"repositoryWithBranch\"].str.contains(\n",
35
- " \"|\".join(repository_filter), case=False)]"
34
+ " df = df[\n",
35
+ " df[\"repositoryWithBranch\"].str.contains(\"|\".join(repository_filter), case=False)\n",
36
+ " ]"
36
37
  ]
37
38
  },
38
39
  {
@@ -145,7 +146,6 @@
145
146
  " color=colors,\n",
146
147
  " customdata=all_nodes,\n",
147
148
  " hovertemplate=\"<b>%{customdata}</b><extra></extra>\",\n",
148
- "\n",
149
149
  " ),\n",
150
150
  " link=dict(\n",
151
151
  " source=source,\n",
@@ -165,13 +165,13 @@
165
165
  " height=max(len(all_nodes) * 10, 500),\n",
166
166
  ")\n",
167
167
  "\n",
168
- "fig.show()\n"
168
+ "fig.show()"
169
169
  ]
170
170
  }
171
171
  ],
172
172
  "metadata": {
173
173
  "kernelspec": {
174
- "display_name": ".python",
174
+ "display_name": "moderne-visualizations-misc",
175
175
  "language": "python",
176
176
  "name": "python3"
177
177
  },
@@ -2,7 +2,7 @@
2
2
  "cells": [
3
3
  {
4
4
  "cell_type": "code",
5
- "execution_count": 1,
5
+ "execution_count": null,
6
6
  "metadata": {
7
7
  "tags": [
8
8
  "parameters"
@@ -19,12 +19,212 @@
19
19
  "execution_count": null,
20
20
  "metadata": {},
21
21
  "outputs": [],
22
- "source": "import pandas as pd\nimport warnings\nimport plotly.graph_objects as go\nimport plotly.express as px\nimport code_data_science.data_table as dt\nimport numpy as np\n\nwarnings.simplefilter(\"ignore\")\n\ndf = dt.read_csv(\"../samples/cyclomatic_complexity.csv\")\n\n# Filter the data frame to only include rows where repositoryPath contains\n# a term in the repository_filter (case insensitive)\nif len(repository_filter) > 0:\n df = df[\n df[\"repositoryPath\"].str.contains(\"|\".join(repository_filter), case=False)\n ]\n\n# Exit early if there are no records and render a plot with a message\nif len(df) == 0:\n fig = go.Figure()\n fig.add_annotation(\n text=\"No data available for the selected repositories\",\n xref=\"paper\",\n yref=\"paper\",\n x=0.5,\n y=0.5,\n showarrow=False,\n font=dict(size=14)\n )\n fig.update_layout(\n xaxis=dict(visible=False),\n yaxis=dict(visible=False),\n margin=dict(l=0, r=0, t=60, b=60),\n title=\"Cyclomatic Complexity Heatmap\"\n )\n fig.show(render=\"plotly_mimetype\")\nelse:\n # Aggregate complexity metrics by repository and class\n class_metrics = df.groupby(['repositoryPath', 'className']).agg({\n 'complexity': ['sum', 'mean', 'max', 'count']\n }).reset_index()\n \n # Flatten column names\n class_metrics.columns = ['repository', 'className', 'total_complexity', 'avg_complexity', 'max_complexity', 'method_count']\n \n # Get short class names for display\n class_metrics['classShortName'] = class_metrics['className'].str.split('.').str[-1]\n \n # Get top N classes by total complexity\n top_classes = class_metrics.nlargest(min(top_n_classes, len(class_metrics)), 'total_complexity')\n \n # Create pivot table for heatmap\n # We'll show different metrics as columns\n metrics_data = []\n for _, row in top_classes.iterrows():\n metrics_data.append({\n 'class': f\"{row['repository'].split('/')[-1]}::{row['classShortName']}\",\n 'metric': 'Total Complexity',\n 'value': row['total_complexity']\n })\n metrics_data.append({\n 'class': f\"{row['repository'].split('/')[-1]}::{row['classShortName']}\",\n 'metric': 'Avg Complexity',\n 'value': row['avg_complexity']\n })\n metrics_data.append({\n 'class': f\"{row['repository'].split('/')[-1]}::{row['classShortName']}\",\n 'metric': 'Max Complexity',\n 'value': row['max_complexity']\n })\n metrics_data.append({\n 'class': f\"{row['repository'].split('/')[-1]}::{row['classShortName']}\",\n 'metric': 'Method Count',\n 'value': row['method_count']\n })\n \n metrics_df = pd.DataFrame(metrics_data)\n pivot_table = metrics_df.pivot(index='class', columns='metric', values='value')\n \n # Reorder columns\n pivot_table = pivot_table[['Method Count', 'Avg Complexity', 'Max Complexity', 'Total Complexity']]\n \n # Sort by total complexity to maintain order\n pivot_table = pivot_table.sort_values('Total Complexity', ascending=False)\n \n # Normalize values for each metric (0-1 scale) for better color representation\n normalized_data = pivot_table.copy()\n for col in normalized_data.columns:\n col_min = normalized_data[col].min()\n col_max = normalized_data[col].max()\n if col_max > col_min:\n normalized_data[col] = (normalized_data[col] - col_min) / (col_max - col_min)\n \n # Create custom hover text\n hover_text = []\n for i in range(len(pivot_table)):\n hover_row = []\n for j, col in enumerate(pivot_table.columns):\n value = pivot_table.iloc[i, j]\n if col == 'Avg Complexity':\n hover_row.append(f\"{col}: {value:.1f}\")\n else:\n hover_row.append(f\"{col}: {int(value)}\")\n hover_text.append(hover_row)\n \n # Create the heatmap\n fig = go.Figure(data=go.Heatmap(\n z=normalized_data.values,\n x=normalized_data.columns,\n y=normalized_data.index,\n colorscale=[\n [0, '#E8F5E9'],\n [0.2, '#A5D6A7'],\n [0.4, '#FFE082'],\n [0.6, '#FFB74D'],\n [0.8, '#FF8A65'],\n [1, '#EF5350']\n ],\n colorbar=dict(\n title=\"Normalized<br>Complexity\",\n thickness=15,\n len=0.7\n ),\n text=hover_text,\n texttemplate=\"\",\n hovertemplate=(\n '<b>%{y}</b><br>' +\n '%{text}' +\n '<extra></extra>'\n )\n ))\n \n # Add text annotations for actual values\n annotations = []\n for i in range(len(pivot_table)):\n for j, col in enumerate(pivot_table.columns):\n value = pivot_table.iloc[i, j]\n if col == 'Avg Complexity':\n text = f\"{value:.1f}\"\n else:\n text = str(int(value))\n \n annotations.append(\n go.layout.Annotation(\n text=text,\n x=j,\n y=i,\n xref=\"x\",\n yref=\"y\",\n showarrow=False,\n font=dict(\n size=10,\n color=\"black\" if normalized_data.iloc[i, j] < 0.6 else \"white\"\n )\n )\n )\n \n # Update layout\n fig.update_layout(\n title=dict(\n text=f\"Cyclomatic Complexity Heatmap by Class<br><sub>Top {len(pivot_table)} classes by total complexity</sub>\",\n font=dict(size=16)\n ),\n xaxis=dict(\n title=\"Complexity Metrics\",\n tickfont=dict(size=12),\n showgrid=False,\n side=\"bottom\"\n ),\n yaxis=dict(\n title=\"Repository::Class\",\n tickfont=dict(size=10),\n showgrid=False,\n autorange=\"reversed\" # Put highest complexity at top\n ),\n annotations=annotations,\n margin=dict(l=250, r=50, t=100, b=80),\n height=max(600, len(pivot_table) * 25 + 200),\n plot_bgcolor='white'\n )\n \n # Show the figure\n fig.show(render=\"plotly_mimetype\")"
22
+ "source": [
23
+ "import pandas as pd\n",
24
+ "import warnings\n",
25
+ "import plotly.graph_objects as go\n",
26
+ "import plotly.express as px\n",
27
+ "import code_data_science.data_table as dt\n",
28
+ "import numpy as np\n",
29
+ "\n",
30
+ "warnings.simplefilter(\"ignore\")\n",
31
+ "\n",
32
+ "df = dt.read_csv(\"../samples/cyclomatic_complexity.csv\")\n",
33
+ "\n",
34
+ "# Filter the data frame to only include rows where repositoryPath contains\n",
35
+ "# a term in the repository_filter (case insensitive)\n",
36
+ "if len(repository_filter) > 0:\n",
37
+ " df = df[df[\"repositoryPath\"].str.contains(\"|\".join(repository_filter), case=False)]\n",
38
+ "\n",
39
+ "# Exit early if there are no records and render a plot with a message\n",
40
+ "if len(df) == 0:\n",
41
+ " fig = go.Figure()\n",
42
+ " fig.add_annotation(\n",
43
+ " text=\"No data available for the selected repositories\",\n",
44
+ " xref=\"paper\",\n",
45
+ " yref=\"paper\",\n",
46
+ " x=0.5,\n",
47
+ " y=0.5,\n",
48
+ " showarrow=False,\n",
49
+ " font=dict(size=14),\n",
50
+ " )\n",
51
+ " fig.update_layout(\n",
52
+ " xaxis=dict(visible=False),\n",
53
+ " yaxis=dict(visible=False),\n",
54
+ " margin=dict(l=0, r=0, t=60, b=60),\n",
55
+ " title=\"Cyclomatic Complexity Heatmap\",\n",
56
+ " )\n",
57
+ " fig.show(render=\"plotly_mimetype\")\n",
58
+ "else:\n",
59
+ " # Aggregate complexity metrics by repository and class\n",
60
+ " class_metrics = (\n",
61
+ " df.groupby([\"repositoryPath\", \"className\"])\n",
62
+ " .agg({\"complexity\": [\"sum\", \"mean\", \"max\", \"count\"]})\n",
63
+ " .reset_index()\n",
64
+ " )\n",
65
+ "\n",
66
+ " # Flatten column names\n",
67
+ " class_metrics.columns = [\n",
68
+ " \"repository\",\n",
69
+ " \"className\",\n",
70
+ " \"total_complexity\",\n",
71
+ " \"avg_complexity\",\n",
72
+ " \"max_complexity\",\n",
73
+ " \"method_count\",\n",
74
+ " ]\n",
75
+ "\n",
76
+ " # Get short class names for display\n",
77
+ " class_metrics[\"classShortName\"] = class_metrics[\"className\"].str.split(\".\").str[-1]\n",
78
+ "\n",
79
+ " # Get top N classes by total complexity\n",
80
+ " top_classes = class_metrics.nlargest(\n",
81
+ " min(top_n_classes, len(class_metrics)), \"total_complexity\"\n",
82
+ " )\n",
83
+ "\n",
84
+ " # Create pivot table for heatmap\n",
85
+ " # We'll show different metrics as columns\n",
86
+ " metrics_data = []\n",
87
+ " for _, row in top_classes.iterrows():\n",
88
+ " metrics_data.append(\n",
89
+ " {\n",
90
+ " \"class\": f\"{row['repository'].split('/')[-1]}::{row['classShortName']}\",\n",
91
+ " \"metric\": \"Total Complexity\",\n",
92
+ " \"value\": row[\"total_complexity\"],\n",
93
+ " }\n",
94
+ " )\n",
95
+ " metrics_data.append(\n",
96
+ " {\n",
97
+ " \"class\": f\"{row['repository'].split('/')[-1]}::{row['classShortName']}\",\n",
98
+ " \"metric\": \"Avg Complexity\",\n",
99
+ " \"value\": row[\"avg_complexity\"],\n",
100
+ " }\n",
101
+ " )\n",
102
+ " metrics_data.append(\n",
103
+ " {\n",
104
+ " \"class\": f\"{row['repository'].split('/')[-1]}::{row['classShortName']}\",\n",
105
+ " \"metric\": \"Max Complexity\",\n",
106
+ " \"value\": row[\"max_complexity\"],\n",
107
+ " }\n",
108
+ " )\n",
109
+ " metrics_data.append(\n",
110
+ " {\n",
111
+ " \"class\": f\"{row['repository'].split('/')[-1]}::{row['classShortName']}\",\n",
112
+ " \"metric\": \"Method Count\",\n",
113
+ " \"value\": row[\"method_count\"],\n",
114
+ " }\n",
115
+ " )\n",
116
+ "\n",
117
+ " metrics_df = pd.DataFrame(metrics_data)\n",
118
+ " pivot_table = metrics_df.pivot(index=\"class\", columns=\"metric\", values=\"value\")\n",
119
+ "\n",
120
+ " # Reorder columns\n",
121
+ " pivot_table = pivot_table[\n",
122
+ " [\"Method Count\", \"Avg Complexity\", \"Max Complexity\", \"Total Complexity\"]\n",
123
+ " ]\n",
124
+ "\n",
125
+ " # Sort by total complexity to maintain order\n",
126
+ " pivot_table = pivot_table.sort_values(\"Total Complexity\", ascending=False)\n",
127
+ "\n",
128
+ " # Normalize values for each metric (0-1 scale) for better color representation\n",
129
+ " normalized_data = pivot_table.copy()\n",
130
+ " for col in normalized_data.columns:\n",
131
+ " col_min = normalized_data[col].min()\n",
132
+ " col_max = normalized_data[col].max()\n",
133
+ " if col_max > col_min:\n",
134
+ " normalized_data[col] = (normalized_data[col] - col_min) / (\n",
135
+ " col_max - col_min\n",
136
+ " )\n",
137
+ "\n",
138
+ " # Create custom hover text\n",
139
+ " hover_text = []\n",
140
+ " for i in range(len(pivot_table)):\n",
141
+ " hover_row = []\n",
142
+ " for j, col in enumerate(pivot_table.columns):\n",
143
+ " value = pivot_table.iloc[i, j]\n",
144
+ " if col == \"Avg Complexity\":\n",
145
+ " hover_row.append(f\"{col}: {value:.1f}\")\n",
146
+ " else:\n",
147
+ " hover_row.append(f\"{col}: {int(value)}\")\n",
148
+ " hover_text.append(hover_row)\n",
149
+ "\n",
150
+ " # Create the heatmap\n",
151
+ " fig = go.Figure(\n",
152
+ " data=go.Heatmap(\n",
153
+ " z=normalized_data.values,\n",
154
+ " x=normalized_data.columns,\n",
155
+ " y=normalized_data.index,\n",
156
+ " colorscale=[\n",
157
+ " [0, \"#E8F5E9\"],\n",
158
+ " [0.2, \"#A5D6A7\"],\n",
159
+ " [0.4, \"#FFE082\"],\n",
160
+ " [0.6, \"#FFB74D\"],\n",
161
+ " [0.8, \"#FF8A65\"],\n",
162
+ " [1, \"#EF5350\"],\n",
163
+ " ],\n",
164
+ " colorbar=dict(title=\"Normalized<br>Complexity\", thickness=15, len=0.7),\n",
165
+ " text=hover_text,\n",
166
+ " texttemplate=\"\",\n",
167
+ " hovertemplate=(\"<b>%{y}</b><br>\" + \"%{text}\" + \"<extra></extra>\"),\n",
168
+ " )\n",
169
+ " )\n",
170
+ "\n",
171
+ " # Add text annotations for actual values\n",
172
+ " annotations = []\n",
173
+ " for i in range(len(pivot_table)):\n",
174
+ " for j, col in enumerate(pivot_table.columns):\n",
175
+ " value = pivot_table.iloc[i, j]\n",
176
+ " if col == \"Avg Complexity\":\n",
177
+ " text = f\"{value:.1f}\"\n",
178
+ " else:\n",
179
+ " text = str(int(value))\n",
180
+ "\n",
181
+ " annotations.append(\n",
182
+ " go.layout.Annotation(\n",
183
+ " text=text,\n",
184
+ " x=j,\n",
185
+ " y=i,\n",
186
+ " xref=\"x\",\n",
187
+ " yref=\"y\",\n",
188
+ " showarrow=False,\n",
189
+ " font=dict(\n",
190
+ " size=10,\n",
191
+ " color=\"black\" if normalized_data.iloc[i, j] < 0.6 else \"white\",\n",
192
+ " ),\n",
193
+ " )\n",
194
+ " )\n",
195
+ "\n",
196
+ " # Update layout\n",
197
+ " fig.update_layout(\n",
198
+ " title=dict(\n",
199
+ " text=f\"Cyclomatic Complexity Heatmap by Class<br><sub>Top {len(pivot_table)} classes by total complexity</sub>\",\n",
200
+ " font=dict(size=16),\n",
201
+ " ),\n",
202
+ " xaxis=dict(\n",
203
+ " title=\"Complexity Metrics\",\n",
204
+ " tickfont=dict(size=12),\n",
205
+ " showgrid=False,\n",
206
+ " side=\"bottom\",\n",
207
+ " ),\n",
208
+ " yaxis=dict(\n",
209
+ " title=\"Repository::Class\",\n",
210
+ " tickfont=dict(size=10),\n",
211
+ " showgrid=False,\n",
212
+ " autorange=\"reversed\", # Put highest complexity at top\n",
213
+ " ),\n",
214
+ " annotations=annotations,\n",
215
+ " margin=dict(l=250, r=50, t=100, b=80),\n",
216
+ " height=max(600, len(pivot_table) * 25 + 200),\n",
217
+ " plot_bgcolor=\"white\",\n",
218
+ " )\n",
219
+ "\n",
220
+ " # Show the figure\n",
221
+ " fig.show(render=\"plotly_mimetype\")"
222
+ ]
23
223
  }
24
224
  ],
25
225
  "metadata": {
26
226
  "kernelspec": {
27
- "display_name": ".python",
227
+ "display_name": "moderne-visualizations-misc",
28
228
  "language": "python",
29
229
  "name": "python3"
30
230
  },
@@ -43,4 +243,4 @@
43
243
  },
44
244
  "nbformat": 4,
45
245
  "nbformat_minor": 4
46
- }
246
+ }
@@ -1840,9 +1840,7 @@
1840
1840
  "# Filter the data frame to only include rows where repositoryPath contains\n",
1841
1841
  "# a term in the repository_filter (case insensitive)\n",
1842
1842
  "if len(repository_filter) > 0:\n",
1843
- " df = df[\n",
1844
- " df[\"repositoryPath\"].str.contains(\"|\".join(repository_filter), case=False)\n",
1845
- " ]\n",
1843
+ " df = df[df[\"repositoryPath\"].str.contains(\"|\".join(repository_filter), case=False)]\n",
1846
1844
  "\n",
1847
1845
  "# Exit early if there are no records and render a plot with a message\n",
1848
1846
  "if len(df) == 0:\n",
@@ -1854,86 +1852,95 @@
1854
1852
  " x=0.5,\n",
1855
1853
  " y=0.5,\n",
1856
1854
  " showarrow=False,\n",
1857
- " font=dict(size=14)\n",
1855
+ " font=dict(size=14),\n",
1858
1856
  " )\n",
1859
1857
  " fig.update_layout(\n",
1860
1858
  " xaxis=dict(visible=False),\n",
1861
1859
  " yaxis=dict(visible=False),\n",
1862
1860
  " margin=dict(l=0, r=0, t=60, b=60),\n",
1863
- " title=\"Cyclomatic Complexity Risk Matrix\"\n",
1861
+ " title=\"Cyclomatic Complexity Risk Matrix\",\n",
1864
1862
  " )\n",
1865
1863
  " fig.show(render=\"plotly_mimetype\")\n",
1866
1864
  "else:\n",
1867
1865
  " # Calculate metrics for each repository\n",
1868
- " repo_metrics = df.groupby('repositoryPath').agg({\n",
1869
- " 'complexity': ['mean', 'count', lambda x: (x >= complexity_threshold).sum()]\n",
1870
- " }).reset_index()\n",
1871
- " \n",
1866
+ " repo_metrics = (\n",
1867
+ " df.groupby(\"repositoryPath\")\n",
1868
+ " .agg(\n",
1869
+ " {\n",
1870
+ " \"complexity\": [\n",
1871
+ " \"mean\",\n",
1872
+ " \"count\",\n",
1873
+ " lambda x: (x >= complexity_threshold).sum(),\n",
1874
+ " ]\n",
1875
+ " }\n",
1876
+ " )\n",
1877
+ " .reset_index()\n",
1878
+ " )\n",
1879
+ "\n",
1872
1880
  " # Flatten column names\n",
1873
- " repo_metrics.columns = ['repository', 'avg_complexity', 'total_methods', 'high_complexity_methods']\n",
1874
- " \n",
1881
+ " repo_metrics.columns = [\n",
1882
+ " \"repository\",\n",
1883
+ " \"avg_complexity\",\n",
1884
+ " \"total_methods\",\n",
1885
+ " \"high_complexity_methods\",\n",
1886
+ " ]\n",
1887
+ "\n",
1875
1888
  " # Count unique classes per repository for bubble size\n",
1876
- " classes_per_repo = df.groupby('repositoryPath')['className'].nunique().reset_index()\n",
1877
- " classes_per_repo.columns = ['repository', 'num_classes']\n",
1878
- " \n",
1889
+ " classes_per_repo = df.groupby(\"repositoryPath\")[\"className\"].nunique().reset_index()\n",
1890
+ " classes_per_repo.columns = [\"repository\", \"num_classes\"]\n",
1891
+ "\n",
1879
1892
  " # Merge the metrics\n",
1880
- " repo_metrics = repo_metrics.merge(classes_per_repo, on='repository')\n",
1881
- " \n",
1893
+ " repo_metrics = repo_metrics.merge(classes_per_repo, on=\"repository\")\n",
1894
+ "\n",
1882
1895
  " # Create the scatter plot\n",
1883
1896
  " fig = go.Figure()\n",
1884
- " \n",
1897
+ "\n",
1885
1898
  " # Add scatter trace\n",
1886
- " fig.add_trace(go.Scatter(\n",
1887
- " x=repo_metrics['high_complexity_methods'],\n",
1888
- " y=repo_metrics['avg_complexity'],\n",
1889
- " mode='markers',\n",
1890
- " marker=dict(\n",
1891
- " size=repo_metrics['num_classes'],\n",
1892
- " sizemode='area',\n",
1893
- " sizeref=2.*max(repo_metrics['num_classes'])/(100.**2),\n",
1894
- " sizemin=4,\n",
1895
- " color=repo_metrics['high_complexity_methods'],\n",
1896
- " colorscale='YlOrRd',\n",
1897
- " showscale=True,\n",
1898
- " colorbar=dict(\n",
1899
- " title=\"High Complexity<br>Methods\",\n",
1900
- " thickness=15,\n",
1901
- " len=0.7\n",
1902
- " )\n",
1903
- " ),\n",
1904
- " text=repo_metrics['repository'],\n",
1905
- " customdata=repo_metrics[['total_methods', 'num_classes']],\n",
1906
- " hovertemplate=(\n",
1907
- " '<b>%{text}</b><br>' +\n",
1908
- " 'Average Complexity: %{y:.2f}<br>' +\n",
1909
- " 'High Complexity Methods: %{x}<br>' +\n",
1910
- " 'Total Methods: %{customdata[0]}<br>' +\n",
1911
- " 'Number of Classes: %{customdata[1]}' +\n",
1912
- " '<extra></extra>'\n",
1899
+ " fig.add_trace(\n",
1900
+ " go.Scatter(\n",
1901
+ " x=repo_metrics[\"high_complexity_methods\"],\n",
1902
+ " y=repo_metrics[\"avg_complexity\"],\n",
1903
+ " mode=\"markers\",\n",
1904
+ " marker=dict(\n",
1905
+ " size=repo_metrics[\"num_classes\"],\n",
1906
+ " sizemode=\"area\",\n",
1907
+ " sizeref=2.0 * max(repo_metrics[\"num_classes\"]) / (100.0**2),\n",
1908
+ " sizemin=4,\n",
1909
+ " color=repo_metrics[\"high_complexity_methods\"],\n",
1910
+ " colorscale=\"YlOrRd\",\n",
1911
+ " showscale=True,\n",
1912
+ " colorbar=dict(\n",
1913
+ " title=\"High Complexity<br>Methods\", thickness=15, len=0.7\n",
1914
+ " ),\n",
1915
+ " ),\n",
1916
+ " text=repo_metrics[\"repository\"],\n",
1917
+ " customdata=repo_metrics[[\"total_methods\", \"num_classes\"]],\n",
1918
+ " hovertemplate=(\n",
1919
+ " \"<b>%{text}</b><br>\"\n",
1920
+ " + \"Average Complexity: %{y:.2f}<br>\"\n",
1921
+ " + \"High Complexity Methods: %{x}<br>\"\n",
1922
+ " + \"Total Methods: %{customdata[0]}<br>\"\n",
1923
+ " + \"Number of Classes: %{customdata[1]}\"\n",
1924
+ " + \"<extra></extra>\"\n",
1925
+ " ),\n",
1913
1926
  " )\n",
1914
- " ))\n",
1915
- " \n",
1927
+ " )\n",
1928
+ "\n",
1916
1929
  " # Add quadrant lines\n",
1917
1930
  " # Calculate median values for quadrant boundaries\n",
1918
- " median_high_complexity = repo_metrics['high_complexity_methods'].median()\n",
1919
- " median_avg_complexity = repo_metrics['avg_complexity'].median()\n",
1920
- " \n",
1931
+ " median_high_complexity = repo_metrics[\"high_complexity_methods\"].median()\n",
1932
+ " median_avg_complexity = repo_metrics[\"avg_complexity\"].median()\n",
1933
+ "\n",
1921
1934
  " # Add vertical line at median high complexity methods\n",
1922
1935
  " fig.add_vline(\n",
1923
- " x=median_high_complexity,\n",
1924
- " line_dash=\"dash\",\n",
1925
- " line_color=\"gray\",\n",
1926
- " opacity=0.5\n",
1936
+ " x=median_high_complexity, line_dash=\"dash\", line_color=\"gray\", opacity=0.5\n",
1927
1937
  " )\n",
1928
- " \n",
1938
+ "\n",
1929
1939
  " # Add horizontal line at median average complexity\n",
1930
1940
  " fig.add_hline(\n",
1931
- " y=median_avg_complexity,\n",
1932
- " line_dash=\"dash\",\n",
1933
- " line_color=\"gray\",\n",
1934
- " opacity=0.5\n",
1941
+ " y=median_avg_complexity, line_dash=\"dash\", line_color=\"gray\", opacity=0.5\n",
1935
1942
  " )\n",
1936
- " \n",
1943
+ "\n",
1937
1944
  " # Add quadrant labels\n",
1938
1945
  " annotations = [\n",
1939
1946
  " # High Risk (top right)\n",
@@ -1946,7 +1953,7 @@
1946
1953
  " showarrow=False,\n",
1947
1954
  " bgcolor=\"rgba(255,0,0,0.1)\",\n",
1948
1955
  " borderpad=4,\n",
1949
- " font=dict(size=10)\n",
1956
+ " font=dict(size=10),\n",
1950
1957
  " ),\n",
1951
1958
  " # Systemic Complexity (top left)\n",
1952
1959
  " dict(\n",
@@ -1958,7 +1965,7 @@
1958
1965
  " showarrow=False,\n",
1959
1966
  " bgcolor=\"rgba(255,165,0,0.1)\",\n",
1960
1967
  " borderpad=4,\n",
1961
- " font=dict(size=10)\n",
1968
+ " font=dict(size=10),\n",
1962
1969
  " ),\n",
1963
1970
  " # Localized Issues (bottom right)\n",
1964
1971
  " dict(\n",
@@ -1970,7 +1977,7 @@
1970
1977
  " showarrow=False,\n",
1971
1978
  " bgcolor=\"rgba(255,255,0,0.1)\",\n",
1972
1979
  " borderpad=4,\n",
1973
- " font=dict(size=10)\n",
1980
+ " font=dict(size=10),\n",
1974
1981
  " ),\n",
1975
1982
  " # Low Risk (bottom left)\n",
1976
1983
  " dict(\n",
@@ -1982,36 +1989,38 @@
1982
1989
  " showarrow=False,\n",
1983
1990
  " bgcolor=\"rgba(0,255,0,0.1)\",\n",
1984
1991
  " borderpad=4,\n",
1985
- " font=dict(size=10)\n",
1986
- " )\n",
1992
+ " font=dict(size=10),\n",
1993
+ " ),\n",
1987
1994
  " ]\n",
1988
- " \n",
1995
+ "\n",
1989
1996
  " # Update layout\n",
1990
1997
  " fig.update_layout(\n",
1991
1998
  " title=dict(\n",
1992
1999
  " text=f\"Cyclomatic Complexity Risk Matrix<br><sub>Bubble size represents number of classes | Threshold: {complexity_threshold}</sub>\",\n",
1993
- " font=dict(size=16)\n",
2000
+ " font=dict(size=16),\n",
1994
2001
  " ),\n",
1995
2002
  " xaxis=dict(\n",
1996
- " title=\"Number of High Complexity Methods (≥\" + str(complexity_threshold) + \")\",\n",
1997
- " gridcolor='rgba(128,128,128,0.2)',\n",
2003
+ " title=\"Number of High Complexity Methods (≥\"\n",
2004
+ " + str(complexity_threshold)\n",
2005
+ " + \")\",\n",
2006
+ " gridcolor=\"rgba(128,128,128,0.2)\",\n",
1998
2007
  " showgrid=True,\n",
1999
2008
  " zeroline=True,\n",
2000
- " zerolinecolor='rgba(128,128,128,0.2)'\n",
2009
+ " zerolinecolor=\"rgba(128,128,128,0.2)\",\n",
2001
2010
  " ),\n",
2002
2011
  " yaxis=dict(\n",
2003
2012
  " title=\"Average Complexity per Repository\",\n",
2004
- " gridcolor='rgba(128,128,128,0.2)',\n",
2013
+ " gridcolor=\"rgba(128,128,128,0.2)\",\n",
2005
2014
  " showgrid=True,\n",
2006
2015
  " zeroline=True,\n",
2007
- " zerolinecolor='rgba(128,128,128,0.2)'\n",
2016
+ " zerolinecolor=\"rgba(128,128,128,0.2)\",\n",
2008
2017
  " ),\n",
2009
2018
  " margin=dict(l=60, r=120, t=100, b=60),\n",
2010
- " plot_bgcolor='white',\n",
2019
+ " plot_bgcolor=\"white\",\n",
2011
2020
  " annotations=annotations,\n",
2012
- " hovermode='closest'\n",
2021
+ " hovermode=\"closest\",\n",
2013
2022
  " )\n",
2014
- " \n",
2023
+ "\n",
2015
2024
  " # Show the figure\n",
2016
2025
  " fig.show(render=\"plotly_mimetype\")"
2017
2026
  ]
@@ -152,7 +152,7 @@
152
152
  "name": "python",
153
153
  "nbconvert_exporter": "python",
154
154
  "pygments_lexer": "ipython3",
155
- "version": "3.12.11"
155
+ "version": "3.12.8"
156
156
  }
157
157
  },
158
158
  "nbformat": 4,