halib 0.2.33__tar.gz → 0.2.35__tar.gz

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.
Files changed (58) hide show
  1. {halib-0.2.33 → halib-0.2.35}/.gitignore +3 -1
  2. {halib-0.2.33 → halib-0.2.35}/PKG-INFO +4 -2
  3. {halib-0.2.33 → halib-0.2.35}/README.md +3 -1
  4. halib-0.2.35/halib/utils/plotly_op.py +248 -0
  5. {halib-0.2.33 → halib-0.2.35}/halib.egg-info/PKG-INFO +4 -2
  6. {halib-0.2.33 → halib-0.2.35}/halib.egg-info/SOURCES.txt +2 -1
  7. {halib-0.2.33 → halib-0.2.35}/setup.py +1 -1
  8. {halib-0.2.33 → halib-0.2.35}/GDriveFolder.txt +0 -0
  9. {halib-0.2.33 → halib-0.2.35}/LICENSE.txt +0 -0
  10. {halib-0.2.33 → halib-0.2.35}/MANIFEST.in +0 -0
  11. {halib-0.2.33 → halib-0.2.35}/halib/__init__.py +0 -0
  12. {halib-0.2.33 → halib-0.2.35}/halib/common/__init__.py +0 -0
  13. {halib-0.2.33 → halib-0.2.35}/halib/common/common.py +0 -0
  14. {halib-0.2.33 → halib-0.2.35}/halib/common/rich_color.py +0 -0
  15. {halib-0.2.33 → halib-0.2.35}/halib/exp/__init__.py +0 -0
  16. {halib-0.2.33 → halib-0.2.35}/halib/exp/core/__init__.py +0 -0
  17. {halib-0.2.33 → halib-0.2.35}/halib/exp/core/base_config.py +0 -0
  18. {halib-0.2.33 → halib-0.2.35}/halib/exp/core/base_exp.py +0 -0
  19. {halib-0.2.33 → halib-0.2.35}/halib/exp/core/param_gen.py +0 -0
  20. {halib-0.2.33 → halib-0.2.35}/halib/exp/data/__init__.py +0 -0
  21. {halib-0.2.33 → halib-0.2.35}/halib/exp/data/dataclass_util.py +0 -0
  22. {halib-0.2.33 → halib-0.2.35}/halib/exp/data/dataset.py +0 -0
  23. {halib-0.2.33 → halib-0.2.35}/halib/exp/data/torchloader.py +0 -0
  24. {halib-0.2.33 → halib-0.2.35}/halib/exp/perf/__init__.py +0 -0
  25. {halib-0.2.33 → halib-0.2.35}/halib/exp/perf/flop_calc.py +0 -0
  26. {halib-0.2.33 → halib-0.2.35}/halib/exp/perf/gpu_mon.py +0 -0
  27. {halib-0.2.33 → halib-0.2.35}/halib/exp/perf/perfcalc.py +0 -0
  28. {halib-0.2.33 → halib-0.2.35}/halib/exp/perf/perfmetrics.py +0 -0
  29. {halib-0.2.33 → halib-0.2.35}/halib/exp/perf/perftb.py +0 -0
  30. {halib-0.2.33 → halib-0.2.35}/halib/exp/perf/profiler.py +0 -0
  31. {halib-0.2.33 → halib-0.2.35}/halib/exp/viz/__init__.py +0 -0
  32. {halib-0.2.33 → halib-0.2.35}/halib/exp/viz/plot.py +0 -0
  33. {halib-0.2.33 → halib-0.2.35}/halib/filetype/__init__.py +0 -0
  34. {halib-0.2.33 → halib-0.2.35}/halib/filetype/csvfile.py +0 -0
  35. {halib-0.2.33 → halib-0.2.35}/halib/filetype/ipynb.py +0 -0
  36. {halib-0.2.33 → halib-0.2.35}/halib/filetype/jsonfile.py +0 -0
  37. {halib-0.2.33 → halib-0.2.35}/halib/filetype/textfile.py +0 -0
  38. {halib-0.2.33 → halib-0.2.35}/halib/filetype/videofile.py +0 -0
  39. {halib-0.2.33 → halib-0.2.35}/halib/filetype/yamlfile.py +0 -0
  40. {halib-0.2.33 → halib-0.2.35}/halib/online/__init__.py +0 -0
  41. {halib-0.2.33 → halib-0.2.35}/halib/online/gdrive.py +0 -0
  42. {halib-0.2.33 → halib-0.2.35}/halib/online/gdrive_mkdir.py +0 -0
  43. {halib-0.2.33 → halib-0.2.35}/halib/online/projectmake.py +0 -0
  44. {halib-0.2.33 → halib-0.2.35}/halib/online/tele_noti.py +0 -0
  45. {halib-0.2.33 → halib-0.2.35}/halib/system/__init__.py +0 -0
  46. {halib-0.2.33 → halib-0.2.35}/halib/system/_list_pc.csv +0 -0
  47. {halib-0.2.33 → halib-0.2.35}/halib/system/cmd.py +0 -0
  48. {halib-0.2.33 → halib-0.2.35}/halib/system/filesys.py +0 -0
  49. {halib-0.2.33 → halib-0.2.35}/halib/system/path.py +0 -0
  50. {halib-0.2.33 → halib-0.2.35}/halib/utils/__init__.py +0 -0
  51. {halib-0.2.33 → halib-0.2.35}/halib/utils/dict.py +0 -0
  52. {halib-0.2.33 → halib-0.2.35}/halib/utils/list.py +0 -0
  53. /halib-0.2.33/halib/utils/slack.py → /halib-0.2.35/halib/utils/slack_op.py +0 -0
  54. {halib-0.2.33 → halib-0.2.35}/halib/utils/wandb_op.py +0 -0
  55. {halib-0.2.33 → halib-0.2.35}/halib.egg-info/dependency_links.txt +0 -0
  56. {halib-0.2.33 → halib-0.2.35}/halib.egg-info/requires.txt +0 -0
  57. {halib-0.2.33 → halib-0.2.35}/halib.egg-info/top_level.txt +0 -0
  58. {halib-0.2.33 → halib-0.2.35}/setup.cfg +0 -0
@@ -56,4 +56,6 @@ venv*/
56
56
  test/test_plot/output
57
57
 
58
58
  # api keys and configurations
59
- .env.yaml
59
+ .env.yaml
60
+
61
+ test/test_utils/test_results_with_table.html
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: halib
3
- Version: 0.2.33
3
+ Version: 0.2.35
4
4
  Summary: Small library for common tasks
5
5
  Author: Hoang Van Ha
6
6
  Author-email: hoangvanhauit@gmail.com
@@ -57,7 +57,9 @@ Dynamic: summary
57
57
 
58
58
  ## v0.2.x (Experiment & Core Updates)
59
59
 
60
- ### **v0.2.33**
60
+ ### **v0.2.35**
61
+
62
+ - ✨ **New Feature:**: introduce `utils.PlotlyUtils` with parallel coordinates plot and data table support
61
63
 
62
64
  - 🚀 **Improvement:**: move `wandb_op.py` to `utils` and add `scripts` folder
63
65
 
@@ -2,7 +2,9 @@
2
2
 
3
3
  ## v0.2.x (Experiment & Core Updates)
4
4
 
5
- ### **v0.2.33**
5
+ ### **v0.2.35**
6
+
7
+ - ✨ **New Feature:**: introduce `utils.PlotlyUtils` with parallel coordinates plot and data table support
6
8
 
7
9
  - 🚀 **Improvement:**: move `wandb_op.py` to `utils` and add `scripts` folder
8
10
 
@@ -0,0 +1,248 @@
1
+ import os
2
+ import pandas as pd
3
+ from typing import List, Optional, Callable, Union
4
+ from rich.pretty import pprint
5
+ import plotly.express as px
6
+ from ..common.common import pprint_local_path
7
+
8
+
9
+ class PlotlyUtils:
10
+ @staticmethod
11
+ # Extract experiment IDs from complex naming convention
12
+ def exp_id_extractor(df: pd.DataFrame) -> pd.Series:
13
+ # MainPC__ds_UFireIndoor2__mt_temp_method_motion_block__9896ed2e67e7__20260202.133758
14
+ exp_names = df["Name"].to_list()
15
+ exp_ids = []
16
+ for name in exp_names:
17
+ parts = name.split("__")
18
+ exp_id = parts[-2] if len(parts) >= 2 else name
19
+ exp_ids.append(exp_id)
20
+ return pd.Series(exp_ids)
21
+
22
+ @staticmethod
23
+ def exp_id_formatter(exp_id: str) -> str:
24
+ if len(exp_id) <= 6:
25
+ return exp_id
26
+ return f"{exp_id[:6]}"
27
+
28
+ @staticmethod
29
+ def parallel_plot(
30
+ df_or_csv_file: Union[pd.DataFrame, str],
31
+ dimensions: List[str] = [],
32
+ exclude_dims: List[str] = [],
33
+ exp_col_or_func: Union[
34
+ str, Callable[[pd.DataFrame], pd.Series]
35
+ ] = exp_id_extractor,
36
+ exp_id_formatter: Optional[Callable[[str], str]] = exp_id_formatter,
37
+ color: Optional[str] = None,
38
+ csv_separator: str = ";",
39
+ plot_bar_height: int = 1200,
40
+ plot_width: int = 1500,
41
+ title: str = "Parallel Coordinates Plot",
42
+ template: str = "plotly_white",
43
+ outdir: str = ".",
44
+ outfile: str = "zresults_with_table.html",
45
+ ):
46
+ # 1. Unified Data Loading
47
+ if isinstance(df_or_csv_file, str):
48
+ df = pd.read_csv(df_or_csv_file, sep=csv_separator, encoding="utf-8")
49
+ else:
50
+ df = df_or_csv_file.copy()
51
+
52
+ # 2. Extract Experiment IDs
53
+ if callable(exp_col_or_func):
54
+ df["exp_id"] = exp_col_or_func(df)
55
+ elif isinstance(exp_col_or_func, str):
56
+ if exp_col_or_func not in df.columns:
57
+ raise ValueError(f"Column '{exp_col_or_func}' not found.")
58
+ df["exp_id"] = df[exp_col_or_func].copy()
59
+ exclude_dims.append(exp_col_or_func)
60
+ else:
61
+ raise ValueError("exp_col_or_func must be a column name or a callable.")
62
+
63
+ # 3. Setup Plot Dimensions
64
+ # Priority: explicit dimensions -> all columns minus exclusions
65
+ if not dimensions:
66
+ dimensions = [
67
+ c for c in df.columns if c not in exclude_dims and c != "exp_id"
68
+ ]
69
+
70
+ df["numeric_id"] = range(len(df))
71
+ # Ensure numeric_id is the first axis for the labels to work
72
+ final_plot_dims = ["numeric_id"] + [
73
+ d for d in dimensions if d != "numeric_id" and d in df.columns
74
+ ]
75
+
76
+ pprint(f"Generating plot: {title}")
77
+
78
+ # 4. Create and Configure Plotly Figure
79
+ fig = px.parallel_coordinates(
80
+ df,
81
+ dimensions=final_plot_dims,
82
+ color=color,
83
+ title=title,
84
+ template=template,
85
+ )
86
+
87
+ # Map string IDs to the numeric axis
88
+ fig.data[0].dimensions[0].tickvals = list(df["numeric_id"])
89
+ fig.data[0].dimensions[0].ticktext = (
90
+ [exp_id_formatter(i) for i in df["exp_id"]]
91
+ if exp_id_formatter
92
+ else df["exp_id"]
93
+ )
94
+ fig.data[0].dimensions[0].label = "Exp IDs"
95
+
96
+ fig.update_layout(
97
+ title={
98
+ "text": title,
99
+ "y": 0.98,
100
+ "x": 0.5,
101
+ "xanchor": "center",
102
+ "yanchor": "top",
103
+ },
104
+ width=plot_width,
105
+ height=plot_bar_height,
106
+ margin=dict(l=150, r=50, t=150, b=50),
107
+ )
108
+
109
+ # 5. Prepare Table Display
110
+ # Clean up columns: Move exp_id to front, drop internal numeric_id
111
+ cols = ["exp_id"] + [c for c in df.columns if c not in ["exp_id", "numeric_id"]]
112
+ cols = [col for col in cols if col not in exclude_dims]
113
+
114
+ df_display = df[cols].copy()
115
+ df_display.insert(0, "Selection", '<button class="select-btn">Select</button>')
116
+
117
+ chart_html = fig.to_html(full_html=False, include_plotlyjs="cdn")
118
+
119
+ table_html = df_display.to_html(
120
+ classes="display nowrap", table_id="exp_table", index=False, escape=False
121
+ )
122
+
123
+ final_html = f"""
124
+ <!DOCTYPE html>
125
+ <html>
126
+ <head>
127
+ <title>Experiment Dashboard</title>
128
+ <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.css">
129
+ <script type="text/javascript" charset="utf8" src="https://code.jquery.com/jquery-3.5.1.js"></script>
130
+ <script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.js"></script>
131
+ <style>
132
+ body {{
133
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
134
+ margin: 20px;
135
+ background-color: #f0f2f5;
136
+ }}
137
+ .container {{
138
+ background: white;
139
+ padding: 30px;
140
+ border-radius: 12px;
141
+ box-shadow: 0 4px 20px rgba(0,0,0,0.08);
142
+ }}
143
+
144
+ /* --- TABLE FONT SIZE FIX --- */
145
+ table.dataTable {{
146
+ font-size: 11px; /* Smaller overall text */
147
+ }}
148
+ table.dataTable thead th {{
149
+ background-color: #333;
150
+ color: white;
151
+ padding: 8px !important;
152
+ font-size: 12px;
153
+ }}
154
+ table.dataTable tbody td {{
155
+ padding: 4px 8px !important; /* Compact rows */
156
+ }}
157
+
158
+ #exp_table tbody tr:nth-child(even), #selected_table tbody tr:nth-child(even) {{ background-color: #f2f2f2; }}
159
+ #exp_table tbody tr:nth-child(odd), #selected_table tbody tr:nth-child(odd) {{ background-color: #ffffff; }}
160
+ #exp_table tbody tr:hover, #selected_table tbody tr:hover {{ background-color: #e0e0e0; }}
161
+
162
+ h2 {{ color: #2c3e50; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-top: 40px; }}
163
+
164
+ /* Smaller buttons */
165
+ .select-btn {{ background-color: #28a745; color: white; border: none; padding: 3px 7px; cursor: pointer; border-radius: 4px; font-size: 10px; }}
166
+ .remove-btn {{ background-color: #dc3545; color: white; border: none; padding: 3px 7px; cursor: pointer; border-radius: 4px; font-size: 10px; }}
167
+ .clear-btn {{ background-color: #6c757d; color: white; border: none; padding: 8px 12px; cursor: pointer; border-radius: 4px; margin-bottom: 10px; font-size: 12px; }}
168
+ </style>
169
+ </head>
170
+ <body>
171
+ <div class="container">
172
+ {chart_html}
173
+
174
+ <h2>Selected Experiments</h2>
175
+ <button id="clear_all" class="clear-btn">Clear All</button>
176
+ <div style="overflow-x:auto; margin-bottom: 40px;">
177
+ <table id="selected_table" class="display nowrap">
178
+ <thead>{df_display.iloc[:0].to_html(index=False, escape=False).split("<thead>")[1].split("</thead>")[0]}</thead>
179
+ <tbody></tbody>
180
+ </table>
181
+ </div>
182
+
183
+ <hr>
184
+
185
+ <h2>Full Experiment Raw Data</h2>
186
+ <div style="overflow-x:auto;">
187
+ {table_html}
188
+ </div>
189
+ </div>
190
+
191
+ <script>
192
+ $(document).ready( function () {{
193
+ var mainTable = $('#exp_table').DataTable({{
194
+ "pageLength": 25,
195
+ "order": [[ 5, "desc" ]],
196
+ "stripeClasses": []
197
+ }});
198
+
199
+ var selectedTable = $('#selected_table').DataTable({{
200
+ "paging": false,
201
+ "searching": false,
202
+ "info": false,
203
+ "stripeClasses": []
204
+ }});
205
+
206
+ // Handle Select button
207
+ $('#exp_table tbody').on('click', '.select-btn', function () {{
208
+ var data = mainTable.row($(this).parents('tr')).data();
209
+ var rowNode = $(this).parents('tr');
210
+
211
+ // Change button to remove in the new table
212
+ var newData = [...data];
213
+ newData[0] = '<button class="remove-btn">Remove</button>';
214
+
215
+ // Check if already in selectedTable (optional but good)
216
+ var alreadyExists = false;
217
+ selectedTable.rows().every(function() {{
218
+ if(this.data()[1] === data[1]) {{ alreadyExists = true; }}
219
+ }});
220
+
221
+ if(!alreadyExists) {{
222
+ selectedTable.row.add(newData).draw();
223
+ }}
224
+ }});
225
+
226
+ // Handle Remove button
227
+ $('#selected_table tbody').on('click', '.remove-btn', function () {{
228
+ selectedTable.row($(this).parents('tr')).remove().draw();
229
+ }});
230
+
231
+ // Handle Clear All
232
+ $('#clear_all').on('click', function() {{
233
+ selectedTable.clear().draw();
234
+ }});
235
+ }});
236
+ </script>
237
+ </body>
238
+ </html>
239
+ """
240
+
241
+ final_html_path = os.path.join(outdir, outfile)
242
+ with open(final_html_path, "w") as f:
243
+ f.write(final_html)
244
+
245
+ pprint_local_path(
246
+ final_html_path, get_wins_path=True, tag="PlotlyUtils.parallel_plot"
247
+ )
248
+ return fig
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: halib
3
- Version: 0.2.33
3
+ Version: 0.2.35
4
4
  Summary: Small library for common tasks
5
5
  Author: Hoang Van Ha
6
6
  Author-email: hoangvanhauit@gmail.com
@@ -57,7 +57,9 @@ Dynamic: summary
57
57
 
58
58
  ## v0.2.x (Experiment & Core Updates)
59
59
 
60
- ### **v0.2.33**
60
+ ### **v0.2.35**
61
+
62
+ - ✨ **New Feature:**: introduce `utils.PlotlyUtils` with parallel coordinates plot and data table support
61
63
 
62
64
  - 🚀 **Improvement:**: move `wandb_op.py` to `utils` and add `scripts` folder
63
65
 
@@ -51,5 +51,6 @@ halib/system/path.py
51
51
  halib/utils/__init__.py
52
52
  halib/utils/dict.py
53
53
  halib/utils/list.py
54
- halib/utils/slack.py
54
+ halib/utils/plotly_op.py
55
+ halib/utils/slack_op.py
55
56
  halib/utils/wandb_op.py
@@ -8,7 +8,7 @@ with open("requirements.txt", "r", encoding="utf-8") as f:
8
8
 
9
9
  setuptools.setup(
10
10
  name="halib",
11
- version="0.2.33",
11
+ version="0.2.35",
12
12
  author="Hoang Van Ha",
13
13
  author_email="hoangvanhauit@gmail.com",
14
14
  description="Small library for common tasks",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes