likelihood 2.2.0.dev1__cp311-cp311-manylinux_2_28_x86_64.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.
@@ -0,0 +1,375 @@
1
+ import datetime
2
+ from html import escape
3
+ from typing import Any
4
+
5
+ from IPython.display import HTML, display
6
+
7
+
8
+ def generate_html_pipeline(
9
+ data_dict: Any,
10
+ save_to_file: bool = False,
11
+ file_name: str = "data_processing_report_improved.html",
12
+ ):
13
+ """
14
+ Generates an HTML report for a data processing pipeline with an improved
15
+ layout using a tabbed interface to reduce vertical scroll.
16
+ """
17
+ css_js = """
18
+ <style>
19
+ /* Existing Styles (omitted for brevity, keep the original content) */
20
+ :root {
21
+ --primary: #0d9488;
22
+ --primary-dark: #0f766e;
23
+ --success: #10b981;
24
+ --accent: #3b82f6;
25
+ --card-bg: #ffffff;
26
+ --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.03);
27
+ --border-radius-md: 8px;
28
+ --font-family: 'Roboto', sans-serif;
29
+ }
30
+
31
+ * {
32
+ box-sizing: border-box;
33
+ }
34
+
35
+ body {
36
+ font-family: var(--font-family);
37
+ background: #f8fafc;
38
+ color: #1e293b;
39
+ margin: 0;
40
+ padding: 1.5rem;
41
+ font-size: 14px;
42
+ }
43
+
44
+ h2 {
45
+ background: linear-gradient(135deg, var(--primary), var(--primary-dark));
46
+ color: white;
47
+ text-align: center;
48
+ padding: 1.2rem;
49
+ border-radius: var(--border-radius-md);
50
+ font-weight: 700;
51
+ font-size: 2rem;
52
+ margin-bottom: 2rem;
53
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
54
+ }
55
+
56
+ section {
57
+ background: var(--card-bg);
58
+ border-radius: var(--border-radius-md);
59
+ padding: 1.5rem;
60
+ box-shadow: var(--shadow-sm);
61
+ margin-bottom: 2rem;
62
+ }
63
+
64
+ h3 {
65
+ color: var(--primary-dark);
66
+ font-weight: 600;
67
+ font-size: 1.4rem;
68
+ border-left: 5px solid var(--success);
69
+ padding-left: 1rem;
70
+ margin-bottom: 1rem;
71
+ transition: color 0.3s ease;
72
+ }
73
+
74
+ h3:hover {
75
+ color: var(--primary);
76
+ }
77
+
78
+ table {
79
+ width: 100%;
80
+ border-collapse: collapse;
81
+ font-size: 14px;
82
+ margin: 1rem 0;
83
+ }
84
+
85
+ th, td {
86
+ padding: 0.8rem 1rem;
87
+ text-align: left;
88
+ border-bottom: 1px solid #e2e8f0;
89
+ vertical-align: top;
90
+ }
91
+
92
+ thead {
93
+ background-color: #f0fdf4;
94
+ }
95
+
96
+ tbody tr:nth-child(odd) {
97
+ background-color: #f9fafb;
98
+ }
99
+
100
+ tbody tr:hover {
101
+ background-color: #e0f2fe;
102
+ }
103
+
104
+ .nested-table {
105
+ font-size: 12px;
106
+ margin-top: 0.8rem;
107
+ }
108
+
109
+ details {
110
+ margin-bottom: 1rem;
111
+ padding: 0.8rem;
112
+ background: #f9f9f9;
113
+ border-radius: var(--border-radius-md);
114
+ transition: background 0.3s ease;
115
+ }
116
+
117
+ details[open] {
118
+ background: #f0fdf4;
119
+ }
120
+
121
+ summary {
122
+ font-weight: 700;
123
+ font-size: 1.1rem;
124
+ color: var(--primary-dark);
125
+ cursor: pointer;
126
+ list-style: none; /* Hide default marker */
127
+ transition: color 0.3s ease;
128
+ }
129
+
130
+ summary::-webkit-details-marker {
131
+ display: none; /* For Chrome/Safari */
132
+ }
133
+
134
+ summary::before {
135
+ content: "▶";
136
+ margin-right: 6px;
137
+ color: var(--success);
138
+ font-size: 1rem;
139
+ display: inline-block;
140
+ transition: transform 0.2s;
141
+ }
142
+
143
+ details[open] summary::before {
144
+ content: "▼";
145
+ }
146
+
147
+ summary:hover {
148
+ color: var(--primary);
149
+ }
150
+
151
+ .tabbed-interface {
152
+ display: flex;
153
+ flex-direction: column;
154
+ background: var(--card-bg);
155
+ border-radius: var(--border-radius-md);
156
+ box-shadow: var(--shadow-sm);
157
+ padding: 0;
158
+ margin-bottom: 2rem;
159
+ }
160
+
161
+ .tab-buttons {
162
+ display: flex;
163
+ border-bottom: 2px solid #e2e8f0;
164
+ flex-wrap: wrap; /* Allows wrapping on smaller screens */
165
+ }
166
+
167
+ .tab-button {
168
+ padding: 1rem 1.5rem;
169
+ cursor: pointer;
170
+ border: none;
171
+ background: transparent;
172
+ font-weight: 600;
173
+ color: #475569;
174
+ font-size: 1rem;
175
+ transition: color 0.3s, border-bottom 0.3s;
176
+ flex-grow: 1; /* Makes buttons take up equal space */
177
+ text-align: center;
178
+ }
179
+
180
+ .tab-button.active, .tab-button:hover {
181
+ color: var(--primary);
182
+ border-bottom: 3px solid var(--primary);
183
+ }
184
+
185
+ .tab-content {
186
+ padding: 1.5rem;
187
+ }
188
+
189
+ .tab-pane {
190
+ display: none;
191
+ }
192
+
193
+ .tab-pane.active {
194
+ display: block;
195
+ }
196
+
197
+ /* --- END NEW TABBED LAYOUT STYLES --- */
198
+
199
+ @media (max-width: 768px) {
200
+ body {
201
+ font-size: 13px;
202
+ }
203
+
204
+ h2 {
205
+ font-size: 1.6rem;
206
+ padding: 1rem;
207
+ }
208
+
209
+ h3 {
210
+ font-size: 1.3rem;
211
+ }
212
+
213
+ table, .nested-table {
214
+ font-size: 12px;
215
+ }
216
+
217
+ section {
218
+ padding: 1rem;
219
+ }
220
+
221
+ .tab-button {
222
+ padding: 0.8rem 1rem;
223
+ font-size: 0.9rem;
224
+ }
225
+ }
226
+ </style>
227
+ <script>
228
+ function openTab(evt, tabName) {
229
+ var i, tabcontent, tablinks;
230
+ tabcontent = document.getElementsByClassName("tab-pane");
231
+ for (i = 0; i < tabcontent.length; i++) {
232
+ tabcontent[i].style.display = "none";
233
+ tabcontent[i].classList.remove("active");
234
+ }
235
+ tablinks = document.getElementsByClassName("tab-button");
236
+ for (i = 0; i < tablinks.length; i++) {
237
+ tablinks[i].classList.remove("active");
238
+ }
239
+ document.getElementById(tabName).style.display = "block";
240
+ document.getElementById(tabName).classList.add("active");
241
+ evt.currentTarget.classList.add("active");
242
+ // Scroll to the top of the tabbed interface container
243
+ document.querySelector('.tabbed-interface').scrollIntoView({ behavior: 'smooth', block: 'start' });
244
+ }
245
+
246
+ // Set 'Initial Dataset' as the default active tab on load
247
+ window.onload = function() {
248
+ document.querySelector('.tab-button').click();
249
+ };
250
+ </script>
251
+ """
252
+
253
+ def render_value(val):
254
+ if isinstance(val, dict):
255
+ return dict_to_table(val, nested=True)
256
+ elif isinstance(val, list):
257
+ if all(isinstance(item, (str, int, float)) for item in val):
258
+ return ", ".join(escape(str(x)) for x in val)
259
+ else:
260
+ return "<ul>" + "".join(f"<li>{render_value(v)}</li>" for v in val) + "</ul>"
261
+ else:
262
+ return escape(str(val))
263
+
264
+ def dict_to_table(d, title=None, nested=False):
265
+ html = ""
266
+ table_class = "nested-table" if nested else "main-table"
267
+ html += f"<table class='{table_class}'>"
268
+ html += "<thead><tr><th>Key</th><th>Value</th></tr></thead><tbody>"
269
+ if not isinstance(d, dict):
270
+ d = {"Error": "Data not available or incorrect format"}
271
+
272
+ for key, val in d.items():
273
+ if val is None or (isinstance(val, (str, list, dict)) and not val):
274
+ continue
275
+ key_html = escape(str(key))
276
+ val_html = render_value(val)
277
+ html += f"<tr><td>{key_html}</td><td>{val_html}</td></tr>"
278
+ html += "</tbody></table>"
279
+ return html
280
+
281
+ html_content = f"""
282
+ <!DOCTYPE html>
283
+ <html lang="en">
284
+ <head>
285
+ <meta charset="UTF-8">
286
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
287
+ <title>Data Processing Report</title>
288
+ {css_js}
289
+ </head>
290
+ <body>
291
+ <h2>📈 Data Processing Report</h2>
292
+ """
293
+ html_content += """
294
+ <div class="tabbed-interface">
295
+ <div class="tab-buttons">
296
+ <button class="tab-button" onclick="openTab(event, 'initial_dataset_tab')">📁 Initial Dataset</button>
297
+ <button class="tab-button" onclick="openTab(event, 'processing_steps_tab')">🔧 Processing Steps</button>
298
+ <button class="tab-button" onclick="openTab(event, 'final_dataset_tab')">✅ Final Dataset</button>
299
+ </div>
300
+ <div class="tab-content">
301
+ """
302
+ html_content += """
303
+ <div id="initial_dataset_tab" class="tab-pane">
304
+ <h3>📁 Initial Dataset Overview</h3>
305
+ """
306
+ html_content += dict_to_table(data_dict.get("initial_dataset", {}))
307
+ html_content += """
308
+ </div>
309
+ """
310
+ html_content += """
311
+ <div id="processing_steps_tab" class="tab-pane">
312
+ <h3>🔧 Pipeline Steps Breakdown</h3>
313
+ """
314
+ for i, step in enumerate(data_dict.get("processing_steps", [])):
315
+ html_content += f"<details>"
316
+ html_content += (
317
+ f"<summary>Step {i + 1}: {escape(step.get('step_name', 'Unnamed Step'))}</summary>"
318
+ )
319
+ html_content += f"<p><strong>Description:</strong> {escape(step.get('description', 'No description provided'))}</p>"
320
+
321
+ html_content += (
322
+ f"<div style='margin-left: 1rem; border-left: 3px solid #e0f2fe; padding-left: 1rem;'>"
323
+ )
324
+
325
+ params_data = step.get("parameters", {})
326
+ if params_data:
327
+ html_content += "<h4>⚙️ Parameters</h4>"
328
+ html_content += dict_to_table(params_data, nested=True)
329
+ else:
330
+ html_content += "<p><em>No parameters recorded.</em></p>"
331
+
332
+ output_info = {
333
+ "Output Shape": step.get("output_shape", "N/A"),
334
+ "Input Columns": step.get("input_columns", "N/A"),
335
+ "Output Columns": step.get("output_columns", "N/A"),
336
+ "Output Dtypes": step.get("output_dtypes", "N/A"),
337
+ "Category Columns": step.get("unique_categories", "N/A"),
338
+ }
339
+ html_content += "<h4>📊 Output Information</h4>"
340
+ html_content += dict_to_table(output_info, nested=True)
341
+
342
+ html_content += "</div>"
343
+ html_content += "</details>"
344
+ html_content += """
345
+ </div>
346
+ """
347
+
348
+ html_content += """
349
+ <div id="final_dataset_tab" class="tab-pane">
350
+ <h3>✅ Final Dataset Overview</h3>
351
+ """
352
+ html_content += dict_to_table(data_dict.get("final_dataset", {}))
353
+ html_content += """
354
+ </div>
355
+ </div> </div> """
356
+ current_time_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
357
+ html_content += f"""
358
+ <p style="text-align: center; color: #94a3b8; font-size: 0.8rem; margin-top: 3rem;">
359
+ Report Generated by Pipeline at {current_time_str}
360
+ </p>
361
+ </body>
362
+ </html>
363
+ """
364
+ if save_to_file:
365
+ try:
366
+ with open(file_name, "w", encoding="utf-8") as f:
367
+ f.write(html_content)
368
+ print(f"✅ Report saved to '{file_name}'")
369
+ except NameError:
370
+ return f"Report content saved to '{file_name}'"
371
+ else:
372
+ try:
373
+ display(HTML(html_content))
374
+ except (ImportError, NameError):
375
+ return html_content