wizata-dsapi 2.0.0.dev27__tar.gz → 2.0.0.dev29__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 (66) hide show
  1. {wizata_dsapi-2.0.0.dev27/wizata_dsapi.egg-info → wizata_dsapi-2.0.0.dev29}/PKG-INFO +1 -1
  2. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/plots/__init__.py +1 -1
  3. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/plots/common.py +207 -32
  4. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/plots/theme.py +10 -0
  5. wizata_dsapi-2.0.0.dev29/wizata_dsapi/version.py +1 -0
  6. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29/wizata_dsapi.egg-info}/PKG-INFO +1 -1
  7. wizata_dsapi-2.0.0.dev27/wizata_dsapi/version.py +0 -1
  8. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/LICENSE.txt +0 -0
  9. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/README.rst +0 -0
  10. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/setup.cfg +0 -0
  11. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/setup.py +0 -0
  12. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/__init__.py +0 -0
  13. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/api_config.py +0 -0
  14. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/api_dto.py +0 -0
  15. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/api_interface.py +0 -0
  16. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/bucket.py +0 -0
  17. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/business_label.py +0 -0
  18. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/context.py +0 -0
  19. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/dashboard.py +0 -0
  20. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/dataframe_toolkit.py +0 -0
  21. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/datapoint.py +0 -0
  22. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/datastore.py +0 -0
  23. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/ds_dataframe.py +0 -0
  24. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/dsapi_json_encoder.py +0 -0
  25. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/edge_config.py +0 -0
  26. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/edge_device.py +0 -0
  27. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/edge_module.py +0 -0
  28. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/evaluation.py +0 -0
  29. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/execution.py +0 -0
  30. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/execution_log.py +0 -0
  31. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/experiment.py +0 -0
  32. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/graylog_log.py +0 -0
  33. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/group_system.py +0 -0
  34. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/ilogger.py +0 -0
  35. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/insight.py +0 -0
  36. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/mlmodel.py +0 -0
  37. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/mobile_asset.py +0 -0
  38. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/model_toolkit.py +0 -0
  39. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/models/__init__.py +0 -0
  40. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/models/common.py +0 -0
  41. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/notification.py +0 -0
  42. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/paged_query_result.py +0 -0
  43. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/pipeline.py +0 -0
  44. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/pipeline_image.py +0 -0
  45. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/plot.py +0 -0
  46. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/request.py +0 -0
  47. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/script.py +0 -0
  48. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/scripts/__init__.py +0 -0
  49. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/scripts/common.py +0 -0
  50. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/search.py +0 -0
  51. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/solution_component.py +0 -0
  52. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/streamlit_utils.py +0 -0
  53. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/template.py +0 -0
  54. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/template_config.py +0 -0
  55. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/trigger.py +0 -0
  56. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/twin.py +0 -0
  57. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/twinregistration.py +0 -0
  58. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/user.py +0 -0
  59. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/wizard_function.py +0 -0
  60. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/wizard_request.py +0 -0
  61. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/wizata_dsapi_client.py +0 -0
  62. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi/words.py +0 -0
  63. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi.egg-info/SOURCES.txt +0 -0
  64. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi.egg-info/dependency_links.txt +0 -0
  65. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi.egg-info/requires.txt +0 -0
  66. {wizata_dsapi-2.0.0.dev27 → wizata_dsapi-2.0.0.dev29}/wizata_dsapi.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wizata_dsapi
3
- Version: 2.0.0.dev27
3
+ Version: 2.0.0.dev29
4
4
  Summary: Wizata Data Science Toolkit
5
5
  Author: Wizata S.A.
6
6
  Author-email: info@wizata.com
@@ -1,2 +1,2 @@
1
- from .common import ts_chart, confusion_matrix, r_squared, anomalies_chart, parallel_coordinates, data_table, setpoint_recommendation, feature_importance
1
+ from .common import ts_chart, confusion_matrix, r_squared, anomalies_chart, parallel_coordinates, data_table, setpoint_recommendation, feature_importance, process_variability
2
2
  from . import theme
@@ -6,13 +6,60 @@ import plotly.graph_objects as go
6
6
  import plotly.express as px
7
7
  import sklearn.metrics
8
8
 
9
+ from plotly.subplots import make_subplots
10
+
9
11
  from .theme import (
10
- apply_theme, SERIES_COLORS, ANOMALY_COLOR, TEXT_MUTED, WHITE,
12
+ apply_theme, SERIES_COLORS, ANOMALY_COLOR, MAIN_COLOR, POSITIVE_COLOR,
13
+ TEXT_MUTED, WHITE,
11
14
  TABLE_HEADER_BG, TABLE_HEADER_TEXT, TABLE_CELL_BG, TABLE_CELL_TEXT,
12
15
  TABLE_LINE_COLOR, FONT_FAMILY, FONT_SIZE,
16
+ COLUMN_TYPE_TELEMETRY, COLUMN_TYPE_SETPOINT, COLUMN_TYPE_RECOMMENDATION,
17
+ COLUMN_TYPE_TARGET, COLUMN_TYPE_CALCULATED, COLUMN_TYPES_ORDER,
13
18
  )
14
19
 
15
20
 
21
+ def _classify_columns(df, context):
22
+ """Classify each dataframe column by its role in the pipeline.
23
+
24
+ Returns a dict of {col_name: {"type": str, "tag": str, "label": str, "color": str}}.
25
+ Type ordering: telemetry < setpoint < recommendation < calculated < target.
26
+ """
27
+ datapoints = context.datapoints or {}
28
+ target = context.properties.get("target_feat") if context.properties else None
29
+
30
+ # Also check models for target_feat if not in properties
31
+ if target is None and hasattr(context, "models") and context.models:
32
+ for model in context.models.values():
33
+ if hasattr(model, "has_target_feat") and model.has_target_feat:
34
+ target_candidates = getattr(model, "target_feat", None)
35
+ if target_candidates:
36
+ target = target_candidates if isinstance(target_candidates, str) else target_candidates[0]
37
+ break
38
+
39
+ classification = {}
40
+ for col in df.select_dtypes(include="number").columns:
41
+ if col == target:
42
+ classification[col] = {**COLUMN_TYPE_TARGET, "type": "target"}
43
+ elif isinstance(col, str) and col.endswith("_recommended"):
44
+ classification[col] = {**COLUMN_TYPE_RECOMMENDATION, "type": "recommendation"}
45
+ elif col in datapoints:
46
+ dp = datapoints[col]
47
+ if dp.business_type == wizata_dsapi.BusinessType.SET_POINTS:
48
+ classification[col] = {**COLUMN_TYPE_SETPOINT, "type": "setpoint"}
49
+ else:
50
+ classification[col] = {**COLUMN_TYPE_TELEMETRY, "type": "telemetry"}
51
+ else:
52
+ classification[col] = {**COLUMN_TYPE_CALCULATED, "type": "calculated"}
53
+
54
+ return classification
55
+
56
+
57
+ def _sort_columns_by_type(columns, classification):
58
+ """Sort columns following COLUMN_TYPES_ORDER: telemetry, setpoint, recommendation, calculated, target."""
59
+ order_map = {t: i for i, t in enumerate(COLUMN_TYPES_ORDER)}
60
+ return sorted(columns, key=lambda c: order_map.get(classification.get(c, {}).get("type", "calculated"), 3))
61
+
62
+
16
63
  def check_single_column_and_target_feat(context: wizata_dsapi.Context):
17
64
  """
18
65
  check_single_column_and_target_feat
@@ -221,14 +268,12 @@ def parallel_coordinates(context: wizata_dsapi.Context):
221
268
 
222
269
 
223
270
  def setpoint_recommendation(context: wizata_dsapi.Context):
224
- """Compare current vs recommended setpoint values as a Wizata-themed table.
225
-
226
- Auto-pairs columns: for every column ending in '_recommended', looks for a matching column
227
- with the same name minus the suffix. Validates that the base column corresponds to a datapoint
228
- with BusinessType.SET_POINTS via context.datapoints (defense against accidental pairings).
229
- Uses the **last row** of the dataframe for current and recommended values (most recent state).
271
+ """Compare current vs recommended setpoint values as a grouped bar chart with a summary table.
230
272
 
231
- Output columns: Setpoint | Current | Recommended | Δ | Δ (%)
273
+ Auto-pairs columns ending in '_recommended' with the matching setpoint column, validated via
274
+ context.datapoints BusinessType.SET_POINTS. Uses the last row (most recent state). The top half
275
+ shows a horizontal grouped bar chart (Current vs Recommended) with type-colored labels; the
276
+ bottom half is a summary table with Setpoint | Current | Recommended | delta | delta (%).
232
277
  """
233
278
  df = context.dataframe
234
279
  datapoints = context.datapoints or {}
@@ -244,8 +289,6 @@ def setpoint_recommendation(context: wizata_dsapi.Context):
244
289
  base = col[: -len(suffix)]
245
290
  if base not in df.columns:
246
291
  continue
247
- # Safety check: only pair if the base column is a declared setpoint datapoint.
248
- # If datapoints are not populated (e.g. local test), fall back to pairing by name.
249
292
  if datapoints:
250
293
  dp = datapoints.get(base)
251
294
  if dp is None or dp.business_type != wizata_dsapi.BusinessType.SET_POINTS:
@@ -258,32 +301,64 @@ def setpoint_recommendation(context: wizata_dsapi.Context):
258
301
  )
259
302
 
260
303
  last = df.iloc[-1]
261
- rows = []
304
+ names, currents, recommendeds, deltas, pcts = [], [], [], [], []
262
305
  for base, rec in pairs:
263
- current = last[base]
264
- recommended = last[rec]
306
+ current = float(last[base])
307
+ recommended = float(last[rec])
265
308
  delta = recommended - current
266
309
  pct = (delta / current * 100.0) if current not in (0, 0.0) and not pd.isna(current) else float("nan")
267
- rows.append({
268
- "Setpoint": base,
269
- "Current": current,
270
- "Recommended": recommended,
271
- "Δ": delta,
272
- "Δ (%)": pct,
273
- })
274
-
275
- out = pd.DataFrame(rows)
276
-
277
- # Formatting — round numerics for readability
278
- for col in ("Current", "Recommended", "Δ", "Δ (%)"):
279
- out[col] = out[col].apply(lambda v: "—" if pd.isna(v) else f"{v:.3f}")
310
+ names.append(base)
311
+ currents.append(current)
312
+ recommendeds.append(recommended)
313
+ deltas.append(delta)
314
+ pcts.append(pct)
315
+
316
+ # ── Build combined figure: bar chart (top) + table (bottom) ──────────
317
+ fig = make_subplots(
318
+ rows=2, cols=1,
319
+ specs=[[{"type": "xy"}], [{"type": "domain"}]],
320
+ row_heights=[0.55, 0.45],
321
+ vertical_spacing=0.08,
322
+ )
280
323
 
281
- n_rows = len(out)
324
+ # Grouped horizontal bars
325
+ fig.add_trace(go.Bar(
326
+ y=names,
327
+ x=recommendeds,
328
+ orientation="h",
329
+ name="Recommended Value",
330
+ marker_color=POSITIVE_COLOR,
331
+ text=[f"{v:.2f}" for v in recommendeds],
332
+ textposition="inside",
333
+ insidetextanchor="start",
334
+ textfont=dict(color=WHITE, size=FONT_SIZE),
335
+ ), row=1, col=1)
336
+
337
+ fig.add_trace(go.Bar(
338
+ y=names,
339
+ x=currents,
340
+ orientation="h",
341
+ name="Current Value",
342
+ marker_color=MAIN_COLOR,
343
+ text=[f"{v:.2f}" for v in currents],
344
+ textposition="inside",
345
+ insidetextanchor="start",
346
+ textfont=dict(color=WHITE, size=FONT_SIZE),
347
+ ), row=1, col=1)
348
+
349
+ fig.update_layout(barmode="group")
350
+ fig.update_xaxes(title_text="Values", row=1, col=1)
351
+ fig.update_yaxes(title_text="Setpoints", row=1, col=1)
352
+
353
+ # Summary table
354
+ fmt = lambda v: "—" if pd.isna(v) else f"{v:.3f}"
355
+ n_rows = len(names)
282
356
  cell_bg = [TABLE_CELL_BG[i % 2] for i in range(n_rows)]
283
357
 
284
- fig = go.Figure(data=[go.Table(
358
+ fig.add_trace(go.Table(
285
359
  header=dict(
286
- values=[f"<b>{c}</b>" for c in out.columns],
360
+ values=["<b>Setpoint</b>", "<b>Current</b>", "<b>Recommended</b>",
361
+ "<b>\u0394</b>", "<b>\u0394 (%)</b>"],
287
362
  fill_color=TABLE_HEADER_BG,
288
363
  font=dict(family=FONT_FAMILY, size=FONT_SIZE, color=TABLE_HEADER_TEXT),
289
364
  align="left",
@@ -291,16 +366,25 @@ def setpoint_recommendation(context: wizata_dsapi.Context):
291
366
  height=32,
292
367
  ),
293
368
  cells=dict(
294
- values=[out[c].tolist() for c in out.columns],
369
+ values=[
370
+ names,
371
+ [fmt(v) for v in currents],
372
+ [fmt(v) for v in recommendeds],
373
+ [fmt(v) for v in deltas],
374
+ [fmt(v) for v in pcts],
375
+ ],
295
376
  fill_color=[cell_bg],
296
377
  font=dict(family=FONT_FAMILY, size=FONT_SIZE, color=TABLE_CELL_TEXT),
297
378
  align="left",
298
379
  line_color=TABLE_LINE_COLOR,
299
380
  height=28,
300
381
  ),
301
- )])
382
+ ), row=2, col=1)
302
383
 
303
- fig.update_layout(margin=dict(l=0, r=0, t=0, b=0))
384
+ fig.update_layout(
385
+ title="Actual vs Recommended Values",
386
+ legend=dict(orientation="h", y=1.02, x=0.5, xanchor="center"),
387
+ )
304
388
  apply_theme(fig)
305
389
 
306
390
  context.set_plot(figure=fig, name="setpoint_recommendation")
@@ -361,6 +445,97 @@ def feature_importance(context: wizata_dsapi.Context):
361
445
  context.set_plot(figure=fig, name="feature_importance")
362
446
 
363
447
 
448
+ def process_variability(context: wizata_dsapi.Context):
449
+ """Parallel coordinates plot showing process configurations variability, colored by a quality
450
+ outcome. Columns are ordered by type: telemetry, setpoints, recommendations, calculated,
451
+ with the target/quality column last. Each axis label is prefixed with a type tag
452
+ ([T], [SP], [REC], [C], [Q]) for quick identification.
453
+
454
+ Column selection:
455
+ - color_by: property name of the quality column used for coloring (defaults to
456
+ context.properties['target_feat'] if set, otherwise the last numeric column).
457
+ - color_reverse: set to true (default) when a LOWER color_by value is better
458
+ (e.g. residual_co2) — low values will be green. Set to false when higher is better
459
+ (e.g. 'good_bottles') — high values will be green.
460
+ """
461
+ df = context.dataframe
462
+ if df is None or len(df) == 0:
463
+ raise ValueError("process_variability: dataframe is empty")
464
+
465
+ numeric_cols = df.select_dtypes(include="number").columns.tolist()
466
+ if len(numeric_cols) < 2:
467
+ raise ValueError("process_variability: need at least 2 numeric columns")
468
+
469
+ # Classify and order columns by type
470
+ classification = _classify_columns(df, context)
471
+ ordered_cols = _sort_columns_by_type(
472
+ [c for c in numeric_cols if c in classification],
473
+ classification
474
+ )
475
+
476
+ # Resolve color column
477
+ color_by = context.properties.get("color_by")
478
+ if color_by is None:
479
+ color_by = context.properties.get("target_feat")
480
+ if color_by is None:
481
+ color_by = ordered_cols[-1] if ordered_cols else numeric_cols[-1]
482
+ if color_by not in df.columns:
483
+ raise ValueError(f"process_variability: color_by column '{color_by}' not found in dataframe")
484
+
485
+ color_reverse = context.properties.get("color_reverse", True)
486
+ if isinstance(color_reverse, str):
487
+ color_reverse = color_reverse.lower() not in ("false", "0", "no")
488
+
489
+ # Build dimensions with type-tagged labels, in order
490
+ dimensions = []
491
+ for col in ordered_cols:
492
+ col_vals = df[col].dropna()
493
+ if col_vals.empty:
494
+ continue
495
+ info = classification[col]
496
+ tagged_label = f"[{info['tag']}] {col}"
497
+ dimensions.append(dict(
498
+ label=tagged_label,
499
+ values=df[col].values,
500
+ range=[float(col_vals.min()), float(col_vals.max())],
501
+ ))
502
+
503
+ # Colorscale: red → yellow → green (reversed if lower is better)
504
+ if color_reverse:
505
+ colorscale = [[0, POSITIVE_COLOR], [0.5, "#FDDD60"], [1, "#FF6E76"]]
506
+ else:
507
+ colorscale = [[0, "#FF6E76"], [0.5, "#FDDD60"], [1, POSITIVE_COLOR]]
508
+
509
+ fig = go.Figure(data=go.Parcoords(
510
+ line=dict(
511
+ color=df[color_by].values,
512
+ colorscale=colorscale,
513
+ showscale=True,
514
+ colorbar=dict(title=color_by),
515
+ ),
516
+ dimensions=dimensions,
517
+ ))
518
+
519
+ # Add a legend-like annotation for the type tags
520
+ type_legend = " ".join(
521
+ f"[{t['tag']}] {t['label']}"
522
+ for t in [COLUMN_TYPE_TELEMETRY, COLUMN_TYPE_SETPOINT, COLUMN_TYPE_RECOMMENDATION,
523
+ COLUMN_TYPE_CALCULATED, COLUMN_TYPE_TARGET]
524
+ )
525
+ fig.update_layout(
526
+ title=dict(text="Configurations Variability"),
527
+ annotations=[dict(
528
+ text=type_legend,
529
+ xref="paper", yref="paper", x=0, y=-0.08,
530
+ showarrow=False,
531
+ font=dict(size=10, color=TEXT_MUTED),
532
+ )],
533
+ )
534
+ apply_theme(fig)
535
+
536
+ context.set_plot(figure=fig, name="process_variability")
537
+
538
+
364
539
  def data_table(context: wizata_dsapi.Context):
365
540
  """Render the dataframe as a styled table with Wizata theme colors."""
366
541
  df = context.dataframe.copy()
@@ -53,6 +53,16 @@ TABLE_CELL_BG = [TERTIARY, FOURTH]
53
53
  TABLE_CELL_TEXT = TEXT_MUTED
54
54
  TABLE_LINE_COLOR = "rgba(255,255,255,0.12)"
55
55
 
56
+ # -- Column type classification -----------------------------------------------
57
+ # Used by plots to visually distinguish column roles in the process pipeline.
58
+ COLUMN_TYPE_TELEMETRY = {"tag": "T", "label": "Telemetry", "color": "#4992FF"}
59
+ COLUMN_TYPE_SETPOINT = {"tag": "SP", "label": "Setpoint", "color": "#E64600"}
60
+ COLUMN_TYPE_RECOMMENDATION = {"tag": "REC", "label": "Recommendation", "color": "#7CFFB2"}
61
+ COLUMN_TYPE_TARGET = {"tag": "Q", "label": "Target / Quality", "color": "#FDDD60"}
62
+ COLUMN_TYPE_CALCULATED = {"tag": "C", "label": "Calculated", "color": "#9E7CFF"}
63
+
64
+ COLUMN_TYPES_ORDER = ["telemetry", "setpoint", "recommendation", "calculated", "target"]
65
+
56
66
  # -- Font ---------------------------------------------------------------------
57
67
  FONT_FAMILY = "Inter, -apple-system, BlinkMacSystemFont, sans-serif"
58
68
  FONT_SIZE = 12
@@ -0,0 +1 @@
1
+ __version__ = "2.0.0.dev29"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wizata_dsapi
3
- Version: 2.0.0.dev27
3
+ Version: 2.0.0.dev29
4
4
  Summary: Wizata Data Science Toolkit
5
5
  Author: Wizata S.A.
6
6
  Author-email: info@wizata.com
@@ -1 +0,0 @@
1
- __version__ = "2.0.0.dev27"