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.
- lessPy/ANOVA.py +74 -15
- lessPy/Chart.py +431 -88
- lessPy/Correlation.py +40 -11
- lessPy/Flows.py +3 -3
- lessPy/Logit.py +15 -11
- lessPy/Regression.py +27 -21
- lessPy/X.py +280 -42
- lessPy/XY.py +1332 -239
- lessPy/__init__.py +12 -2
- lessPy/_themes.py +5007 -0
- lessPy/bc_items_plotly.py +33 -20
- lessPy/bc_plotly.py +27 -10
- lessPy/bubble_plotly.py +33 -17
- lessPy/corCFA.py +9 -5
- lessPy/corProp.py +8 -4
- lessPy/corReflect.py +8 -4
- lessPy/corReorder.py +8 -4
- lessPy/corScree.py +12 -8
- lessPy/data/StockPrice.csv +1401 -1386
- lessPy/details.py +17 -4
- lessPy/dn_plotly.py +74 -54
- lessPy/dot_plotly.py +9 -8
- lessPy/freq_poly_plotly.py +18 -11
- lessPy/getColors.py +247 -20
- lessPy/hier_plotly.py +41 -14
- lessPy/hs_plotly.py +23 -11
- lessPy/pie_plotly.py +1 -1
- lessPy/pivot.py +39 -9
- lessPy/plotly_utils.py +162 -29
- lessPy/plt_add.py +2 -7
- lessPy/plt_contour.py +6 -6
- lessPy/plt_contour_facet.py +3 -3
- lessPy/plt_mat_plotly.py +85 -12
- lessPy/plt_plotly.py +34 -18
- lessPy/plt_smooth.py +4 -4
- lessPy/plt_time.py +10 -3
- lessPy/prob_norm.py +7 -3
- lessPy/prob_tcut.py +7 -3
- lessPy/prob_znorm.py +7 -1
- lessPy/profile_plotly.py +5 -4
- lessPy/radar_plotly.py +4 -3
- lessPy/rcolors.py +461 -0
- lessPy/simCImean.py +7 -3
- lessPy/simCLT.py +7 -3
- lessPy/simFlips.py +7 -3
- lessPy/simMeans.py +7 -3
- lessPy/stats_out.py +257 -11
- lessPy/style.py +167 -0
- lessPy/sunflower_plotly.py +141 -0
- lessPy/ttest.py +17 -13
- lessPy/utils.py +146 -6
- lessPy/vbs_plotly.py +39 -27
- lessPy/x_console.py +763 -0
- {lesspython-0.2.0.dist-info → lesspython-0.3.1.dist-info}/METADATA +13 -2
- lesspython-0.3.1.dist-info/RECORD +89 -0
- {lesspython-0.2.0.dist-info → lesspython-0.3.1.dist-info}/WHEEL +1 -1
- lesspython-0.2.0.dist-info/RECORD +0 -84
- {lesspython-0.2.0.dist-info → lesspython-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {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=
|
|
599
|
-
paper_bgcolor=
|
|
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=
|
|
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=
|
|
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=
|
|
635
|
-
paper_bgcolor=
|
|
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.
|
|
12
|
-
"lab_size": 1.
|
|
13
|
-
"axis_size": 0.
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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,
|
|
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,
|
|
204
|
-
|
|
205
|
-
|
|
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 =
|
|
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(
|
|
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=
|
|
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,
|
|
416
|
+
x=pts, y=yj,
|
|
407
417
|
name=None if nm is None else str(nm),
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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=
|
|
448
|
-
line=dict(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=
|
|
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 =
|
|
490
|
-
s_text =
|
|
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=
|
|
523
|
-
paper_bgcolor=
|
|
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 =
|
|
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=
|
|
537
|
-
bordercolor=
|
|
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:
|