lessPython 0.2.0__py3-none-any.whl → 0.3.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.
Files changed (59) hide show
  1. lessPy/ANOVA.py +74 -15
  2. lessPy/Chart.py +431 -88
  3. lessPy/Correlation.py +40 -11
  4. lessPy/Flows.py +3 -3
  5. lessPy/Logit.py +15 -11
  6. lessPy/Regression.py +27 -21
  7. lessPy/X.py +280 -42
  8. lessPy/XY.py +1332 -239
  9. lessPy/__init__.py +12 -2
  10. lessPy/_themes.py +5007 -0
  11. lessPy/bc_items_plotly.py +33 -20
  12. lessPy/bc_plotly.py +27 -10
  13. lessPy/bubble_plotly.py +33 -17
  14. lessPy/corCFA.py +9 -5
  15. lessPy/corProp.py +8 -4
  16. lessPy/corReflect.py +8 -4
  17. lessPy/corReorder.py +8 -4
  18. lessPy/corScree.py +12 -8
  19. lessPy/data/StockPrice.csv +1401 -1386
  20. lessPy/details.py +17 -4
  21. lessPy/dn_plotly.py +74 -54
  22. lessPy/dot_plotly.py +9 -8
  23. lessPy/freq_poly_plotly.py +18 -11
  24. lessPy/getColors.py +247 -20
  25. lessPy/hier_plotly.py +41 -14
  26. lessPy/hs_plotly.py +23 -11
  27. lessPy/pie_plotly.py +1 -1
  28. lessPy/pivot.py +39 -9
  29. lessPy/plotly_utils.py +162 -29
  30. lessPy/plt_add.py +2 -7
  31. lessPy/plt_contour.py +6 -6
  32. lessPy/plt_contour_facet.py +3 -3
  33. lessPy/plt_mat_plotly.py +85 -12
  34. lessPy/plt_plotly.py +34 -18
  35. lessPy/plt_smooth.py +4 -4
  36. lessPy/plt_time.py +10 -3
  37. lessPy/prob_norm.py +7 -3
  38. lessPy/prob_tcut.py +7 -3
  39. lessPy/prob_znorm.py +7 -1
  40. lessPy/profile_plotly.py +5 -4
  41. lessPy/radar_plotly.py +4 -3
  42. lessPy/rcolors.py +461 -0
  43. lessPy/simCImean.py +7 -3
  44. lessPy/simCLT.py +7 -3
  45. lessPy/simFlips.py +7 -3
  46. lessPy/simMeans.py +7 -3
  47. lessPy/stats_out.py +257 -11
  48. lessPy/style.py +167 -0
  49. lessPy/sunflower_plotly.py +141 -0
  50. lessPy/ttest.py +17 -13
  51. lessPy/utils.py +146 -6
  52. lessPy/vbs_plotly.py +39 -27
  53. lessPy/x_console.py +763 -0
  54. {lesspython-0.2.0.dist-info → lesspython-0.3.1.dist-info}/METADATA +13 -2
  55. lesspython-0.3.1.dist-info/RECORD +89 -0
  56. {lesspython-0.2.0.dist-info → lesspython-0.3.1.dist-info}/WHEEL +1 -1
  57. lesspython-0.2.0.dist-info/RECORD +0 -84
  58. {lesspython-0.2.0.dist-info → lesspython-0.3.1.dist-info}/licenses/LICENSE +0 -0
  59. {lesspython-0.2.0.dist-info → lesspython-0.3.1.dist-info}/top_level.txt +0 -0
lessPy/ttest.py CHANGED
@@ -24,7 +24,7 @@ import numpy as np
24
24
  import pandas as pd
25
25
 
26
26
  from .Regression import _getdigits
27
- from .utils import fmt, get_column, get_option
27
+ from .utils import fmt, get_column, get_option, file_output, show_plots
28
28
 
29
29
 
30
30
  class ttestResults:
@@ -309,14 +309,14 @@ def _two_group(n1, m1, s1, n2, m2, s2, Ynm, Xnm, X1nm, X2nm,
309
309
  if graph and from_data:
310
310
  plots["two_group"] = _two_group_plot(
311
311
  YA, YB, Ynm, X1nm, X2nm, m1, m2, d)
312
- return ttestResults(
312
+ return show_plots(ttestResults(
313
313
  kind="two-group", n_total=n1 + n2, digits_d=d,
314
314
  group1={"name": X1nm, "n": n1, "mean": m1, "sd": s1},
315
315
  group2={"name": X2nm, "n": n2, "mean": m2, "sd": s2},
316
316
  mean_diff=m1 - m2, pooled_sd=sw, cohen_d=smd,
317
317
  equal_var={"t": tvalue, "df": df, "p_value": pvalue,
318
318
  "se": sterr, "lb": lb, "ub": ub},
319
- welch=welch, plots=plots)
319
+ welch=welch, plots=plots))
320
320
 
321
321
 
322
322
  def _assumptions(YA, YB, X1nm, X2nm, Ynm, n1, n2, v1, v2, df1,
@@ -529,12 +529,12 @@ def _one_group(Y, n, m, s, mu, Ynm, brief, conf_level,
529
529
  if graph and from_data:
530
530
  plots["one_group"] = _one_group_plot(
531
531
  Y, Ynm, m, lb, ub, d, paired)
532
- return ttestResults(
532
+ return show_plots(ttestResults(
533
533
  kind="paired" if paired else "one-group", n_total=n,
534
534
  digits_d=d, n=n, mean=m, sd=s, mu=mu,
535
535
  infer={"t": tvalue, "df": df, "p_value": pvalue,
536
536
  "se": sterr, "lb": lb, "ub": ub},
537
- cohen_d=cohen, plots=plots)
537
+ cohen_d=cohen, plots=plots))
538
538
 
539
539
 
540
540
  def _needed_1(Edesired, conf_level, s, E, n, d):
@@ -572,7 +572,7 @@ def _kde(v):
572
572
  def _two_group_plot(YA, YB, Ynm, X1nm, X2nm, m1, m2, d):
573
573
  import plotly.graph_objects as go
574
574
  from .plotly_utils import (
575
- BASE_COLORS, axis_format, axis_num, make_trans,
575
+ as_plotly_color, BASE_COLORS, axis_format, axis_num, make_trans,
576
576
  plot_border, plotly_style, to_hex, x_grid)
577
577
  from .utils import pretty
578
578
  style = plotly_style()
@@ -595,8 +595,8 @@ def _two_group_plot(YA, YB, Ynm, X1nm, X2nm, m1, m2, d):
595
595
  fig.update_layout(
596
596
  xaxis=ax_x, yaxis=ax_y,
597
597
  shapes=x_grid(axT1) + plot_border(), template=None,
598
- plot_bgcolor=to_hex(style["panel_fill"]),
599
- paper_bgcolor=to_hex(style["window_fill"]),
598
+ plot_bgcolor=as_plotly_color(style["panel_fill"]),
599
+ paper_bgcolor=as_plotly_color(style["window_fill"]),
600
600
  legend=dict(title=dict(text=str(X1nm) + " / " + str(X2nm))),
601
601
  title=dict(text="Two-Group Density Plot", x=0.5,
602
602
  xanchor="center",
@@ -608,7 +608,7 @@ def _two_group_plot(YA, YB, Ynm, X1nm, X2nm, m1, m2, d):
608
608
  def _one_group_plot(Y, Ynm, m, lb, ub, d, paired):
609
609
  import plotly.graph_objects as go
610
610
  from .plotly_utils import (
611
- BASE_COLORS, axis_format, axis_num, make_trans,
611
+ as_plotly_color, BASE_COLORS, axis_format, axis_num, make_trans,
612
612
  plot_border, plotly_style, to_hex, x_grid)
613
613
  from .utils import pretty
614
614
  style = plotly_style()
@@ -616,13 +616,13 @@ def _one_group_plot(Y, Ynm, m, lb, ub, d, paired):
616
616
  c = BASE_COLORS[0]
617
617
  fig = go.Figure()
618
618
  fig.add_trace(go.Scatter(
619
- x=xs, y=ys, mode="lines", line=dict(color=to_hex(c),
619
+ x=xs, y=ys, mode="lines", line=dict(color=as_plotly_color(c),
620
620
  width=2),
621
621
  fill="tozeroy", fillcolor=make_trans(c, 0.85),
622
622
  hoverinfo="x", showlegend=False))
623
623
  ym = float(np.interp(m, xs, ys))
624
624
  fig.add_shape(type="line", x0=m, x1=m, y0=0, y1=ym,
625
- line=dict(color=to_hex("gray50"), width=1))
625
+ line=dict(color=as_plotly_color("gray50"), width=1))
626
626
  axT1 = pretty(float(xs.min()), float(xs.max()))
627
627
  xlab = ("Differences of Matched Pairs" if paired else Ynm)
628
628
  ax_x = axis_num(xlab, axT1, axis_format(axT1, d))
@@ -631,11 +631,15 @@ def _one_group_plot(Y, Ynm, m, lb, ub, d, paired):
631
631
  fig.update_layout(
632
632
  xaxis=ax_x, yaxis=ax_y,
633
633
  shapes=x_grid(axT1) + plot_border(), template=None,
634
- plot_bgcolor=to_hex(style["panel_fill"]),
635
- paper_bgcolor=to_hex(style["window_fill"]),
634
+ plot_bgcolor=as_plotly_color(style["panel_fill"]),
635
+ paper_bgcolor=as_plotly_color(style["window_fill"]),
636
636
  title=dict(
637
637
  text="One-Group Density Plot", x=0.5,
638
638
  xanchor="center",
639
639
  font=dict(size=round(16 * get_option("main_size",
640
640
  1)))))
641
641
  return fig
642
+
643
+
644
+ # pdf_file= and png_file= write the figures, as lessR's pdf_file=
645
+ ttest = file_output(ttest)
lessPy/utils.py CHANGED
@@ -8,9 +8,9 @@ import math
8
8
 
9
9
  # style settings; R analog: options() set by lessR style()
10
10
  _OPTIONS = {
11
- "main_size": 1.0,
12
- "lab_size": 1.0,
13
- "axis_size": 0.9,
11
+ "main_size": 1.16, # zzz_on.R
12
+ "lab_size": 1.05, # zzz_on.R
13
+ "axis_size": 0.80, # zzz_on.R
14
14
  "axis_color": "black",
15
15
  "lab_color": "black",
16
16
  "grid_color": "gray90",
@@ -23,6 +23,7 @@ _OPTIONS = {
23
23
  "panel_fill": "white",
24
24
  "window_fill": "white",
25
25
  "digits_d": 2,
26
+ "suggest": True, # >>> Suggestions, as R
26
27
  "pt_color": "#324E5C", # rgb(50,78,92), zzz_on.R
27
28
  "trans_pt_fill": 0.10,
28
29
  "segment_color": "gray40",
@@ -159,9 +160,10 @@ def resolve_facet(data, facet, fun):
159
160
  "facet names a categorical variable for its "
160
161
  "panels")
161
162
  if len(facet) > 2:
162
- print(f"facet has {len(facet)} variables. {fun}() "
163
- "uses the first two: "
164
- f"{facet[0]}, {facet[1]}.")
163
+ from .stats_out import advise
164
+ advise(f"facet has {len(facet)} variables. {fun}() "
165
+ "uses the first two: "
166
+ f"{facet[0]}, {facet[1]}.")
165
167
  f1 = get_column(data, facet[0], "facet")
166
168
  if len(facet) == 1:
167
169
  return f1, facet[0], None, None
@@ -273,3 +275,141 @@ def pretty(lo, hi, n=5):
273
275
  vals = [(ns + i) * unit for i in range(int(nu - ns) + 1)]
274
276
  # avoid -0.0 and float dust such as 0.30000000000000004
275
277
  return [round(v, 10) + 0.0 for v in vals]
278
+
279
+
280
+ def _in_notebook():
281
+ """True in a notebook kernel (Jupyter, Colab, VS Code), False in
282
+ a script, the terminal, or the IPython console."""
283
+ try:
284
+ from IPython import get_ipython
285
+ except ImportError:
286
+ return False
287
+ ip = get_ipython()
288
+ return ip is not None and getattr(ip, "kernel", None) is not None
289
+
290
+
291
+ def show_plots(result):
292
+ """Show the figures an analysis returns, as lessR draws its
293
+ graphics as it runs. Only in a notebook: elsewhere fig.show()
294
+ opens a browser tab per figure, so the figures stay in .plots
295
+ (or .attrs["plots"] for a returned DataFrame). Displayed as a
296
+ notebook displays a returned Chart() figure; a display failure
297
+ leaves the figures in .plots rather than lose the analysis.
298
+ Returns result."""
299
+ attrs = getattr(result, "attrs", None)
300
+ plots = (attrs.get("plots") if isinstance(attrs, dict)
301
+ else getattr(result, "plots", None))
302
+ if plots and _in_notebook():
303
+ from IPython.display import display
304
+ try:
305
+ for fig in plots.values():
306
+ if fig is not None:
307
+ display(fig)
308
+ except Exception as e:
309
+ import warnings
310
+ warnings.warn(f"figures not displayed ({e}); they are "
311
+ "in .plots, show one with .show()")
312
+ return result
313
+
314
+
315
+ def _figures_of(out, names=None):
316
+ """The figures a function returned, keyed by the file-name
317
+ suffix: an analysis result's .plots (or .attrs["plots"]) by plot
318
+ name, a list of Figures by variable name (X() of a list), and a
319
+ single Figure by no suffix."""
320
+ if hasattr(out, "write_image"):
321
+ return {"": out}
322
+ if isinstance(out, (list, tuple)):
323
+ keys = ([str(v) for v in names] if names
324
+ and len(names) == len(out)
325
+ else [str(i + 1) for i in range(len(out))])
326
+ return {k: f for k, f in zip(keys, out)
327
+ if hasattr(f, "write_image")}
328
+ attrs = getattr(out, "attrs", None)
329
+ plots = (attrs.get("plots") if isinstance(attrs, dict)
330
+ else getattr(out, "plots", None))
331
+ return {k: f for k, f in (plots or {}).items() if f is not None}
332
+
333
+
334
+ def write_figures(out, stem, ext, names=None):
335
+ """Write the returned figures to ext ("pdf", "png") files named
336
+ from stem, as lessR's pdf_file=: one figure is stem.ext, several
337
+ are stem_<name>.ext. Reports the files as lessR's .showfile();
338
+ on Colab also downloads them to the user's computer. A write
339
+ failure warns and leaves the analysis result intact."""
340
+ import os
341
+ import sys
342
+ import warnings
343
+ stem = str(stem)
344
+ if stem.lower().endswith("." + ext):
345
+ stem = stem[:-len(ext) - 1]
346
+ figs = _figures_of(out, names)
347
+ if not figs:
348
+ return
349
+ if len(figs) == 1:
350
+ figs = {"": next(iter(figs.values()))}
351
+ dir_nm = os.path.dirname(stem)
352
+ if dir_nm and not os.path.isdir(dir_nm):
353
+ warnings.warn(f"{ext} file not written: no folder {dir_nm}",
354
+ stacklevel=3)
355
+ return
356
+ files = []
357
+ try:
358
+ for key, fig in figs.items():
359
+ fname = f"{stem}_{key}.{ext}" if key else f"{stem}.{ext}"
360
+ fig.write_image(fname, scale=2 if ext == "png" else 1)
361
+ files.append(fname)
362
+ except Exception as e:
363
+ warnings.warn(
364
+ f"{ext} file not written ({e})\nWriting {ext} files needs "
365
+ "the png extra: pip install \"lessPython[png]\", then "
366
+ "plotly_get_chrome -y once (on Colab: !plotly_get_chrome "
367
+ "-y).", stacklevel=3)
368
+ if not files:
369
+ return
370
+ where = ("written at the current working directory"
371
+ if not dir_nm else "written")
372
+ workdir = os.getcwd() if not dir_nm else dir_nm
373
+ word = "file" if len(files) == 1 else "files"
374
+ print(f"\nThe {ext} {word} {where}")
375
+ for f in files:
376
+ print(f" {os.path.basename(f)}")
377
+ print(f" in: {workdir}\n")
378
+ if "google.colab" in sys.modules:
379
+ try:
380
+ from google.colab import files as _colab_files
381
+ for f in files:
382
+ _colab_files.download(f)
383
+ except Exception:
384
+ pass
385
+
386
+
387
+ def file_output(func):
388
+ """Wrap a function that returns figures so pdf_file= and
389
+ png_file= write them to files, as lessR's pdf_file=: the file
390
+ name, or with several figures the stem of the names,
391
+ stem_<plot>.ext. For a list of x variables (X()), each file is
392
+ named by its variable. As in lessR, True is refused: the name
393
+ is always given, so a second analysis cannot overwrite the
394
+ files of the first under a fixed name."""
395
+ import functools
396
+
397
+ @functools.wraps(func)
398
+ def wrapper(*args, pdf_file=None, png_file=None, **kwargs):
399
+ for given, prm in ((pdf_file, "pdf_file"), (png_file, "png_file")):
400
+ if isinstance(given, bool) and given:
401
+ raise ValueError(
402
+ f"{prm} takes the stem of the file names, such as "
403
+ f"{prm}=\"myReg\", which for Regression() writes "
404
+ "one file per chart, such as "
405
+ "myReg_scatter_matrix." + prm[:3] + ".")
406
+ out = func(*args, **kwargs)
407
+ if pdf_file or png_file:
408
+ xs = kwargs.get("x", args[0] if args else None)
409
+ names = xs if isinstance(xs, (list, tuple)) else None
410
+ for given, ext in ((pdf_file, "pdf"), (png_file, "png")):
411
+ if given:
412
+ write_figures(out, given, ext, names)
413
+ return out
414
+
415
+ return wrapper
lessPy/vbs_plotly.py CHANGED
@@ -42,7 +42,7 @@ import plotly.graph_objects as go
42
42
  from .plotly_utils import (
43
43
  as_plotly_color, axis_format, axis_num, get_tick_fmt,
44
44
  make_trans,
45
- plot_border, plotly_style, sym_at, to_hex, x_grid,
45
+ plot_border, plotly_style, marks, to_hex, x_grid,
46
46
  )
47
47
  from .utils import band_width, fmt, get_option, kde, pretty
48
48
 
@@ -200,9 +200,10 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
200
200
  strip = "s" in vbs_plot
201
201
 
202
202
  # grouped replication measures, .param.VBS() group branch;
203
- # by and facet share the branch, as .param.VBS() does
204
- grp = by if by is not None else facet
205
- grp_ord = by_order if by is not None else facet_order
203
+ # by and facet share the branch, the facet levels when both are
204
+ # given (.param.VBS(): facet1 <- by0 only when facet1 is missing)
205
+ grp = facet if facet is not None else by
206
+ grp_ord = facet_order if facet is not None else by_order
206
207
  if grp is not None:
207
208
  mx_gc = max((grp == nm).sum() for nm in grp_ord)
208
209
  mc_w = max(int(np.unique(x[grp == nm],
@@ -210,7 +211,9 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
210
211
  for nm in grp_ord if (grp == nm).any())
211
212
  reps = (n - n_ux) / n > 0.15 and mc_w > 0.05 * n
212
213
 
213
- # jitter_x breaks ties in the data itself, as in X.R
214
+ # jitter_x breaks ties in the data itself, as in X.R; the violin
215
+ # bandwidth is read from the data as given, as .param.VBS() does
216
+ x_given = x.copy()
214
217
  if jitter_x is None:
215
218
  if grp is None:
216
219
  jitter_x = 1.1 * (1 - np.exp(-0.03 * mx_c))
@@ -256,13 +259,21 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
256
259
  box_fill = get_option("box_fill", "#419BD2")
257
260
  if box_color is None:
258
261
  box_color = get_option("box_color", "gray15")
259
- box_color = to_hex(box_color)
262
+ box_color = as_plotly_color(box_color)
260
263
 
261
264
  fig = go.Figure()
262
265
  val_fmt = get_tick_fmt(x, digits_d)
263
266
  vpart = f"%{{x:{val_fmt}}}" if val_fmt else "%{x}"
264
267
  rng_ = np.random.default_rng(n) # reproducible spread
265
268
  jy = 0.5 if jitter_y is None else float(jitter_y)
269
+ # the values plotted, for X()'s "Parameter values" report; one
270
+ # bandwidth only when one violin is drawn (facets take their own)
271
+ from .stats_out import record_stats
272
+ record_stats(pt_size=float(cex), out_size=float(out_cex),
273
+ jitter_x=float(jitter_x), jitter_y=jy,
274
+ bw=(float(bw) if bw is not None else
275
+ float(band_width(x_given, bw_iter)) if facet is None
276
+ else None))
266
277
 
267
278
  # facet units, first level in the TOP band (reading order, as
268
279
  # lessR as.table=TRUE); facet2 stacks one section of facet
@@ -326,7 +337,7 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
326
337
  # violin: mirrored KDE, max width = vbs_ratio
327
338
  if violin and len(xu) > 1:
328
339
  h = (bw if bw is not None
329
- else band_width(xu, bw_iter))
340
+ else band_width(x_given[um], bw_iter))
330
341
  grid = np.linspace(xu.min() - 3 * h,
331
342
  xu.max() + 3 * h, 512)
332
343
  dens = kde(xu, grid, h)
@@ -336,7 +347,7 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
336
347
  y=np.concatenate([yc + half,
337
348
  yc - half[::-1]]),
338
349
  mode="lines",
339
- line=dict(color=to_hex(violin_color), width=1),
350
+ line=dict(color=as_plotly_color(violin_color), width=1),
340
351
  fill="toself",
341
352
  fillcolor=as_plotly_color(violin_fill),
342
353
  hoverinfo="skip", showlegend=False,
@@ -397,21 +408,22 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
397
408
  len(pts))
398
409
  # by groups differ by color only; shape= (scalar or
399
410
  # per-group vector) overrides for every group
400
- sym = "circle" if shape is None else sym_at(shape, i)
401
411
  hover = f"{x_lab}: {vpart}"
402
412
  if nm is not None:
403
413
  hover += f"<br>{by_name}: {nm}"
404
414
  hover += lvl_part
405
415
  fig.add_trace(go.Scatter(
406
- x=pts, y=yj, mode="markers",
416
+ x=pts, y=yj,
407
417
  name=None if nm is None else str(nm),
408
- marker=dict(
409
- symbol=sym, size=px,
410
- color=make_trans(_col_for(pt_fill, i),
411
- 1 - pt_trans),
412
- line=dict(
413
- color=to_hex(_col_for(pt_color, i)),
414
- width=0.5)),
418
+ **marks("circle" if shape is None else shape, i,
419
+ "markers", dict(
420
+ size=px,
421
+ color=make_trans(_col_for(pt_fill, i),
422
+ 1 - pt_trans),
423
+ line=dict(
424
+ color=as_plotly_color(
425
+ _col_for(pt_color, i)),
426
+ width=0.5))),
415
427
  hovertemplate=hover + "<extra></extra>",
416
428
  showlegend=nm is not None and ui == 0,
417
429
  ))
@@ -444,8 +456,8 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
444
456
  mode="markers",
445
457
  marker=dict(
446
458
  symbol=out_shape, size=px_out,
447
- color=to_hex(o_fill),
448
- line=dict(color=to_hex(o_color),
459
+ color=as_plotly_color(o_fill),
460
+ line=dict(color=as_plotly_color(o_color),
449
461
  width=1)),
450
462
  hovertemplate=hover + "<extra></extra>",
451
463
  showlegend=False,
@@ -465,7 +477,7 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
465
477
  keep_i = cand[np.argsort(-np.abs(xu[cand]),
466
478
  kind="stable")][:out_cut]
467
479
  id_font = dict(
468
- color=to_hex(get_option("ID_color",
480
+ color=as_plotly_color(get_option("ID_color",
469
481
  "gray50")),
470
482
  size=max(8, round(float(ID_size) * 14)))
471
483
  for ii in keep_i:
@@ -486,8 +498,8 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
486
498
  annotations = []
487
499
  if n_fac > 1: # shaded strip label per band
488
500
  s_fill = as_plotly_color(get_option("strip_fill"))
489
- s_line = to_hex(get_option("strip_color"))
490
- s_text = to_hex(get_option("strip_text_color"))
501
+ s_line = as_plotly_color(get_option("strip_color"))
502
+ s_text = as_plotly_color(get_option("strip_text_color"))
491
503
  s_font = round(14 * get_option("axis_size", 0.9))
492
504
  strip_items = [(u["yc"] + _STRIP[0],
493
505
  u["yc"] + _STRIP[1], u["strip"])
@@ -519,22 +531,22 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
519
531
  shapes=shapes,
520
532
  annotations=annotations,
521
533
  template=None,
522
- plot_bgcolor=to_hex(style_opts["panel_fill"]),
523
- paper_bgcolor=to_hex(style_opts["window_fill"]),
534
+ plot_bgcolor=as_plotly_color(style_opts["panel_fill"]),
535
+ paper_bgcolor=as_plotly_color(style_opts["window_fill"]),
524
536
  height=(450 if n_fac == 1
525
537
  else 120 + 190 * n_fac
526
538
  + 40 * len(sec_strips)),
527
539
  )
528
540
  if n_grp > 1: # lattice key: top, one row
529
- leg_color = to_hex(style_opts["lab_color"])
541
+ leg_color = as_plotly_color(style_opts["lab_color"])
530
542
  fig.update_layout(legend=dict(
531
543
  orientation="h",
532
544
  x=0.5, xanchor="center", y=1.02, yanchor="bottom",
533
545
  font=dict(size=round(14 * get_option("axis_size",
534
546
  0.9)),
535
547
  family="Arial", color=leg_color),
536
- bgcolor=to_hex(style_opts["window_fill"]),
537
- bordercolor=to_hex("gray80"), borderwidth=1,
548
+ bgcolor=as_plotly_color(style_opts["window_fill"]),
549
+ bordercolor=as_plotly_color("gray80"), borderwidth=1,
538
550
  itemsizing="constant",
539
551
  ))
540
552
  if main: