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.
- lessPy/ANOVA.py +70 -11
- lessPy/Chart.py +49 -4
- lessPy/Correlation.py +39 -10
- lessPy/Flows.py +3 -3
- lessPy/Logit.py +14 -10
- lessPy/Regression.py +22 -18
- lessPy/X.py +3 -2
- lessPy/XY.py +528 -91
- lessPy/bc_items_plotly.py +2 -2
- lessPy/bc_plotly.py +6 -5
- lessPy/bubble_plotly.py +16 -15
- lessPy/corCFA.py +7 -3
- lessPy/corProp.py +7 -3
- lessPy/corReflect.py +7 -3
- lessPy/corReorder.py +7 -3
- lessPy/corScree.py +10 -6
- lessPy/dn_plotly.py +9 -9
- lessPy/dot_plotly.py +9 -8
- lessPy/freq_poly_plotly.py +6 -6
- lessPy/hier_plotly.py +5 -5
- lessPy/hs_plotly.py +7 -7
- lessPy/pie_plotly.py +1 -1
- lessPy/pivot.py +39 -9
- lessPy/plotly_utils.py +90 -26
- lessPy/plt_add.py +2 -7
- lessPy/plt_contour.py +6 -6
- lessPy/plt_contour_facet.py +3 -3
- lessPy/plt_mat_plotly.py +11 -10
- lessPy/plt_plotly.py +34 -18
- lessPy/plt_smooth.py +4 -4
- lessPy/prob_norm.py +5 -1
- lessPy/prob_tcut.py +5 -1
- lessPy/prob_znorm.py +5 -1
- lessPy/profile_plotly.py +5 -4
- lessPy/radar_plotly.py +4 -3
- lessPy/simCImean.py +5 -1
- lessPy/simCLT.py +5 -1
- lessPy/simFlips.py +5 -1
- lessPy/simMeans.py +5 -1
- lessPy/style.py +8 -1
- lessPy/sunflower_plotly.py +6 -5
- lessPy/ttest.py +13 -9
- lessPy/utils.py +103 -0
- lessPy/vbs_plotly.py +23 -22
- {lesspython-0.3.0.dist-info → lesspython-0.3.1.dist-info}/METADATA +8 -1
- lesspython-0.3.1.dist-info/RECORD +89 -0
- {lesspython-0.3.0.dist-info → lesspython-0.3.1.dist-info}/WHEEL +1 -1
- lesspython-0.3.0.dist-info/RECORD +0 -89
- {lesspython-0.3.0.dist-info → lesspython-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {lesspython-0.3.0.dist-info → lesspython-0.3.1.dist-info}/top_level.txt +0 -0
lessPy/pivot.py
CHANGED
|
@@ -45,8 +45,10 @@ def pivot(data, compute, variable=None, by=None, filter=None,
|
|
|
45
45
|
"""Aggregate a numeric variable over by groups, or tabulate
|
|
46
46
|
frequencies. compute is a statistic name or a list of names
|
|
47
47
|
("mean", ["mean","sd"], "table"); variable is the numeric
|
|
48
|
-
column to aggregate
|
|
49
|
-
|
|
48
|
+
column to aggregate, or a list of them, each then with its own
|
|
49
|
+
{variable}_n, {variable}_na, and statistic columns; by is the
|
|
50
|
+
grouping column(s). Returns a long-form DataFrame.
|
|
51
|
+
R analog: pivot()"""
|
|
50
52
|
if filter is not None:
|
|
51
53
|
data = data.query(filter)
|
|
52
54
|
computes = [compute] if isinstance(compute, str) \
|
|
@@ -72,16 +74,44 @@ def pivot(data, compute, variable=None, by=None, filter=None,
|
|
|
72
74
|
raise ValueError(
|
|
73
75
|
f"unknown compute {unknown}; use "
|
|
74
76
|
f"{', '.join(_STAT)}, or \"table\"")
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
variables = (list(variable) if isinstance(variable, (list, tuple))
|
|
78
|
+
else [variable])
|
|
79
|
+
for var in variables:
|
|
80
|
+
v = get_column(data, var, "variable")
|
|
81
|
+
if not pd.api.types.is_numeric_dtype(v):
|
|
82
|
+
raise TypeError(
|
|
83
|
+
f"the variable to aggregate '{var}' is "
|
|
84
|
+
f"{v.dtype}: it must be numeric. Put categorical "
|
|
85
|
+
"variables in by=.")
|
|
81
86
|
if not by:
|
|
82
87
|
raise ValueError("by= is required: the grouping "
|
|
83
88
|
"column(s)")
|
|
84
|
-
|
|
89
|
+
if len(variables) == 1:
|
|
90
|
+
return _pivot_agg(data, variables[0], by, computes, show_n,
|
|
91
|
+
sort)
|
|
92
|
+
if len(computes) > 1: # R pivot.R
|
|
93
|
+
raise ValueError(
|
|
94
|
+
"Cannot have multiple compute functions, multiple "
|
|
95
|
+
"variables,\n and do aggregation with a by variable. "
|
|
96
|
+
"Choose two of the three")
|
|
97
|
+
# several variables: each its own n, na, and statistic, side by
|
|
98
|
+
# side over the same by groups, as R's Sales_n, Sales_na,
|
|
99
|
+
# Sales_sum, Profit_n, ...
|
|
100
|
+
parts = []
|
|
101
|
+
for var in variables:
|
|
102
|
+
a = _pivot_agg(data, var, by, computes, True, None)
|
|
103
|
+
parts.append(a.drop(columns=by).rename(
|
|
104
|
+
columns={"n": f"{var}_n", "na": f"{var}_na"}))
|
|
105
|
+
out = pd.concat([a[by]] + parts, axis=1)
|
|
106
|
+
if sort is not None:
|
|
107
|
+
stat_col = out.columns[-1]
|
|
108
|
+
out = out.sort_values(
|
|
109
|
+
stat_col, ascending=(sort == "+"),
|
|
110
|
+
na_position="last", kind="stable").reset_index(drop=True)
|
|
111
|
+
if not show_n:
|
|
112
|
+
out = out.drop(columns=[c for v_ in variables
|
|
113
|
+
for c in (f"{v_}_n", f"{v_}_na")])
|
|
114
|
+
return out
|
|
85
115
|
|
|
86
116
|
|
|
87
117
|
def _cat_frame(data, by):
|
lessPy/plotly_utils.py
CHANGED
|
@@ -264,14 +264,14 @@ def legend_style(by_name, style_opts, title=None, position=None,
|
|
|
264
264
|
title=dict(text=abbrev(text, abbrev_n) or "",
|
|
265
265
|
font=dict(size=round(
|
|
266
266
|
15 * get_option("lab_size", 1) * mult),
|
|
267
|
-
color=
|
|
267
|
+
color=as_plotly_color(style_opts["lab_color"]))),
|
|
268
268
|
# the legend reads in the theme's label color, light on the
|
|
269
269
|
# black sub_theme as the axis labels are
|
|
270
270
|
font=dict(size=round(
|
|
271
271
|
16 * get_option("axis_size", 0.9) * mult),
|
|
272
|
-
color=
|
|
273
|
-
bgcolor=
|
|
274
|
-
bordercolor=
|
|
272
|
+
color=as_plotly_color(style_opts["lab_color"])),
|
|
273
|
+
bgcolor=as_plotly_color(style_opts["window_fill"]),
|
|
274
|
+
bordercolor=as_plotly_color(style_opts["legend_border"]),
|
|
275
275
|
borderwidth=1,
|
|
276
276
|
)
|
|
277
277
|
# placement stays plotly's own unless asked for, so the callers
|
|
@@ -360,6 +360,17 @@ def axis_format(vals, digits_d=2, axis_fmt="K", prefix=""):
|
|
|
360
360
|
return base
|
|
361
361
|
|
|
362
362
|
|
|
363
|
+
_R_DASH = {"dashed": "dash", "dotted": "dot",
|
|
364
|
+
"dotdash": "dashdot", "longdash": "longdash",
|
|
365
|
+
"twodash": "longdashdot"}
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def r_dash(lty):
|
|
369
|
+
"""An R line type name as plotly's dash, such as "dotted" to
|
|
370
|
+
"dot"; plotly's own names and None pass through. R analog: lty"""
|
|
371
|
+
return _R_DASH.get(lty, lty) if isinstance(lty, str) else lty
|
|
372
|
+
|
|
373
|
+
|
|
363
374
|
def grid_style():
|
|
364
375
|
"""R analog: .grid_style(). A sub_theme sets the grid through
|
|
365
376
|
grid_x_color / grid_y_color (white on the gray panel of "default"),
|
|
@@ -367,9 +378,9 @@ def grid_style():
|
|
|
367
378
|
clr = (get_option("grid_y_color") or get_option("grid_x_color")
|
|
368
379
|
or get_option("grid_col", "gray85"))
|
|
369
380
|
return {
|
|
370
|
-
"color":
|
|
381
|
+
"color": as_plotly_color(clr),
|
|
371
382
|
"width": get_option("grid_lwd", 0.5),
|
|
372
|
-
"dash": get_option("grid_lty", None),
|
|
383
|
+
"dash": r_dash(get_option("grid_lty", None)),
|
|
373
384
|
}
|
|
374
385
|
|
|
375
386
|
|
|
@@ -416,24 +427,24 @@ def axis_base():
|
|
|
416
427
|
return {
|
|
417
428
|
"zeroline": False,
|
|
418
429
|
"showline": True,
|
|
419
|
-
"linecolor":
|
|
430
|
+
"linecolor": as_plotly_color(ax_line),
|
|
420
431
|
"linewidth": get_option("axis_lwd", 1),
|
|
421
432
|
"ticks": "outside",
|
|
422
433
|
"ticklen": 4,
|
|
423
|
-
"tickcolor":
|
|
434
|
+
"tickcolor": as_plotly_color(ax_line),
|
|
424
435
|
"automargin": True,
|
|
425
436
|
"tickfont": {
|
|
426
|
-
"color":
|
|
437
|
+
"color": as_plotly_color(ax_text),
|
|
427
438
|
"size": 16 * get_option("axis_size", 0.9),
|
|
428
439
|
},
|
|
429
440
|
"title": {
|
|
430
441
|
"font": {
|
|
431
|
-
"color":
|
|
442
|
+
"color": as_plotly_color(get_option("lab_color", "black")),
|
|
432
443
|
"size": 15 * get_option("lab_size", 1),
|
|
433
444
|
},
|
|
434
445
|
"standoff": 10,
|
|
435
446
|
},
|
|
436
|
-
"gridcolor":
|
|
447
|
+
"gridcolor": as_plotly_color(get_option("grid_color", "gray90")),
|
|
437
448
|
"gridwidth": get_option("grid_lwd", 1),
|
|
438
449
|
}
|
|
439
450
|
|
|
@@ -503,7 +514,7 @@ def add_subtitle(fig, sub):
|
|
|
503
514
|
title_size = round(16 * get_option("main_size", 1))
|
|
504
515
|
size = round(title_size * get_option("sub_size", 0.75) / 0.75
|
|
505
516
|
* 0.75)
|
|
506
|
-
color =
|
|
517
|
+
color = as_plotly_color(get_option("sub_color",
|
|
507
518
|
get_option("main_color",
|
|
508
519
|
get_option("lab_color",
|
|
509
520
|
"black"))))
|
|
@@ -558,13 +569,66 @@ def font_scaled(func):
|
|
|
558
569
|
return wrapper
|
|
559
570
|
|
|
560
571
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
572
|
+
# R's pch codes 0-25 as plotly symbols; 21-25 are lessR's named
|
|
573
|
+
# shapes. R analog: .plt.shapes(), and points() for the open codes
|
|
574
|
+
_R_PCH = {
|
|
575
|
+
0: "square-open", 1: "circle-open", 2: "triangle-up-open",
|
|
576
|
+
3: "cross-thin-open", 4: "x-thin-open", 5: "diamond-open",
|
|
577
|
+
6: "triangle-down-open", 7: "square-x-open",
|
|
578
|
+
8: "asterisk-open", 9: "diamond-cross-open",
|
|
579
|
+
10: "circle-cross-open", 11: "hexagram-open",
|
|
580
|
+
12: "square-cross-open", 13: "circle-x-open",
|
|
581
|
+
14: "square-open", 15: "square", 16: "circle",
|
|
582
|
+
17: "triangle-up", 18: "diamond", 19: "circle", 20: "circle",
|
|
583
|
+
21: "circle", 22: "square", 23: "diamond", 24: "triangle-up",
|
|
584
|
+
25: "triangle-down"}
|
|
585
|
+
_LESSR_SHAPES = {"triup": "triangle-up", "tridown": "triangle-down"}
|
|
586
|
+
# pt_shape="vary": one shape per by group, in lessR's order
|
|
587
|
+
_VARY = (["triup", "tridown", "circle", "square", "diamond",
|
|
588
|
+
8, 7, 9, 10, 12, 13, 14, 11]
|
|
589
|
+
+ list("abcdefghijklmnopqrstuvwxyz")
|
|
590
|
+
+ list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|
591
|
+
+ list("+*#%!=-&$?|><@./;:"))
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
def shape_at(shape, i):
|
|
595
|
+
"""Per-group shape as (plotly symbol, None), or (None, char) for
|
|
596
|
+
a single character, drawn as text, as R's pch="$". A scalar
|
|
597
|
+
shape is used for every group (by= differentiates by color
|
|
598
|
+
only, the default); a list gives one shape per group, recycled;
|
|
599
|
+
"vary" a different shape per group. Takes plotly's names,
|
|
600
|
+
lessR's triup/tridown, and R's pch codes 0-25.
|
|
601
|
+
R analog: .plt.shapes()"""
|
|
602
|
+
if isinstance(shape, str) and shape == "vary":
|
|
603
|
+
shape = _VARY
|
|
565
604
|
if isinstance(shape, (list, tuple)):
|
|
566
|
-
|
|
567
|
-
|
|
605
|
+
shape = shape[i % len(shape)]
|
|
606
|
+
if isinstance(shape, (int, np.integer)) and not isinstance(
|
|
607
|
+
shape, bool):
|
|
608
|
+
if int(shape) not in _R_PCH:
|
|
609
|
+
raise ValueError(
|
|
610
|
+
f"pt_shape={shape}: R's numbered shapes are 0 to 25")
|
|
611
|
+
return _R_PCH[int(shape)], None
|
|
612
|
+
s = str(shape)
|
|
613
|
+
if len(s) == 1:
|
|
614
|
+
return None, s
|
|
615
|
+
return _LESSR_SHAPES.get(s, s), None
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
def marks(shape, i, mode, marker):
|
|
619
|
+
"""go.Scatter keywords that draw the points of group i: the
|
|
620
|
+
marker with its symbol, or for a character shape the
|
|
621
|
+
character as text in the marker's border color, sized to the
|
|
622
|
+
marker. mode is "markers" or "lines+markers"."""
|
|
623
|
+
sym, ch = shape_at(shape, i)
|
|
624
|
+
if ch is None:
|
|
625
|
+
return dict(mode=mode, marker=dict(marker, symbol=sym))
|
|
626
|
+
color = (marker.get("line") or {}).get("color", marker.get("color"))
|
|
627
|
+
return dict(mode=mode.replace("markers", "text"), text=ch,
|
|
628
|
+
textposition="middle center",
|
|
629
|
+
textfont=dict(color=color,
|
|
630
|
+
size=max(8, round(float(np.median(
|
|
631
|
+
marker.get("size", 8))) * 1.4))))
|
|
568
632
|
|
|
569
633
|
|
|
570
634
|
def square_layout(main=False, side=460):
|
|
@@ -693,8 +757,8 @@ def finish_facet(fig, levels, ax, x_lab, y_lab, gridT1,
|
|
|
693
757
|
anns = list(fig.layout.annotations or [])
|
|
694
758
|
s_fill = as_plotly_color(get_option("strip_fill",
|
|
695
759
|
"#7F7F7F37"))
|
|
696
|
-
s_line =
|
|
697
|
-
s_text =
|
|
760
|
+
s_line = as_plotly_color(get_option("strip_color", "gray40"))
|
|
761
|
+
s_text = as_plotly_color(get_option("strip_text_color", "gray15"))
|
|
698
762
|
strip_h = max(0.10, min(0.30, 0.05 * n_row))
|
|
699
763
|
# strip font: shrink so the longest label fits its panel
|
|
700
764
|
# (the two-facet Var = "level" cell labels run long)
|
|
@@ -716,7 +780,7 @@ def finish_facet(fig, levels, ax, x_lab, y_lab, gridT1,
|
|
|
716
780
|
if y_cat is None:
|
|
717
781
|
ay = axis_num(show_ylab, ax["axT2"], ax["axL2"])
|
|
718
782
|
ay.update(showgrid=True,
|
|
719
|
-
gridcolor=
|
|
783
|
+
gridcolor=as_plotly_color(style_opts["grid_col"]),
|
|
720
784
|
gridwidth=1, griddash="dot",
|
|
721
785
|
showticklabels=c == 1,
|
|
722
786
|
range=[0, float(ax["axT2"][-1]) * 1.04])
|
|
@@ -749,7 +813,7 @@ def finish_facet(fig, levels, ax, x_lab, y_lab, gridT1,
|
|
|
749
813
|
else:
|
|
750
814
|
fig.update_xaxes(
|
|
751
815
|
row=r, col=c, showline=True, ticks="",
|
|
752
|
-
linecolor=
|
|
816
|
+
linecolor=as_plotly_color(get_option("axis_color",
|
|
753
817
|
"black")))
|
|
754
818
|
for v in (gridT1 or []): # vertical panel grid
|
|
755
819
|
shapes.append({
|
|
@@ -762,7 +826,7 @@ def finish_facet(fig, levels, ax, x_lab, y_lab, gridT1,
|
|
|
762
826
|
"type": "rect",
|
|
763
827
|
"xref": f"x{suf} domain", "yref": f"y{suf} domain",
|
|
764
828
|
"x0": 0, "x1": 1, "y0": 0, "y1": 1,
|
|
765
|
-
"line": {"color":
|
|
829
|
+
"line": {"color": as_plotly_color("gray75"), "width": 1},
|
|
766
830
|
"fillcolor": "rgba(0,0,0,0)"})
|
|
767
831
|
shapes.append({ # strip label band
|
|
768
832
|
"type": "rect",
|
|
@@ -787,8 +851,8 @@ def finish_facet(fig, levels, ax, x_lab, y_lab, gridT1,
|
|
|
787
851
|
|
|
788
852
|
layout_kw = dict(
|
|
789
853
|
shapes=shapes, annotations=anns, template=None,
|
|
790
|
-
plot_bgcolor=
|
|
791
|
-
paper_bgcolor=
|
|
854
|
+
plot_bgcolor=as_plotly_color(style_opts["panel_fill"]),
|
|
855
|
+
paper_bgcolor=as_plotly_color(style_opts["window_fill"]),
|
|
792
856
|
height=height if height is not None else 140 + 160 * n_row,
|
|
793
857
|
)
|
|
794
858
|
if width is not None:
|
|
@@ -883,7 +947,7 @@ def plot_border(top=True, right=True, color=None, width=None):
|
|
|
883
947
|
if isinstance(color, str) and re.fullmatch(r"gray\d+", color):
|
|
884
948
|
color = "gray75" # make a gray a little lighter for plotly
|
|
885
949
|
|
|
886
|
-
line = {"color":
|
|
950
|
+
line = {"color": as_plotly_color(color), "width": width}
|
|
887
951
|
out = []
|
|
888
952
|
if top:
|
|
889
953
|
out.append({"type": "line", "xref": "paper", "yref": "paper",
|
lessPy/plt_add.py
CHANGED
|
@@ -13,14 +13,9 @@
|
|
|
13
13
|
import numpy as np
|
|
14
14
|
import plotly.graph_objects as go
|
|
15
15
|
|
|
16
|
-
from .plotly_utils import as_plotly_color, make_trans, to_hex
|
|
16
|
+
from .plotly_utils import as_plotly_color, make_trans, r_dash, to_hex
|
|
17
17
|
from .utils import get_option
|
|
18
18
|
|
|
19
|
-
_DASH = {"dashed": "dash", "dotted": "dot",
|
|
20
|
-
"dotdash": "dashdot", "longdash": "longdash",
|
|
21
|
-
"twodash": "longdashdot"}
|
|
22
|
-
|
|
23
|
-
|
|
24
19
|
def _as_list(v):
|
|
25
20
|
if v is None:
|
|
26
21
|
return []
|
|
@@ -86,7 +81,7 @@ def plt_add(fig, add, x1=None, x2=None, y1=None, y2=None):
|
|
|
86
81
|
else as_plotly_color(fll))
|
|
87
82
|
line = dict(color=col, width=max(0.5, lwd * 2))
|
|
88
83
|
if lty != "solid":
|
|
89
|
-
line["dash"] =
|
|
84
|
+
line["dash"] = r_dash(lty)
|
|
90
85
|
|
|
91
86
|
for xx1, yy1, xx2, yy2 in locs(obj):
|
|
92
87
|
if obj == "v_line":
|
lessPy/plt_contour.py
CHANGED
|
@@ -14,7 +14,7 @@ import plotly.graph_objects as go
|
|
|
14
14
|
from scipy import stats as sps
|
|
15
15
|
|
|
16
16
|
from .plotly_utils import (
|
|
17
|
-
axis_format, axis_num, get_tick_fmt, plot_border,
|
|
17
|
+
as_plotly_color, axis_format, axis_num, get_tick_fmt, plot_border,
|
|
18
18
|
plotly_style, to_hex)
|
|
19
19
|
from .utils import get_option, pretty
|
|
20
20
|
|
|
@@ -134,7 +134,7 @@ def plt_contour(xv, yv, contour_n, contour_nbins, contour_points,
|
|
|
134
134
|
showscale=bool(legend),
|
|
135
135
|
colorbar=dict(
|
|
136
136
|
tickfont=dict(
|
|
137
|
-
color=
|
|
137
|
+
color=as_plotly_color(get_option("axis_color", "black")),
|
|
138
138
|
size=16 * get_option("axis_size", 0.9)),
|
|
139
139
|
outlinewidth=0),
|
|
140
140
|
hovertemplate=(f"{x_lab}: {xpart}<br>{y_lab}: {ypart}"
|
|
@@ -158,7 +158,7 @@ def plt_contour(xv, yv, contour_n, contour_nbins, contour_points,
|
|
|
158
158
|
for ex_l, ey_l in ellipses or []:
|
|
159
159
|
fig.add_trace(go.Scatter(
|
|
160
160
|
x=ex_l, y=ey_l, mode="lines",
|
|
161
|
-
line=dict(color=
|
|
161
|
+
line=dict(color=as_plotly_color(ellipse_color),
|
|
162
162
|
width=ellipse_lwd),
|
|
163
163
|
hoverinfo="skip", showlegend=False))
|
|
164
164
|
|
|
@@ -167,7 +167,7 @@ def plt_contour(xv, yv, contour_n, contour_nbins, contour_points,
|
|
|
167
167
|
continue
|
|
168
168
|
fig.add_trace(go.Scatter(
|
|
169
169
|
x=fl["x"], y=fl["y"], mode="lines",
|
|
170
|
-
line=dict(color=
|
|
170
|
+
line=dict(color=as_plotly_color(fit_color), width=fit_lwd),
|
|
171
171
|
hoverinfo="skip", showlegend=False))
|
|
172
172
|
|
|
173
173
|
ax_x = axis_num(x_lab, axT1, axL1)
|
|
@@ -178,8 +178,8 @@ def plt_contour(xv, yv, contour_n, contour_nbins, contour_points,
|
|
|
178
178
|
xaxis=ax_x, yaxis=ax_y,
|
|
179
179
|
shapes=plot_border(),
|
|
180
180
|
template=None,
|
|
181
|
-
plot_bgcolor=
|
|
182
|
-
paper_bgcolor=
|
|
181
|
+
plot_bgcolor=as_plotly_color(style_opts["panel_fill"]),
|
|
182
|
+
paper_bgcolor=as_plotly_color(style_opts["window_fill"]),
|
|
183
183
|
)
|
|
184
184
|
|
|
185
185
|
if main:
|
lessPy/plt_contour_facet.py
CHANGED
|
@@ -17,7 +17,7 @@ import numpy as np
|
|
|
17
17
|
import plotly.graph_objects as go
|
|
18
18
|
|
|
19
19
|
from .plotly_utils import (
|
|
20
|
-
axis_format, facet_fig, facet_panels, finish_facet,
|
|
20
|
+
as_plotly_color, axis_format, facet_fig, facet_panels, finish_facet,
|
|
21
21
|
plotly_style, to_hex)
|
|
22
22
|
from .plt_contour import _COLORSCALE, _bw_nrd, _kde2d
|
|
23
23
|
from .plt_smooth import _RAMP as _SMOOTH_RAMP
|
|
@@ -159,7 +159,7 @@ def plt_contour_facet(xv, yv, facet_arr, facet_order, facet_name,
|
|
|
159
159
|
ex, ey = ellipse_fn(xi, yi, float(lv))
|
|
160
160
|
fig.add_trace(go.Scatter(
|
|
161
161
|
x=ex, y=ey, mode="lines",
|
|
162
|
-
line=dict(color=
|
|
162
|
+
line=dict(color=as_plotly_color(ellipse_color),
|
|
163
163
|
width=ellipse_lwd),
|
|
164
164
|
hoverinfo="skip", showlegend=False,
|
|
165
165
|
), row=row, col=col)
|
|
@@ -169,7 +169,7 @@ def plt_contour_facet(xv, yv, facet_arr, facet_order, facet_name,
|
|
|
169
169
|
if okf.sum() >= 2:
|
|
170
170
|
fig.add_trace(go.Scatter(
|
|
171
171
|
x=xs[okf], y=f[okf], mode="lines",
|
|
172
|
-
line=dict(color=
|
|
172
|
+
line=dict(color=as_plotly_color(fit_color),
|
|
173
173
|
width=fit_lwd),
|
|
174
174
|
hoverinfo="skip", showlegend=False,
|
|
175
175
|
), row=row, col=col)
|
lessPy/plt_mat_plotly.py
CHANGED
|
@@ -68,12 +68,12 @@ def scatter_matrix(df, fit="lm", digits_d=2, cor_coef=True,
|
|
|
68
68
|
bg = window_fill if panel_fill == "transparent" else panel_fill
|
|
69
69
|
diag_fill = get_option("se_fill", "#1A1A1A19")
|
|
70
70
|
se_fill = get_option("se_fill", "#1A1A1A19")
|
|
71
|
-
border =
|
|
71
|
+
border = as_plotly_color(style["panel_border"])
|
|
72
72
|
pt_fill = get_option("pt_fill", get_option("pt_color",
|
|
73
73
|
"#324E5C"))
|
|
74
74
|
pt_color = get_option("pt_color", "#324E5C")
|
|
75
|
-
lab_color =
|
|
76
|
-
fit_color =
|
|
75
|
+
lab_color = as_plotly_color(style["lab_color"])
|
|
76
|
+
fit_color = as_plotly_color(get_option("fit_color", "#5C4032"))
|
|
77
77
|
fit_lwd = get_option("fit_lwd", 2)
|
|
78
78
|
|
|
79
79
|
# sizes shrink with the variable count, as R's cex.adj
|
|
@@ -160,8 +160,8 @@ def scatter_matrix(df, fit="lm", digits_d=2, cor_coef=True,
|
|
|
160
160
|
|
|
161
161
|
fig.update_layout(
|
|
162
162
|
template=None, showlegend=False,
|
|
163
|
-
plot_bgcolor=
|
|
164
|
-
paper_bgcolor=
|
|
163
|
+
plot_bgcolor=as_plotly_color(bg),
|
|
164
|
+
paper_bgcolor=as_plotly_color(window_fill))
|
|
165
165
|
if main:
|
|
166
166
|
fig.update_layout(title=dict(
|
|
167
167
|
text=main, x=0.5, xanchor="center",
|
|
@@ -207,16 +207,17 @@ def _scatter_cell(fig, r, c, xv, yv, fit, do_fit, px,
|
|
|
207
207
|
(f - tq * se_f)[::-1]]))
|
|
208
208
|
else:
|
|
209
209
|
poly = _se_band(xs, ys_s, f, 0.95)
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
if poly is not None:
|
|
211
|
+
fig.add_trace(go.Scatter(
|
|
212
|
+
x=poly[0], y=poly[1], mode="none", fill="toself",
|
|
213
|
+
fillcolor=as_plotly_color(se_fill),
|
|
214
|
+
hoverinfo="skip", showlegend=False), row=r, col=c)
|
|
214
215
|
|
|
215
216
|
fig.add_trace(go.Scatter(
|
|
216
217
|
x=xv, y=yv, mode="markers",
|
|
217
218
|
marker=dict(symbol="circle", size=px, sizemode="diameter",
|
|
218
219
|
color=make_trans(pt_fill, 0.9), opacity=1,
|
|
219
|
-
line=dict(color=
|
|
220
|
+
line=dict(color=as_plotly_color(pt_color), width=0.5)),
|
|
220
221
|
hoverinfo="x+y", showlegend=False), row=r, col=c)
|
|
221
222
|
|
|
222
223
|
if do_fit and len(xv) >= 2:
|
lessPy/plt_plotly.py
CHANGED
|
@@ -17,7 +17,7 @@ import plotly.graph_objects as go
|
|
|
17
17
|
|
|
18
18
|
from .plotly_utils import (
|
|
19
19
|
as_plotly_color, axis_base, axis_num, get_tick_fmt, make_trans,
|
|
20
|
-
plot_border, plotly_style,
|
|
20
|
+
plot_border, plotly_style, marks, to_hex, x_grid, y_grid,
|
|
21
21
|
)
|
|
22
22
|
from .utils import get_option
|
|
23
23
|
|
|
@@ -47,6 +47,7 @@ def plt_plotly(groups, by_name=None,
|
|
|
47
47
|
se_polys=None, se_fill=None,
|
|
48
48
|
ellipses=None, ellipse_fill=None,
|
|
49
49
|
ellipse_color=None, ellipse_lwd=1,
|
|
50
|
+
sizes=None, size_name=None,
|
|
50
51
|
style_opts=None):
|
|
51
52
|
"""Scatterplot / time-series renderer for XY().
|
|
52
53
|
|
|
@@ -107,19 +108,34 @@ def plt_plotly(groups, by_name=None,
|
|
|
107
108
|
hover = hover.replace(
|
|
108
109
|
"<extra></extra>", f"<br>{by_name}: {nm}"
|
|
109
110
|
"<extra></extra>")
|
|
111
|
+
# bubbles: a pixel diameter per point, its value in the hover
|
|
112
|
+
custom = None
|
|
113
|
+
if sizes is not None:
|
|
114
|
+
custom = sizes[i][1]
|
|
115
|
+
hover = hover.replace(
|
|
116
|
+
"<extra></extra>",
|
|
117
|
+
f"<br>{size_name}: %{{customdata:.{digits_d}f}}"
|
|
118
|
+
"<extra></extra>")
|
|
110
119
|
marker = dict(
|
|
111
|
-
|
|
120
|
+
size=px if sizes is None else sizes[i][0],
|
|
121
|
+
sizemode="diameter",
|
|
112
122
|
color=make_trans(fills[i], pt_opacity), opacity=1,
|
|
113
|
-
line=dict(color=
|
|
114
|
-
)
|
|
123
|
+
line=dict(color=as_plotly_color(borders[i]), width=1),
|
|
124
|
+
)
|
|
125
|
+
pts_kw = (marks(shape, i, mode_pts, marker)
|
|
126
|
+
if "markers" in mode_pts else dict(mode=mode_pts))
|
|
127
|
+
# a single series' line takes segment_color when it is given;
|
|
128
|
+
# several series keep the color that distinguishes them
|
|
129
|
+
ln_col = (style_opts["segment_color"]
|
|
130
|
+
if not has_groups and get_option("segment_color_set")
|
|
131
|
+
else borders[i])
|
|
115
132
|
fig.add_trace(go.Scatter(
|
|
116
|
-
x=xv, y=yv,
|
|
133
|
+
x=xv, y=yv, **pts_kw,
|
|
117
134
|
name=None if nm is None else str(nm),
|
|
118
135
|
legendgroup=None if nm is None else str(nm),
|
|
119
|
-
|
|
120
|
-
line=(dict(color=to_hex(borders[i]), width=ln_width)
|
|
136
|
+
line=(dict(color=as_plotly_color(ln_col), width=ln_width)
|
|
121
137
|
if connect else None),
|
|
122
|
-
hovertemplate=hover,
|
|
138
|
+
hovertemplate=hover, customdata=custom,
|
|
123
139
|
# connected series show a legend-only line sample below
|
|
124
140
|
showlegend=has_groups and not connect,
|
|
125
141
|
))
|
|
@@ -127,15 +143,15 @@ def plt_plotly(groups, by_name=None,
|
|
|
127
143
|
fig.add_trace(go.Scatter(
|
|
128
144
|
x=xv[:2], y=yv[:2], mode="lines",
|
|
129
145
|
name=str(nm), legendgroup=str(nm),
|
|
130
|
-
line=dict(color=
|
|
146
|
+
line=dict(color=as_plotly_color(borders[i]), width=ln_width),
|
|
131
147
|
hoverinfo="skip", showlegend=True,
|
|
132
148
|
))
|
|
133
149
|
|
|
134
150
|
# ellipses: border per group when grouped, else ellipse_color
|
|
135
151
|
if ellipses:
|
|
136
152
|
for k, (ex, ey) in enumerate(ellipses):
|
|
137
|
-
edge = (
|
|
138
|
-
else
|
|
153
|
+
edge = (as_plotly_color(borders[k % n_grp]) if has_groups
|
|
154
|
+
else as_plotly_color(ellipse_color))
|
|
139
155
|
fig.add_trace(go.Scatter(
|
|
140
156
|
x=ex, y=ey, mode="lines",
|
|
141
157
|
line=dict(color=edge, width=ellipse_lwd),
|
|
@@ -171,8 +187,8 @@ def plt_plotly(groups, by_name=None,
|
|
|
171
187
|
name="Fit" if single else f"Fit: {nm}",
|
|
172
188
|
legendgroup="fit" if single else str(nm),
|
|
173
189
|
line=dict(
|
|
174
|
-
color=(
|
|
175
|
-
else
|
|
190
|
+
color=(as_plotly_color(fit_color) if single
|
|
191
|
+
else as_plotly_color(fills[i])),
|
|
176
192
|
width=fit_lwd),
|
|
177
193
|
hovertemplate=(
|
|
178
194
|
f"{x_lab}: {xpart}<br>{lbl}: {ypart}"
|
|
@@ -185,7 +201,7 @@ def plt_plotly(groups, by_name=None,
|
|
|
185
201
|
ax_x = axis_base()
|
|
186
202
|
ax_x["title"]["text"] = x_lab
|
|
187
203
|
ax_x.update(showgrid=True,
|
|
188
|
-
gridcolor=
|
|
204
|
+
gridcolor=as_plotly_color(style_opts["grid_col"]),
|
|
189
205
|
gridwidth=1)
|
|
190
206
|
shapes = y_grid(gridT2) + plot_border()
|
|
191
207
|
else:
|
|
@@ -193,7 +209,7 @@ def plt_plotly(groups, by_name=None,
|
|
|
193
209
|
shapes = x_grid(gridT1) + y_grid(gridT2) + plot_border()
|
|
194
210
|
ax_y = axis_num(y_lab, ax["axT2"], ax["axL2"])
|
|
195
211
|
|
|
196
|
-
leg_color =
|
|
212
|
+
leg_color = as_plotly_color(style_opts["lab_color"])
|
|
197
213
|
fig.update_layout(
|
|
198
214
|
xaxis=ax_x, yaxis=ax_y,
|
|
199
215
|
shapes=shapes,
|
|
@@ -209,12 +225,12 @@ def plt_plotly(groups, by_name=None,
|
|
|
209
225
|
family="Arial", color=leg_color),
|
|
210
226
|
orientation="v", x=1.05, y=0.5,
|
|
211
227
|
xanchor="left", yanchor="middle",
|
|
212
|
-
bgcolor=
|
|
228
|
+
bgcolor=as_plotly_color(style_opts["window_fill"]),
|
|
213
229
|
bordercolor="#CCCCCC", borderwidth=1,
|
|
214
230
|
itemsizing="constant",
|
|
215
231
|
),
|
|
216
|
-
plot_bgcolor=
|
|
217
|
-
paper_bgcolor=
|
|
232
|
+
plot_bgcolor=as_plotly_color(style_opts["panel_fill"]),
|
|
233
|
+
paper_bgcolor=as_plotly_color(style_opts["window_fill"]),
|
|
218
234
|
)
|
|
219
235
|
|
|
220
236
|
if main:
|
lessPy/plt_smooth.py
CHANGED
|
@@ -129,7 +129,7 @@ def plt_smooth(xv, yv, smooth_points, smooth_size, smooth_power,
|
|
|
129
129
|
for ex, ey in ellipses or []:
|
|
130
130
|
fig.add_trace(go.Scatter(
|
|
131
131
|
x=ex, y=ey, mode="lines",
|
|
132
|
-
line=dict(color=
|
|
132
|
+
line=dict(color=as_plotly_color(ellipse_color),
|
|
133
133
|
width=ellipse_lwd),
|
|
134
134
|
fill="toself",
|
|
135
135
|
fillcolor=as_plotly_color(ellipse_fill),
|
|
@@ -145,7 +145,7 @@ def plt_smooth(xv, yv, smooth_points, smooth_size, smooth_power,
|
|
|
145
145
|
fig.add_trace(go.Scatter(
|
|
146
146
|
x=fl["x"], y=fl["y"], mode="lines", name="Fit",
|
|
147
147
|
legendgroup="fit",
|
|
148
|
-
line=dict(color=
|
|
148
|
+
line=dict(color=as_plotly_color(fit_color), width=fit_lwd),
|
|
149
149
|
hoverinfo="skip", showlegend=True))
|
|
150
150
|
|
|
151
151
|
ax_x = axis_num(x_lab, ax["axT1"], ax["axL1"])
|
|
@@ -156,8 +156,8 @@ def plt_smooth(xv, yv, smooth_points, smooth_size, smooth_power,
|
|
|
156
156
|
xaxis=ax_x, yaxis=ax_y,
|
|
157
157
|
shapes=x_grid(gridT1) + y_grid(gridT2) + plot_border(),
|
|
158
158
|
template=None,
|
|
159
|
-
plot_bgcolor=
|
|
160
|
-
paper_bgcolor=
|
|
159
|
+
plot_bgcolor=as_plotly_color(style_opts["panel_fill"]),
|
|
160
|
+
paper_bgcolor=as_plotly_color(style_opts["window_fill"]),
|
|
161
161
|
)
|
|
162
162
|
|
|
163
163
|
if main:
|
lessPy/prob_norm.py
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
|
|
11
|
-
from .utils import fmt, show_plots
|
|
11
|
+
from .utils import fmt, file_output, show_plots
|
|
12
12
|
|
|
13
13
|
_FILL_NRM = "#E8E8E8" # grey91
|
|
14
14
|
_FILL_INT = "#9FB6CD" # slategray3
|
|
@@ -109,3 +109,7 @@ def _plot(lo, hi, lo_lbl, hi_lbl, mu, sigma, prob, nrm_color,
|
|
|
109
109
|
showarrow=False,
|
|
110
110
|
font=dict(size=11))
|
|
111
111
|
return fig
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# pdf_file= and png_file= write the figures, as lessR's pdf_file=
|
|
115
|
+
prob_norm = file_output(prob_norm)
|
lessPy/prob_tcut.py
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
|
|
12
|
-
from .utils import fmt, show_plots
|
|
12
|
+
from .utils import fmt, file_output, show_plots
|
|
13
13
|
|
|
14
14
|
_BG = "#F9F9FC" # rgb(249,249,252)
|
|
15
15
|
_TAIL = "#8B475D" # palevioletred4
|
|
@@ -129,3 +129,7 @@ def _plot(df, alpha, t_lo, t_hi, n_lo, n_hi, digits_d, y_axis,
|
|
|
129
129
|
bordercolor="black", borderwidth=0.5,
|
|
130
130
|
font=dict(size=10)))
|
|
131
131
|
return fig
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# pdf_file= and png_file= write the figures, as lessR's pdf_file=
|
|
135
|
+
prob_tcut = file_output(prob_tcut)
|
lessPy/prob_znorm.py
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
|
|
14
|
-
from .utils import show_plots
|
|
14
|
+
from .utils import file_output, show_plots
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class ProbZnormResults:
|
|
@@ -110,3 +110,7 @@ def _plot(mu, sigma, border, fill, main, y_axis, z):
|
|
|
110
110
|
showarrow=False,
|
|
111
111
|
font=dict(size=11))
|
|
112
112
|
return fig
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# pdf_file= and png_file= write the figures, as lessR's pdf_file=
|
|
116
|
+
prob_znorm = file_output(prob_znorm)
|