lessPython 0.3.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 (50) hide show
  1. lessPy/ANOVA.py +70 -11
  2. lessPy/Chart.py +49 -4
  3. lessPy/Correlation.py +39 -10
  4. lessPy/Flows.py +3 -3
  5. lessPy/Logit.py +14 -10
  6. lessPy/Regression.py +22 -18
  7. lessPy/X.py +3 -2
  8. lessPy/XY.py +528 -91
  9. lessPy/bc_items_plotly.py +2 -2
  10. lessPy/bc_plotly.py +6 -5
  11. lessPy/bubble_plotly.py +16 -15
  12. lessPy/corCFA.py +7 -3
  13. lessPy/corProp.py +7 -3
  14. lessPy/corReflect.py +7 -3
  15. lessPy/corReorder.py +7 -3
  16. lessPy/corScree.py +10 -6
  17. lessPy/dn_plotly.py +9 -9
  18. lessPy/dot_plotly.py +9 -8
  19. lessPy/freq_poly_plotly.py +6 -6
  20. lessPy/hier_plotly.py +5 -5
  21. lessPy/hs_plotly.py +7 -7
  22. lessPy/pie_plotly.py +1 -1
  23. lessPy/pivot.py +39 -9
  24. lessPy/plotly_utils.py +90 -26
  25. lessPy/plt_add.py +2 -7
  26. lessPy/plt_contour.py +6 -6
  27. lessPy/plt_contour_facet.py +3 -3
  28. lessPy/plt_mat_plotly.py +11 -10
  29. lessPy/plt_plotly.py +34 -18
  30. lessPy/plt_smooth.py +4 -4
  31. lessPy/prob_norm.py +5 -1
  32. lessPy/prob_tcut.py +5 -1
  33. lessPy/prob_znorm.py +5 -1
  34. lessPy/profile_plotly.py +5 -4
  35. lessPy/radar_plotly.py +4 -3
  36. lessPy/simCImean.py +5 -1
  37. lessPy/simCLT.py +5 -1
  38. lessPy/simFlips.py +5 -1
  39. lessPy/simMeans.py +5 -1
  40. lessPy/style.py +8 -1
  41. lessPy/sunflower_plotly.py +6 -5
  42. lessPy/ttest.py +13 -9
  43. lessPy/utils.py +103 -0
  44. lessPy/vbs_plotly.py +23 -22
  45. {lesspython-0.3.0.dist-info → lesspython-0.3.1.dist-info}/METADATA +8 -1
  46. lesspython-0.3.1.dist-info/RECORD +89 -0
  47. {lesspython-0.3.0.dist-info → lesspython-0.3.1.dist-info}/WHEEL +1 -1
  48. lesspython-0.3.0.dist-info/RECORD +0 -89
  49. {lesspython-0.3.0.dist-info → lesspython-0.3.1.dist-info}/licenses/LICENSE +0 -0
  50. {lesspython-0.3.0.dist-info → lesspython-0.3.1.dist-info}/top_level.txt +0 -0
lessPy/profile_plotly.py CHANGED
@@ -21,6 +21,7 @@ import plotly.graph_objects as go
21
21
 
22
22
  from .utils import get_option
23
23
  from .plotly_utils import (
24
+ as_plotly_color,
24
25
  axis_num, facet_layout, make_trans, plot_border, plotly_style,
25
26
  to_hex, y_grid,
26
27
  )
@@ -75,9 +76,9 @@ def profile_facet_plotly(cells, x_levels, series, y_tick, y_lab_tick,
75
76
  marker=dict(symbol="circle", size=px,
76
77
  sizemode="diameter",
77
78
  color=make_trans(fills[j], 1),
78
- line=dict(color=to_hex(fills[j]),
79
+ line=dict(color=as_plotly_color(fills[j]),
79
80
  width=1)),
80
- line=dict(color=to_hex(fills[j]), width=ln_width),
81
+ line=dict(color=as_plotly_color(fills[j]), width=ln_width),
81
82
  hovertemplate=hover,
82
83
  showlegend=grouped and i == 0,
83
84
  ))
@@ -114,8 +115,8 @@ def profile_facet_plotly(cells, x_levels, series, y_tick, y_lab_tick,
114
115
  yanchor="top", font=dict(size=title_size))
115
116
  if main else None),
116
117
  template=None,
117
- plot_bgcolor=to_hex(style_opts["panel_fill"]),
118
- paper_bgcolor=to_hex(style_opts["window_fill"]),
118
+ plot_bgcolor=as_plotly_color(style_opts["panel_fill"]),
119
+ paper_bgcolor=as_plotly_color(style_opts["window_fill"]),
119
120
  **axes,
120
121
  )
121
122
  return fig
lessPy/radar_plotly.py CHANGED
@@ -20,6 +20,7 @@ import plotly.graph_objects as go
20
20
 
21
21
  from .utils import get_option
22
22
  from .plotly_utils import (
23
+ as_plotly_color,
23
24
  BASE_COLORS, facet_layout, make_trans, plotly_style, to_hex,
24
25
  )
25
26
 
@@ -182,7 +183,7 @@ def radar_plotly(x=None, x_name=None, by_name=None, main=None,
182
183
  text=main, x=0.5, xanchor="center",
183
184
  y=0.97, yanchor="top",
184
185
  font=dict(size=title_size,
185
- color=to_hex(get_option("lab_color",
186
+ color=as_plotly_color(get_option("lab_color",
186
187
  "black")))),
187
188
  margin=dict(t=round(title_size * 2.2), b=10,
188
189
  l=20 if n_fac == 1 else r_margin,
@@ -191,11 +192,11 @@ def radar_plotly(x=None, x_name=None, by_name=None, main=None,
191
192
  annotations=anns,
192
193
  legend=dict(
193
194
  x=1.02, xanchor="left", y=1.0, yanchor="top",
194
- bordercolor=to_hex(style_opts["panel_border"]),
195
+ bordercolor=as_plotly_color(style_opts["panel_border"]),
195
196
  borderwidth=1,
196
197
  font=dict(size=round(18 * ax_cex)),
197
198
  ),
198
199
  template=None,
199
- paper_bgcolor=to_hex(style_opts["window_fill"]),
200
+ paper_bgcolor=as_plotly_color(style_opts["window_fill"]),
200
201
  )
201
202
  return fig
lessPy/simCImean.py CHANGED
@@ -15,7 +15,7 @@
15
15
 
16
16
  import numpy as np
17
17
 
18
- from .utils import fmt, show_plots
18
+ from .utils import fmt, file_output, show_plots
19
19
 
20
20
 
21
21
  class SimCImeanResults:
@@ -163,3 +163,7 @@ def _report(ns, n, ymean, ysd, se, E, lb, ub, hit, mu, sigma, cl,
163
163
  print(f" Mean: {fmt(ymean.mean(), d2):>{w}}")
164
164
  print(f"Std Dev: {fmt(ymean.std(ddof=1), d2):>{w}}")
165
165
  print()
166
+
167
+
168
+ # pdf_file= and png_file= write the figures, as lessR's pdf_file=
169
+ simCImean = file_output(simCImean)
lessPy/simCLT.py CHANGED
@@ -21,7 +21,7 @@
21
21
 
22
22
  import numpy as np
23
23
 
24
- from .utils import fmt, show_plots
24
+ from .utils import fmt, file_output, show_plots
25
25
 
26
26
  _GHOST = "#F8F8FF"
27
27
  _STEEL = "#A2B5CD" # lightsteelblue3
@@ -263,3 +263,7 @@ def _report(dist, mu, sigma, skew, med, ns, n, mx, sx, ymean,
263
263
  print(f" Mean: {fmt(ymean[i], digits_d)}")
264
264
  print(f" Rounded Data Values: {vals}")
265
265
  print()
266
+
267
+
268
+ # pdf_file= and png_file= write the figures, as lessR's pdf_file=
269
+ simCLT = file_output(simCLT)
lessPy/simFlips.py CHANGED
@@ -12,7 +12,7 @@
12
12
 
13
13
  import numpy as np
14
14
 
15
- from .utils import fmt, show_plots
15
+ from .utils import fmt, file_output, show_plots
16
16
 
17
17
 
18
18
  class SimFlipsResults:
@@ -102,3 +102,7 @@ def _plot(n, flips, ybar, prob, grid, show_flips, show_title,
102
102
  title=dict(text=title, x=0.5, xanchor="center",
103
103
  font=dict(size=12)))
104
104
  return fig
105
+
106
+
107
+ # pdf_file= and png_file= write the figures, as lessR's pdf_file=
108
+ simFlips = file_output(simFlips)
lessPy/simMeans.py CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  import numpy as np
18
18
 
19
- from .utils import fmt, show_plots
19
+ from .utils import fmt, file_output, show_plots
20
20
 
21
21
 
22
22
  class SimMeansResults:
@@ -144,3 +144,7 @@ def _report(ns, n, o, ymean, ysd, data, mu, sigma, max_data,
144
144
  " Direct estimate of the standard error of the "
145
145
  "sample mean")
146
146
  print()
147
+
148
+
149
+ # pdf_file= and png_file= write the figures, as lessR's pdf_file=
150
+ simMeans = file_output(simMeans)
lessPy/style.py CHANGED
@@ -116,10 +116,17 @@ def style(theme=None, sub_theme=None, set=None, get=False, reset=True,
116
116
 
117
117
  for k, v in settings.items():
118
118
  utils._OPTIONS[k] = v
119
+ # the line that connects the points of a single series takes
120
+ # segment_color only when it is given, otherwise color. A
121
+ # theme, applied above, starts from neither. R analog:
122
+ # style() option segment_color_set
123
+ if "segment_color" in settings:
124
+ utils._OPTIONS["segment_color_set"] = True
119
125
 
120
126
  if get:
121
127
  return {k: copy.deepcopy(utils._OPTIONS.get(k))
122
- for k in sorted(keys | {"theme", "sub_theme"})}
128
+ for k in sorted(keys | {"theme", "sub_theme",
129
+ "segment_color_set"})}
123
130
  return None
124
131
 
125
132
 
@@ -16,6 +16,7 @@ import numpy as np
16
16
  import plotly.graph_objects as go
17
17
 
18
18
  from .plotly_utils import (
19
+ as_plotly_color,
19
20
  axis_format, axis_num, facet_fig, facet_panels, finish_facet,
20
21
  make_trans, plot_border, plotly_style, to_hex, x_grid,
21
22
  )
@@ -57,10 +58,10 @@ def _panel_traces(x, y, xr, yr, w_px, h_px, fill, color, pt_size,
57
58
  px = max(3.0, 5.5 * float(pt_size))
58
59
  return [
59
60
  go.Scatter(x=sx, y=sy, mode="lines",
60
- line=dict(color=to_hex(color), width=1),
61
+ line=dict(color=as_plotly_color(color), width=1),
61
62
  hoverinfo="skip", showlegend=False),
62
63
  go.Scatter(x=xx, y=yy, mode="markers",
63
- marker=dict(size=px, color=to_hex(fill),
64
+ marker=dict(size=px, color=as_plotly_color(fill),
64
65
  line=dict(width=0)),
65
66
  customdata=cnt, hovertemplate=hover,
66
67
  showlegend=False)]
@@ -104,13 +105,13 @@ def sunflower_plotly(x, y, x_lab, y_lab, main=None, facet=None,
104
105
  axis_fmt, axis_y_pre))
105
106
  ax_x.update(range=list(xr))
106
107
  ax_y.update(range=list(yr), showgrid=True,
107
- gridcolor=to_hex(style_opts["grid_col"]),
108
+ gridcolor=as_plotly_color(style_opts["grid_col"]),
108
109
  gridwidth=1, griddash="dot")
109
110
  fig.update_layout(
110
111
  xaxis=ax_x, yaxis=ax_y, template=None,
111
112
  shapes=x_grid(axT1) + plot_border(),
112
- plot_bgcolor=to_hex(style_opts["panel_fill"]),
113
- paper_bgcolor=to_hex(style_opts["window_fill"]))
113
+ plot_bgcolor=as_plotly_color(style_opts["panel_fill"]),
114
+ paper_bgcolor=as_plotly_color(style_opts["window_fill"]))
114
115
  else:
115
116
  labels, pos, sel, n_row_g, n_col = facet_panels(
116
117
  facet, facet_order, facet2, facet2_order, facet_name,
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, show_plots
27
+ from .utils import fmt, get_column, get_option, file_output, show_plots
28
28
 
29
29
 
30
30
  class ttestResults:
@@ -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
@@ -310,3 +310,106 @@ def show_plots(result):
310
310
  warnings.warn(f"figures not displayed ({e}); they are "
311
311
  "in .plots, show one with .show()")
312
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
 
@@ -259,7 +259,7 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
259
259
  box_fill = get_option("box_fill", "#419BD2")
260
260
  if box_color is None:
261
261
  box_color = get_option("box_color", "gray15")
262
- box_color = to_hex(box_color)
262
+ box_color = as_plotly_color(box_color)
263
263
 
264
264
  fig = go.Figure()
265
265
  val_fmt = get_tick_fmt(x, digits_d)
@@ -347,7 +347,7 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
347
347
  y=np.concatenate([yc + half,
348
348
  yc - half[::-1]]),
349
349
  mode="lines",
350
- line=dict(color=to_hex(violin_color), width=1),
350
+ line=dict(color=as_plotly_color(violin_color), width=1),
351
351
  fill="toself",
352
352
  fillcolor=as_plotly_color(violin_fill),
353
353
  hoverinfo="skip", showlegend=False,
@@ -408,21 +408,22 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
408
408
  len(pts))
409
409
  # by groups differ by color only; shape= (scalar or
410
410
  # per-group vector) overrides for every group
411
- sym = "circle" if shape is None else sym_at(shape, i)
412
411
  hover = f"{x_lab}: {vpart}"
413
412
  if nm is not None:
414
413
  hover += f"<br>{by_name}: {nm}"
415
414
  hover += lvl_part
416
415
  fig.add_trace(go.Scatter(
417
- x=pts, y=yj, mode="markers",
416
+ x=pts, y=yj,
418
417
  name=None if nm is None else str(nm),
419
- marker=dict(
420
- symbol=sym, size=px,
421
- color=make_trans(_col_for(pt_fill, i),
422
- 1 - pt_trans),
423
- line=dict(
424
- color=to_hex(_col_for(pt_color, i)),
425
- 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))),
426
427
  hovertemplate=hover + "<extra></extra>",
427
428
  showlegend=nm is not None and ui == 0,
428
429
  ))
@@ -455,8 +456,8 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
455
456
  mode="markers",
456
457
  marker=dict(
457
458
  symbol=out_shape, size=px_out,
458
- color=to_hex(o_fill),
459
- line=dict(color=to_hex(o_color),
459
+ color=as_plotly_color(o_fill),
460
+ line=dict(color=as_plotly_color(o_color),
460
461
  width=1)),
461
462
  hovertemplate=hover + "<extra></extra>",
462
463
  showlegend=False,
@@ -476,7 +477,7 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
476
477
  keep_i = cand[np.argsort(-np.abs(xu[cand]),
477
478
  kind="stable")][:out_cut]
478
479
  id_font = dict(
479
- color=to_hex(get_option("ID_color",
480
+ color=as_plotly_color(get_option("ID_color",
480
481
  "gray50")),
481
482
  size=max(8, round(float(ID_size) * 14)))
482
483
  for ii in keep_i:
@@ -497,8 +498,8 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
497
498
  annotations = []
498
499
  if n_fac > 1: # shaded strip label per band
499
500
  s_fill = as_plotly_color(get_option("strip_fill"))
500
- s_line = to_hex(get_option("strip_color"))
501
- 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"))
502
503
  s_font = round(14 * get_option("axis_size", 0.9))
503
504
  strip_items = [(u["yc"] + _STRIP[0],
504
505
  u["yc"] + _STRIP[1], u["strip"])
@@ -530,22 +531,22 @@ def vbs_plotly(x, x_name=None, vbs_plot="vbs",
530
531
  shapes=shapes,
531
532
  annotations=annotations,
532
533
  template=None,
533
- plot_bgcolor=to_hex(style_opts["panel_fill"]),
534
- 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"]),
535
536
  height=(450 if n_fac == 1
536
537
  else 120 + 190 * n_fac
537
538
  + 40 * len(sec_strips)),
538
539
  )
539
540
  if n_grp > 1: # lattice key: top, one row
540
- leg_color = to_hex(style_opts["lab_color"])
541
+ leg_color = as_plotly_color(style_opts["lab_color"])
541
542
  fig.update_layout(legend=dict(
542
543
  orientation="h",
543
544
  x=0.5, xanchor="center", y=1.02, yanchor="bottom",
544
545
  font=dict(size=round(14 * get_option("axis_size",
545
546
  0.9)),
546
547
  family="Arial", color=leg_color),
547
- bgcolor=to_hex(style_opts["window_fill"]),
548
- bordercolor=to_hex("gray80"), borderwidth=1,
548
+ bgcolor=as_plotly_color(style_opts["window_fill"]),
549
+ bordercolor=as_plotly_color("gray80"), borderwidth=1,
549
550
  itemsizing="constant",
550
551
  ))
551
552
  if main:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lessPython
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Python port of R's lessR: analytic-view visualizations, statistical models, and data utilities, rendered with plotly
5
5
  Author-email: "David W. Gerbing" <gerbing@pdx.edu>
6
6
  License-Expression: GPL-2.0-or-later
@@ -119,6 +119,13 @@ when the analysis runs, even when the result is assigned, as
119
119
  `r = lp.Regression(...)`. From a script, show one with
120
120
  `r.plots["scatter"].show()`.
121
121
 
122
+ Every function that draws also takes `pdf_file=` and `png_file=`
123
+ (needs the png extra, `pip install "lessPython[png]"`, then
124
+ `plotly_get_chrome -y` once). A name such as `png_file="reg"`
125
+ names the file, or with several figures is the stem of each
126
+ name (`reg_scatter_matrix.png`), as lessR's `pdf_file=`. On Colab
127
+ the files also download to your computer.
128
+
122
129
  ## Development install
123
130
 
124
131
  ```
@@ -0,0 +1,89 @@
1
+ lessPy/ANOVA.py,sha256=p0IUM004vGTKEHl_VAgyf-f_1NnklR8KWx_YdsNOerU,30437
2
+ lessPy/Chart.py,sha256=MYM4Ji5DHstRg2bp9sMjDvCDWLf-cHW9PLjzG6zel2U,90920
3
+ lessPy/Correlation.py,sha256=QdeSiVmaDjE_iNPvAsoZx5a1xBJ1g1t-ZtZrW2zDimU,10331
4
+ lessPy/Flows.py,sha256=5wfIZQGlOsALFinZDpioIR79uJfqn3YrNBLHFb8JGNk,4898
5
+ lessPy/Logit.py,sha256=zuDxYgBjSSt6rM5EIhBA5Ug5p26o4MforABOiE4MkJU,25426
6
+ lessPy/Prop_test.py,sha256=mSYiQdTN7gpF5oMBAjFgicH9-YarJojgAEBnxQg17Og,10452
7
+ lessPy/Regression.py,sha256=WEyf2JhfkKYc73buJVREVaivq0CkXfxuRtRIU2qO3us,61638
8
+ lessPy/VariableLabels.py,sha256=eoRVwDLFQZvvLD-UBePD3BJG1yLVgBJqtmbzfAWOkzI,4336
9
+ lessPy/X.py,sha256=68KnSUtS3icBXeurJlRyRZ3VePhq6Q-h-qAbUidoB68,29369
10
+ lessPy/XY.py,sha256=NnY2vXSJln1dMONpVjtvOrINVYj0qs61sRj6aQBY7yg,136311
11
+ lessPy/__init__.py,sha256=QYPMfVx3LsO4ua59W0h7DxOogsAAgG_aIihu47nmn6U,2773
12
+ lessPy/_themes.py,sha256=ILPfwoqSeFQZyewXX_g_1-s4F3DXO0a1mCPaHulX1Y8,228371
13
+ lessPy/anova_rmd.py,sha256=kc7KtBZU4FF0Q3T1UJvEqq22imtqwJ8ppu9yC_8iTAk,8436
14
+ lessPy/bc_items_plotly.py,sha256=Dz45CfA-s1mHJWXH_5pbFviTV_1E75cFMQVcB0Eeal4,8862
15
+ lessPy/bc_plotly.py,sha256=bZMZDovUKJ2-Ou7zBZsx1SKY50cJSqRk5TbkcH94EQQ,26583
16
+ lessPy/bubble_plotly.py,sha256=nKy5s2VDdBjMOz1wlcp232nSyhhds9mlhFSOIs_OSXM,19107
17
+ lessPy/corCFA.py,sha256=PQsq44xvK9kaL2wFETAUfFpZ5Nabj5Rgarjjr9ArL_Q,11783
18
+ lessPy/corEFA.py,sha256=-umpIEYeT6efN8AkZMlCqOyL8V-e2TqaadHRpuoi7yA,7606
19
+ lessPy/corPrint.py,sha256=kV6ZOu03Cm9j16uCA-An6XvLXbNa3_rRUPhE7zT6zqk,1575
20
+ lessPy/corProp.py,sha256=ObDN6zFuLmc1JZFpdzaW_EiDJGr4Q9NkWl4KJWfgAhE,2934
21
+ lessPy/corRead.py,sha256=VsvdQIYYk8MRHvUCeVx659yGKaeWk8sYeDy7ulu3VUo,2096
22
+ lessPy/corReflect.py,sha256=RhCIt9wybBr-Q5P-UJxIVJBhGCyeciKZ3gKg7vop-pw,2912
23
+ lessPy/corReorder.py,sha256=hYk_fxysyINdt6fSVoKKvu5yz3TeGYODL4AXv9jVr6M,6180
24
+ lessPy/corScree.py,sha256=U3ud1tTwKZGmVROGZlorrlFvLIbMZx9HVMver1k5iCE,3355
25
+ lessPy/datasets.py,sha256=8YiYdcRZJa-UiB4xs3ciZmOfd4ARy3rIJFddY-qdKm4,1690
26
+ lessPy/date_infer.py,sha256=OgTMy5eeu1hhW314FTv034Pl9kthmM2H0kYAeWQObx0,4302
27
+ lessPy/details.py,sha256=kz33hIl0_im0M2G-xF-Hb-e9z87kKOkfC5piJ9Xzd7s,11435
28
+ lessPy/dn_plotly.py,sha256=LdHV0e8opWqkXycXLzNfPCJZLqYvyZc1qVaS230PQ_s,20782
29
+ lessPy/dot_plotly.py,sha256=_yTrkxPhpeLJVFXQ42OoXL52xL8hCRHupzCxMgBnj4E,18660
30
+ lessPy/freq_poly_plotly.py,sha256=3U7yaGU4BGkKbK6qyQIlxtDB81FAoaw3KB8HClFZxpk,12816
31
+ lessPy/getColors.py,sha256=fKKJHmBw8S5BM1636Iaxt1ge1zDFbKweNApf_lE2qqE,22528
32
+ lessPy/hier_plotly.py,sha256=ZH5FKI7SWjRjohgk5LrbPsoVFC4I75kNYTpfFIaN0_o,16376
33
+ lessPy/hs_plotly.py,sha256=Q29ifoZSOVrw2REiID0W-Ta5mo2b5OW4fR5aX_NHpb4,15560
34
+ lessPy/logit_rmd.py,sha256=Wf5f5vRTfxUG467Lad2irMYPSFqvsE5dpvQSG8Aeyzo,15646
35
+ lessPy/order_by.py,sha256=LpqV95REi33CPXxEyFSsM52LqxqkdRFuHIx3D37Bchg,3150
36
+ lessPy/pie_plotly.py,sha256=mLaFTMxemLws--v06-1emJaAfg2VA9eLsCMLmyBX07M,11054
37
+ lessPy/pivot.py,sha256=p6Nq-YUvy7qH9agFMD2cWQ-7AeC7Sjwg-Ax7KubuexE,7705
38
+ lessPy/plotly_utils.py,sha256=YFnPBVU4vOmQDeuugsyPFX5gvxFmcbItKpyVSa8PkMs,37976
39
+ lessPy/plt_add.py,sha256=RjVZoZS4Y2m1ip6-oauwabc2QM_TjJVIPjOXhN6xuQs,5086
40
+ lessPy/plt_contour.py,sha256=1PfxF47ogk5LkDuAdrNZY50OcusKDpFhyuqk05DFpa4,7317
41
+ lessPy/plt_contour_facet.py,sha256=_rRPIiNlW2It-JA8IyqM9qav7sVV6zwDSJoEPL0e6a8,8183
42
+ lessPy/plt_forecast.py,sha256=rIlHbvKL9psCjc2ZebnfHomCzqaMn9PAZxeWNzQOQus,26095
43
+ lessPy/plt_mat_plotly.py,sha256=zcd1kfrAKGZSSgd4Nh4ocnaP-Ztos_29PEK-qF_RsPI,11888
44
+ lessPy/plt_plotly.py,sha256=2EfgZ9Q_yrV6eupxXZsMyRFiVsg7cIjYUwZPl8ZFFCI,9591
45
+ lessPy/plt_smooth.py,sha256=FuGPqrAf4sxL1AIIjoMkf6bRXH8ICL4JAA6s9g9mZxo,6835
46
+ lessPy/plt_time.py,sha256=kaloqSiiDC-10c3xH_qyZ8r9ztTkoJcn3NIzmQFHDBU,6003
47
+ lessPy/prob_norm.py,sha256=QcfRAiFtPlDEtCxSZimONgz_LddgxjkH58dF8MXMg0M,4257
48
+ lessPy/prob_tcut.py,sha256=aM8whjdcC3x2olcNbzIVBer7VDRK7w77I7ohiiRwSb4,5139
49
+ lessPy/prob_znorm.py,sha256=WPE9CWEHntue0ywmwj_8uK9OqurM60fVHPBDg7PihUg,4583
50
+ lessPy/profile_plotly.py,sha256=3fygow-7isg_sHGMMO3rhhWtFknwv9Ng8gVrVyYvXoQ,5224
51
+ lessPy/radar_plotly.py,sha256=xr6WQH8Q-3eBwcepF1gm8B5oJnR7OVjh0Ed9S73kNYI,7367
52
+ lessPy/rcolors.py,sha256=kr5GmImQkYyYnX4GBcDIxmL4pge47aktnwgJkWwGrnM,13129
53
+ lessPy/reg_rmd.py,sha256=B3bGyNL4t9GDtv2aNW5x7ki41uGD_lHJOCe9ZbO-if4,28958
54
+ lessPy/rename.py,sha256=83iwwCidpfi1hm7r4XgsZYeAs2MPHGfueo_UVyVqygc,1244
55
+ lessPy/reshape.py,sha256=KnaFgcRAervP8FSZvYMYw9PXEeP7ecNCLHx1wO91xBU,4035
56
+ lessPy/showColors.py,sha256=y1Qh4kYWbe0YRUyKwSXWWf3ctz8ub1ctnltrmy940IU,5948
57
+ lessPy/simCImean.py,sha256=vfO6xs8u1l7jWkHZ6btxEWRBEAEI-mIB3utDv9r0XzE,6470
58
+ lessPy/simCLT.py,sha256=3rWeMP_VPNIN41bEfOpaamB9kfpkphFblqJFXT-akqQ,10113
59
+ lessPy/simFlips.py,sha256=7O4EoKeNSV8mknsYXawYqCAa8oHyuqFRAhp18s8ZAMc,4161
60
+ lessPy/simMeans.py,sha256=_j7jTPf5ZaHdjGm5OLvb20lCHWoJlA_BBdfHaRiVLEM,5564
61
+ lessPy/stats_out.py,sha256=cbpe8a_OPPOy3WL8s4ZLke6SUYffSK0BR0KExHMN8ok,30564
62
+ lessPy/style.py,sha256=i9W_bVxId7AV3RMzIWebVe3aZYIFfdG6u_ZJGadC0aM,6375
63
+ lessPy/sunflower_plotly.py,sha256=BQfFekQxD-kexOfBiU5cAD_wJyIITXZFxMWSxseYZ6Q,6008
64
+ lessPy/ttest.py,sha256=fP47ziTnoR2S-tOL9CCZONM6kKkpXQxDdlLqJhqgG9w,25033
65
+ lessPy/utils.py,sha256=-CKALbfFEvPYYvsuZ9m8tLf-yZajr2b684eGBMrx09s,15261
66
+ lessPy/vbs_plotly.py,sha256=N68bh7ii9k7qxVYWZNqqEfUVP3abyae8Ywom4tP8tvU,24059
67
+ lessPy/x_console.py,sha256=rj5k2uISIYM2tQgd48E5yJ0-OlAeCYTJ7sUdfy94Sw4,28879
68
+ lessPy/data/Anova_1way.csv,sha256=lA1ZXx7d471QDVXs9E0Chd7FEyCYH1S2FrJVtnp50r8,294
69
+ lessPy/data/Anova_2way.csv,sha256=XJwu_Y12-JZhOMTAOXbIRA0rfNjwkSGPmgJWlMyF8lY,923
70
+ lessPy/data/Anova_rb.csv,sha256=lU5V_TK7F6PigUZa4GLlBEpJsesncb-mswGi9PmxZJg,128
71
+ lessPy/data/Anova_rbf.csv,sha256=WshzhSatbAnR40NSXEWp97JaXwx8CpgDiLVoFXB3mho,1315
72
+ lessPy/data/Anova_sp.csv,sha256=DSuabe7xndzOoRBYotTIE8LlxPULpiZ7MhicriDfB_8,1128
73
+ lessPy/data/BodyMeas.csv,sha256=Z6HR9Xf9igbuwaIglWyqU2Stv9pYMHHDIoGncLtdsnA,8861
74
+ lessPy/data/Cars93.csv,sha256=A3X2C6A9_8USE9uMTfMpBGWfVbi8u-jM_JyJlVWSv5c,10149
75
+ lessPy/data/Employee.csv,sha256=DYUXu_b6uDZNHcXq-5RoGx9IzdnIx__L9D8-qbHnLT8,2054
76
+ lessPy/data/Employee_lbl.csv,sha256=Yzq998mPzRvrufcnpDt0RYK_kLvDJur0IrCmQpj-GMc,331
77
+ lessPy/data/FreqTable99.csv,sha256=mkroqRikxvLzVDiuaD_qJbATWyA-OCPjj-DmayjHH00,72
78
+ lessPy/data/Jackets.csv,sha256=prNRSZpbg928w6AcbzZBiXxeFcpQhsutcNWtu9GTWeU,14524
79
+ lessPy/data/Learn.csv,sha256=fUSWxUEVgxNeCKgvzR9tQN2AyUJarW4UMweXDCmd9Ew,346
80
+ lessPy/data/Mach4.csv,sha256=fRzeipGfzSpzZHWjqHnYRAxD8Jb7R73H1zSGyfdP3Us,14871
81
+ lessPy/data/Mach4_lbl.csv,sha256=okp93EBnSXi4GsXg09M1evwwRiZ77MmCr6VmBgSJbpI,1582
82
+ lessPy/data/Reading.csv,sha256=4RZ9colCorvGSB7qjZCjtpT6t8wCPOUz2siVsdnjpGA,1162
83
+ lessPy/data/StockPrice.csv,sha256=EV9I1PK3ee3hFSLoqZi-4UFESLGD9zAS2zkg3j65iKI,66774
84
+ lessPy/data/WeightLoss.csv,sha256=Iw3P0jHBVXZgESpvfrOzC_Vgg0TVHiPo0ktesmP55qA,234
85
+ lesspython-0.3.1.dist-info/licenses/LICENSE,sha256=7a72Msu2Q-TnoiFxemxEGkwafJGObk1W3rw9hzmyM_Y,17984
86
+ lesspython-0.3.1.dist-info/METADATA,sha256=B24tLpagrqm3Ki4L7SF3odBKAokxUTk3wOaCrK1soqM,5142
87
+ lesspython-0.3.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
88
+ lesspython-0.3.1.dist-info/top_level.txt,sha256=zwwOr1PSYgRRXTloRB9jFgrQW9_l-aahPmcEtTpCkgo,7
89
+ lesspython-0.3.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (84.0.0)
2
+ Generator: setuptools (84.2.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5