lessPython 0.2.0__py3-none-any.whl → 0.3.0__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 +5 -5
- lessPy/Chart.py +386 -88
- lessPy/Correlation.py +2 -2
- lessPy/Logit.py +2 -2
- lessPy/Regression.py +6 -4
- lessPy/X.py +279 -42
- lessPy/XY.py +814 -158
- lessPy/__init__.py +12 -2
- lessPy/_themes.py +5007 -0
- lessPy/bc_items_plotly.py +31 -18
- lessPy/bc_plotly.py +23 -7
- lessPy/bubble_plotly.py +17 -2
- lessPy/corCFA.py +3 -3
- lessPy/corProp.py +2 -2
- lessPy/corReflect.py +2 -2
- lessPy/corReorder.py +2 -2
- lessPy/corScree.py +3 -3
- lessPy/data/StockPrice.csv +1401 -1386
- lessPy/details.py +17 -4
- lessPy/dn_plotly.py +65 -45
- lessPy/freq_poly_plotly.py +12 -5
- lessPy/getColors.py +247 -20
- lessPy/hier_plotly.py +36 -9
- lessPy/hs_plotly.py +16 -4
- lessPy/plotly_utils.py +78 -9
- lessPy/plt_mat_plotly.py +74 -2
- lessPy/plt_time.py +10 -3
- lessPy/prob_norm.py +3 -3
- lessPy/prob_tcut.py +3 -3
- lessPy/prob_znorm.py +3 -1
- lessPy/rcolors.py +461 -0
- lessPy/simCImean.py +3 -3
- lessPy/simCLT.py +3 -3
- lessPy/simFlips.py +3 -3
- lessPy/simMeans.py +3 -3
- lessPy/stats_out.py +257 -11
- lessPy/style.py +160 -0
- lessPy/sunflower_plotly.py +140 -0
- lessPy/ttest.py +5 -5
- lessPy/utils.py +43 -6
- lessPy/vbs_plotly.py +16 -5
- lessPy/x_console.py +763 -0
- {lesspython-0.2.0.dist-info → lesspython-0.3.0.dist-info}/METADATA +6 -2
- lesspython-0.3.0.dist-info/RECORD +89 -0
- lesspython-0.2.0.dist-info/RECORD +0 -84
- {lesspython-0.2.0.dist-info → lesspython-0.3.0.dist-info}/WHEEL +0 -0
- {lesspython-0.2.0.dist-info → lesspython-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {lesspython-0.2.0.dist-info → lesspython-0.3.0.dist-info}/top_level.txt +0 -0
lessPy/hier_plotly.py
CHANGED
|
@@ -19,15 +19,18 @@
|
|
|
19
19
|
# ported; fills default to BASE_COLORS keyed by top-level
|
|
20
20
|
# category (lessR's default "colors" theme). A sequential
|
|
21
21
|
# palette NAMED in fill= is ported (read by magnitude off the
|
|
22
|
-
# palette's ramp, R's pal_explicit branch)
|
|
23
|
-
#
|
|
24
|
-
#
|
|
22
|
+
# palette's ramp, R's pal_explicit branch), and with facet=
|
|
23
|
+
# each panel reads its own shades off that ramp
|
|
24
|
+
# (fill_vec_byfac); other fills are the same in every panel.
|
|
25
25
|
|
|
26
26
|
import numpy as np
|
|
27
27
|
import pandas as pd
|
|
28
28
|
import plotly.graph_objects as go
|
|
29
29
|
|
|
30
30
|
from .getColors import _SEQ_NAMES
|
|
31
|
+
|
|
32
|
+
# the palettes read by magnitude, R's seq.pals of .hier_color_resolve()
|
|
33
|
+
_HIER_SEQ = set(_SEQ_NAMES) | {"terrain"}
|
|
31
34
|
from .utils import STAT_FUN, get_option
|
|
32
35
|
from .plotly_utils import (
|
|
33
36
|
BASE_COLORS, facet_layout, plotly_style, to_hex,
|
|
@@ -160,6 +163,28 @@ def _seq_palette_fill(top_levels, pal, x, y, stat):
|
|
|
160
163
|
return {lv: ramp[i] for lv, i in zip(top_levels, idx)}
|
|
161
164
|
|
|
162
165
|
|
|
166
|
+
def hier_color_resolve_byfac(top_levels, fill, x, y, stat, facet,
|
|
167
|
+
facet_order):
|
|
168
|
+
"""Per-panel fills for a faceted chart: with a named sequential
|
|
169
|
+
palette, each panel's categories take their shades from that
|
|
170
|
+
panel's own counts (or stat of y), so each panel spans the
|
|
171
|
+
palette; None for any other fill, which every panel shares.
|
|
172
|
+
R analog: the fill_vec_byfac branch of .hier_color_resolve()"""
|
|
173
|
+
if not (isinstance(fill, str) and fill.lower() in _HIER_SEQ):
|
|
174
|
+
return None
|
|
175
|
+
fac = facet.astype(str)
|
|
176
|
+
out = {}
|
|
177
|
+
for lv in facet_order:
|
|
178
|
+
m = (fac == str(lv)).to_numpy()
|
|
179
|
+
present = set(x[m].astype(str))
|
|
180
|
+
tops = [t for t in top_levels if str(t) in present]
|
|
181
|
+
if tops:
|
|
182
|
+
out[str(lv)] = _seq_palette_fill(
|
|
183
|
+
tops, fill.lower(), x[m].astype(str),
|
|
184
|
+
None if y is None else y[m], stat)
|
|
185
|
+
return out
|
|
186
|
+
|
|
187
|
+
|
|
163
188
|
def hier_color_resolve(top_levels, fill=None, x=None, y=None,
|
|
164
189
|
stat=None):
|
|
165
190
|
"""Hex color per top-level category, inherited down the tree.
|
|
@@ -169,7 +194,7 @@ def hier_color_resolve(top_levels, fill=None, x=None, y=None,
|
|
|
169
194
|
ported."""
|
|
170
195
|
if fill is None:
|
|
171
196
|
fill = BASE_COLORS
|
|
172
|
-
if (isinstance(fill, str) and fill.lower() in
|
|
197
|
+
if (isinstance(fill, str) and fill.lower() in _HIER_SEQ
|
|
173
198
|
and x is not None):
|
|
174
199
|
return _seq_palette_fill(top_levels, fill.lower(), x, y,
|
|
175
200
|
stat)
|
|
@@ -183,7 +208,7 @@ def hier_color_resolve(top_levels, fill=None, x=None, y=None,
|
|
|
183
208
|
for i, lv in enumerate(top_levels)}
|
|
184
209
|
|
|
185
210
|
|
|
186
|
-
def hier_plotly(agg, fill_vec, type="sunburst",
|
|
211
|
+
def hier_plotly(agg, fill_vec, type="sunburst", fill_vec_byfac=None,
|
|
187
212
|
x_name="X", by_name=None, facet_name=None,
|
|
188
213
|
main=None, border=None, digits_d=None,
|
|
189
214
|
labels=None, labels_color="white",
|
|
@@ -254,8 +279,9 @@ def hier_plotly(agg, fill_vec, type="sunburst",
|
|
|
254
279
|
if texttemplate is not None:
|
|
255
280
|
kw["texttemplate"] = texttemplate
|
|
256
281
|
|
|
257
|
-
def make_trace(nd_i, dom_x, dom_y):
|
|
258
|
-
|
|
282
|
+
def make_trace(nd_i, dom_x, dom_y, cols=None):
|
|
283
|
+
cols = fill_vec if not cols else cols
|
|
284
|
+
node_cols = [cols.get(r, list(cols.values())[0])
|
|
259
285
|
for r in nd_i["root"]]
|
|
260
286
|
return trace_cls(
|
|
261
287
|
ids=nd_i["ids"],
|
|
@@ -334,8 +360,9 @@ def hier_plotly(agg, fill_vec, type="sunburst",
|
|
|
334
360
|
for i, lv in enumerate(fac_levels):
|
|
335
361
|
nd_i = nd_byfac[lv]
|
|
336
362
|
if nd_i["ids"]:
|
|
337
|
-
fig.add_trace(make_trace(
|
|
338
|
-
|
|
363
|
+
fig.add_trace(make_trace(
|
|
364
|
+
nd_i, domains[i]["x"], domains[i]["y"],
|
|
365
|
+
cols=(fill_vec_byfac or {}).get(str(lv))))
|
|
339
366
|
|
|
340
367
|
t_margin = round(title_size * 2.8)
|
|
341
368
|
fig.update_layout(
|
lessPy/hs_plotly.py
CHANGED
|
@@ -93,8 +93,8 @@ def hs_plotly(x, by=None, x_name=None, by_name=None,
|
|
|
93
93
|
|
|
94
94
|
# groups need distinguishable hues: default to the palette
|
|
95
95
|
if fill_miss and G > 1:
|
|
96
|
-
from .plotly_utils import
|
|
97
|
-
fill =
|
|
96
|
+
from .plotly_utils import by_colors
|
|
97
|
+
fill = by_colors(G)
|
|
98
98
|
|
|
99
99
|
# --- counts per bin (right-closed bins, as in R's hist) ---
|
|
100
100
|
def bin_counts(xg):
|
|
@@ -107,6 +107,18 @@ def hs_plotly(x, by=None, x_name=None, by_name=None,
|
|
|
107
107
|
xg = xg[np.isfinite(xg)]
|
|
108
108
|
y_mat[:, g] = bin_counts(pd.Series(xg))
|
|
109
109
|
|
|
110
|
+
# the bins as R's X() returns them
|
|
111
|
+
from .stats_out import record_stats
|
|
112
|
+
cnt = y_mat[:, 0] if G == 1 else pd.DataFrame(y_mat, columns=groups)
|
|
113
|
+
tot = cnt.sum() if G == 1 else cnt.sum(axis=0)
|
|
114
|
+
record_stats(bin_width=float(widths[0]), n_bins=n_bins,
|
|
115
|
+
breaks=list(breaks), mids=mids.tolist(),
|
|
116
|
+
counts=(cnt.astype(int).tolist() if G == 1
|
|
117
|
+
else cnt.astype(int)),
|
|
118
|
+
prop=(cnt / tot).tolist() if G == 1 else cnt / tot,
|
|
119
|
+
cprop=(np.cumsum(cnt) / tot).tolist() if G == 1
|
|
120
|
+
else cnt.cumsum() / tot)
|
|
121
|
+
|
|
110
122
|
# density: normalize each group to unit area; proportion: to 1
|
|
111
123
|
if not freq:
|
|
112
124
|
for g in range(G):
|
|
@@ -287,8 +299,8 @@ def _hs_facet(x, facet, facet_order, x_name, facet_name, breaks,
|
|
|
287
299
|
|
|
288
300
|
if fill is None:
|
|
289
301
|
if G > 1:
|
|
290
|
-
from .plotly_utils import
|
|
291
|
-
fill =
|
|
302
|
+
from .plotly_utils import by_colors
|
|
303
|
+
fill = by_colors(G)
|
|
292
304
|
else:
|
|
293
305
|
fill = get_option("bar_fill_cont", "#96AAC3")
|
|
294
306
|
if border is None:
|
lessPy/plotly_utils.py
CHANGED
|
@@ -17,6 +17,43 @@ BASE_COLORS = [
|
|
|
17
17
|
"#00A3BA", "#D26FAF", "#00A76F", "#BD76CB",
|
|
18
18
|
]
|
|
19
19
|
|
|
20
|
+
|
|
21
|
+
def theme_palette(theme=None):
|
|
22
|
+
"""The palette a color theme gives to groups. R analog: .get_fill()
|
|
23
|
+
(not divergent): the qualitative hues for the default theme, else a
|
|
24
|
+
sequential palette in the theme's hue."""
|
|
25
|
+
from .utils import get_option
|
|
26
|
+
if theme is None:
|
|
27
|
+
theme = get_option("theme", "colors")
|
|
28
|
+
if theme == "colors":
|
|
29
|
+
return "hues"
|
|
30
|
+
for pal, members in (
|
|
31
|
+
("grays", ("gray", "white")),
|
|
32
|
+
("blues", ("lightbronze", "dodgerblue", "blue")),
|
|
33
|
+
("browns", ("gold", "brown", "sienna")),
|
|
34
|
+
("rusts", ("orange",)),
|
|
35
|
+
("reds", ("darkred", "red", "rose", "slatered")),
|
|
36
|
+
("greens", ("darkgreen", "green")),
|
|
37
|
+
("violets", ("purple",))):
|
|
38
|
+
if theme in members:
|
|
39
|
+
return pal
|
|
40
|
+
return "blues"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def by_colors(n, theme=None):
|
|
44
|
+
"""One color per group of a by variable under the current theme,
|
|
45
|
+
as X() and XY() draw them. R analog: .color_range(.get_fill(theme),
|
|
46
|
+
n), two grays set apart as gray60 and gray30."""
|
|
47
|
+
pal = theme_palette(theme)
|
|
48
|
+
if pal == "hues":
|
|
49
|
+
return [BASE_COLORS[i % len(BASE_COLORS)] for i in range(n)]
|
|
50
|
+
if pal == "grays" and n == 2:
|
|
51
|
+
return ["#999999", "#4D4D4D"]
|
|
52
|
+
from .getColors import getColors
|
|
53
|
+
cols = getColors(pal, n=max(1, n), quiet=True)
|
|
54
|
+
return [c[:7] if len(c) == 9 else c for c in cols]
|
|
55
|
+
|
|
56
|
+
|
|
20
57
|
# minimal named-color table; R's col2rgb() knows all R names, but
|
|
21
58
|
# plotly accepts CSS names directly so unknowns pass through as-is
|
|
22
59
|
_NAMED = {
|
|
@@ -80,6 +117,10 @@ def to_hex(col):
|
|
|
80
117
|
gray = _gray_level(lower)
|
|
81
118
|
if gray is not None:
|
|
82
119
|
return gray
|
|
120
|
+
# any of R's named colors, as col2rgb() resolves them
|
|
121
|
+
from .rcolors import R_COLORS
|
|
122
|
+
if lower in R_COLORS:
|
|
123
|
+
return R_COLORS[lower]
|
|
83
124
|
return c1 # CSS name unknown to us; plotly handles it
|
|
84
125
|
|
|
85
126
|
|
|
@@ -222,9 +263,13 @@ def legend_style(by_name, style_opts, title=None, position=None,
|
|
|
222
263
|
leg = dict(
|
|
223
264
|
title=dict(text=abbrev(text, abbrev_n) or "",
|
|
224
265
|
font=dict(size=round(
|
|
225
|
-
15 * get_option("lab_size", 1) * mult)
|
|
266
|
+
15 * get_option("lab_size", 1) * mult),
|
|
267
|
+
color=to_hex(style_opts["lab_color"]))),
|
|
268
|
+
# the legend reads in the theme's label color, light on the
|
|
269
|
+
# black sub_theme as the axis labels are
|
|
226
270
|
font=dict(size=round(
|
|
227
|
-
16 * get_option("axis_size", 0.9) * mult)
|
|
271
|
+
16 * get_option("axis_size", 0.9) * mult),
|
|
272
|
+
color=to_hex(style_opts["lab_color"])),
|
|
228
273
|
bgcolor=to_hex(style_opts["window_fill"]),
|
|
229
274
|
bordercolor=to_hex(style_opts["legend_border"]),
|
|
230
275
|
borderwidth=1,
|
|
@@ -316,9 +361,13 @@ def axis_format(vals, digits_d=2, axis_fmt="K", prefix=""):
|
|
|
316
361
|
|
|
317
362
|
|
|
318
363
|
def grid_style():
|
|
319
|
-
"""R analog: .grid_style()
|
|
364
|
+
"""R analog: .grid_style(). A sub_theme sets the grid through
|
|
365
|
+
grid_x_color / grid_y_color (white on the gray panel of "default"),
|
|
366
|
+
which take precedence over the grid color itself"""
|
|
367
|
+
clr = (get_option("grid_y_color") or get_option("grid_x_color")
|
|
368
|
+
or get_option("grid_col", "gray85"))
|
|
320
369
|
return {
|
|
321
|
-
"color": to_hex(
|
|
370
|
+
"color": to_hex(clr),
|
|
322
371
|
"width": get_option("grid_lwd", 0.5),
|
|
323
372
|
"dash": get_option("grid_lty", None),
|
|
324
373
|
}
|
|
@@ -355,17 +404,26 @@ def y_grid(y_vals):
|
|
|
355
404
|
|
|
356
405
|
|
|
357
406
|
def axis_base():
|
|
358
|
-
"""R analog: axis_base()
|
|
407
|
+
"""R analog: axis_base(). A sub_theme sets the axes through their
|
|
408
|
+
own settings, so on sub_theme="black" the axis line and its labels
|
|
409
|
+
are light where axis_color stays dark; the labels are text, so they
|
|
410
|
+
take axis_text_color, as lessR's base R axes do"""
|
|
411
|
+
ax_line = (get_option("axis_x_color")
|
|
412
|
+
or get_option("axis_color", "black"))
|
|
413
|
+
ax_text = (get_option("axis_x_text_color")
|
|
414
|
+
or get_option("axis_text_color")
|
|
415
|
+
or get_option("axis_color", "black"))
|
|
359
416
|
return {
|
|
360
417
|
"zeroline": False,
|
|
361
418
|
"showline": True,
|
|
362
|
-
"linecolor": to_hex(
|
|
419
|
+
"linecolor": to_hex(ax_line),
|
|
363
420
|
"linewidth": get_option("axis_lwd", 1),
|
|
364
421
|
"ticks": "outside",
|
|
365
422
|
"ticklen": 4,
|
|
423
|
+
"tickcolor": to_hex(ax_line),
|
|
366
424
|
"automargin": True,
|
|
367
425
|
"tickfont": {
|
|
368
|
-
"color": to_hex(
|
|
426
|
+
"color": to_hex(ax_text),
|
|
369
427
|
"size": 16 * get_option("axis_size", 0.9),
|
|
370
428
|
},
|
|
371
429
|
"title": {
|
|
@@ -486,6 +544,10 @@ def font_scaled(func):
|
|
|
486
544
|
fig = func(*args, **kwargs)
|
|
487
545
|
if sub and hasattr(fig, "layout"):
|
|
488
546
|
add_subtitle(fig, sub)
|
|
547
|
+
# style(font_family=) sets the family of all plotted text
|
|
548
|
+
family = get_option("font_family")
|
|
549
|
+
if family and hasattr(fig, "layout"):
|
|
550
|
+
fig.update_layout(font=dict(family=family))
|
|
489
551
|
try:
|
|
490
552
|
if font_size and font_size != 1 and hasattr(fig, "layout"):
|
|
491
553
|
apply_font_size(fig, font_size)
|
|
@@ -603,7 +665,7 @@ def facet_panels(facet, facet_order, facet2=None,
|
|
|
603
665
|
|
|
604
666
|
def finish_facet(fig, levels, ax, x_lab, y_lab, gridT1,
|
|
605
667
|
style_opts=None, y_cat=None, n_col=1, pos=None,
|
|
606
|
-
height=None, width=None):
|
|
668
|
+
height=None, width=None, x_cat=None):
|
|
607
669
|
"""Facet styling shared by the faceted renderers: per-panel y
|
|
608
670
|
axes on a common scale (y label on the middle panel of the
|
|
609
671
|
first column), x ticks on the bottom row only, vertical grid
|
|
@@ -670,7 +732,14 @@ def finish_facet(fig, levels, ax, x_lab, y_lab, gridT1,
|
|
|
670
732
|
showticklabels=c == 1)
|
|
671
733
|
fig.update_yaxes(row=r, col=c, **ay)
|
|
672
734
|
lowest = r == n_row or (r + 1, c) not in occupied
|
|
673
|
-
if lowest:
|
|
735
|
+
if lowest and x_cat is not None:
|
|
736
|
+
# categories along x, the vertical bars of a panel
|
|
737
|
+
ax_x = axis_cat(x_lab if c == mid_c else "")
|
|
738
|
+
ax_x.update(categoryorder="array",
|
|
739
|
+
categoryarray=list(x_cat), tickmode="array",
|
|
740
|
+
tickvals=list(x_cat), ticktext=list(x_cat))
|
|
741
|
+
fig.update_xaxes(row=r, col=c, showticklabels=True, **ax_x)
|
|
742
|
+
elif lowest:
|
|
674
743
|
# a shared x axis hides the labels above the bottom row,
|
|
675
744
|
# so a ragged grid's lowest panel turns its own back on
|
|
676
745
|
fig.update_xaxes(
|
lessPy/plt_mat_plotly.py
CHANGED
|
@@ -29,14 +29,28 @@ def _axis_ref(k, kind):
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def scatter_matrix(df, fit="lm", digits_d=2, cor_coef=True,
|
|
32
|
-
main=None, band=True
|
|
32
|
+
main=None, band=True, form="scatter",
|
|
33
|
+
contour_n=None, contour_nbins=50,
|
|
34
|
+
contour_points=False, smooth_bins=128,
|
|
35
|
+
smooth_power=0.25):
|
|
33
36
|
"""Scatterplot matrix of the columns of df, in column order.
|
|
34
37
|
fit: "off" (no line, XY default), "lm" (Regression) or
|
|
35
38
|
"loess". cor_coef=True puts the correlation in the upper
|
|
36
39
|
triangle and the scatter below (~ .plt.mat, Regression);
|
|
37
40
|
cor_coef=False draws the scatter in every off-diagonal cell,
|
|
38
41
|
the symmetric matrix R's Logit uses (logit.4Pred). band adds
|
|
39
|
-
the fit's 95% confidence band.
|
|
42
|
+
the fit's 95% confidence band. form="contour" or "smooth"
|
|
43
|
+
draws each cell as its own kernel density over the cell's
|
|
44
|
+
range, 8 contour bands unless contour_n is given (a cell cannot
|
|
45
|
+
resolve the 20 of a single plot), any fit drawn without its
|
|
46
|
+
band. R analog: .plt.mat() panel.dens. Returns a plotly
|
|
47
|
+
Figure."""
|
|
48
|
+
if form not in ("scatter", "contour", "smooth"):
|
|
49
|
+
raise ValueError(
|
|
50
|
+
'A matrix renders its cells as form="scatter", "contour", '
|
|
51
|
+
f'or "smooth", so form="{form}" is not\navailable for a '
|
|
52
|
+
"matrix.")
|
|
53
|
+
contour_n = 8 if contour_n is None else int(contour_n)
|
|
40
54
|
cols = list(df.columns)
|
|
41
55
|
n = len(cols)
|
|
42
56
|
if n < 2:
|
|
@@ -78,6 +92,17 @@ def scatter_matrix(df, fit="lm", digits_d=2, cor_coef=True,
|
|
|
78
92
|
|
|
79
93
|
# scatter in the lower triangle, and also in the
|
|
80
94
|
# upper triangle when no correlations are requested
|
|
95
|
+
if r != c and (r > c or not cor_coef) \
|
|
96
|
+
and form != "scatter":
|
|
97
|
+
_cell_bg(fig, xr, yr, bg, border)
|
|
98
|
+
_density_cell(fig, r, c, vals[cols[c - 1]],
|
|
99
|
+
vals[cols[r - 1]], rng[cols[c - 1]],
|
|
100
|
+
rng[cols[r - 1]], form, contour_n,
|
|
101
|
+
contour_nbins, contour_points,
|
|
102
|
+
smooth_bins, smooth_power,
|
|
103
|
+
fit if do_fit else "off", fit_color,
|
|
104
|
+
fit_lwd)
|
|
105
|
+
continue
|
|
81
106
|
if r != c and (r > c or not cor_coef):
|
|
82
107
|
_cell_bg(fig, xr, yr, bg, border)
|
|
83
108
|
_scatter_cell(fig, r, c, vals[cols[c - 1]],
|
|
@@ -199,3 +224,50 @@ def _scatter_cell(fig, r, c, xv, yv, fit, do_fit, px,
|
|
|
199
224
|
x=xs, y=f, mode="lines",
|
|
200
225
|
line=dict(color=fit_color, width=fit_lwd),
|
|
201
226
|
hoverinfo="skip", showlegend=False), row=r, col=c)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _density_cell(fig, r, c, xv, yv, xr, yr, form, contour_n,
|
|
230
|
+
contour_nbins, contour_points, smooth_bins,
|
|
231
|
+
smooth_power, fit, fit_color, fit_lwd):
|
|
232
|
+
"""One cell as a kernel density over the cell's range: filled
|
|
233
|
+
contour bands or the smooth shading, then the fit, unbanded.
|
|
234
|
+
R analog: panel.dens of .plt.mat()"""
|
|
235
|
+
from .plt_contour import _COLORSCALE, _bw_nrd, _kde2d
|
|
236
|
+
from .plt_smooth import _RAMP
|
|
237
|
+
from .XY import _loess, _plt_fit
|
|
238
|
+
|
|
239
|
+
ok = np.isfinite(xv) & np.isfinite(yv)
|
|
240
|
+
xo, yo = xv[ok], yv[ok]
|
|
241
|
+
if len(xo) < 3 or _bw_nrd(xo) <= 0 or _bw_nrd(yo) <= 0:
|
|
242
|
+
return
|
|
243
|
+
lims = (float(xr[0]), float(xr[-1]), float(yr[0]), float(yr[-1]))
|
|
244
|
+
n_grid = smooth_bins if form == "smooth" else contour_nbins
|
|
245
|
+
gx, gy, z = _kde2d(xo, yo, n_grid, lims)
|
|
246
|
+
if form == "smooth":
|
|
247
|
+
fig.add_trace(go.Heatmap(
|
|
248
|
+
x=gx, y=gy, z=(z ** smooth_power).T, colorscale=_RAMP,
|
|
249
|
+
zsmooth="best", showscale=False, hoverinfo="skip"),
|
|
250
|
+
row=r, col=c)
|
|
251
|
+
else:
|
|
252
|
+
lv0, lv1 = float(z.min()), float(z.max())
|
|
253
|
+
step = (lv1 - lv0) / contour_n
|
|
254
|
+
fig.add_trace(go.Contour(
|
|
255
|
+
x=gx, y=gy, z=z.T, colorscale=_COLORSCALE,
|
|
256
|
+
contours=dict(start=lv0 + step, end=lv1, size=step),
|
|
257
|
+
line=dict(width=0), showscale=False, hoverinfo="skip"),
|
|
258
|
+
row=r, col=c)
|
|
259
|
+
if contour_points:
|
|
260
|
+
fig.add_trace(go.Scatter(
|
|
261
|
+
x=xo, y=yo, mode="markers",
|
|
262
|
+
marker=dict(size=3, color="rgba(0,0,0,0.27)",
|
|
263
|
+
line=dict(color="white", width=0.2)),
|
|
264
|
+
hoverinfo="skip", showlegend=False), row=r, col=c)
|
|
265
|
+
if fit in ("lm", "loess"):
|
|
266
|
+
if fit == "loess":
|
|
267
|
+
xs, _, f, _ = _loess(xo, yo, 2 / 3)
|
|
268
|
+
else:
|
|
269
|
+
xs, _, f = _plt_fit(xo, yo, "lm", 1)
|
|
270
|
+
fig.add_trace(go.Scatter(
|
|
271
|
+
x=xs, y=f, mode="lines",
|
|
272
|
+
line=dict(color=fit_color, width=fit_lwd),
|
|
273
|
+
hoverinfo="skip", showlegend=False), row=r, col=c)
|
lessPy/plt_time.py
CHANGED
|
@@ -56,11 +56,18 @@ def _agg_one(dser, yser, ts_unit, aggfun):
|
|
|
56
56
|
per = dser
|
|
57
57
|
else:
|
|
58
58
|
per = dser.dt.to_period(_PERIOD_FREQ[ts_unit])
|
|
59
|
-
# trailing partial period: last date short of period
|
|
59
|
+
# trailing partial period: its last date short of the period
|
|
60
|
+
# end AND fewer observations than the median of the earlier
|
|
61
|
+
# periods, so data dated at period starts keeps its complete
|
|
62
|
+
# final period. R analog: ts_truncate() (plt.time.R)
|
|
60
63
|
last_per = per.iloc[int(np.argmax(dser.to_numpy()))]
|
|
61
64
|
if dser.max() < last_per.end_time.normalize():
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
n_per = per.value_counts()
|
|
66
|
+
others = n_per.drop(last_per)
|
|
67
|
+
n_full = float(np.median(others)) if len(others) else 0
|
|
68
|
+
if n_per[last_per] < n_full:
|
|
69
|
+
keep = (per != last_per).to_numpy()
|
|
70
|
+
dser, yser, per = dser[keep], yser[keep], per[keep]
|
|
64
71
|
if len(dser) == 0:
|
|
65
72
|
return (np.array([], dtype="datetime64[ns]"),
|
|
66
73
|
np.array([]))
|
lessPy/prob_norm.py
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
|
|
11
|
-
from .utils import fmt
|
|
11
|
+
from .utils import fmt, show_plots
|
|
12
12
|
|
|
13
13
|
_FILL_NRM = "#E8E8E8" # grey91
|
|
14
14
|
_FILL_INT = "#9FB6CD" # slategray3
|
|
@@ -57,8 +57,8 @@ def prob_norm(lo=None, hi=None, mu=0, sigma=1, nrm_color="black",
|
|
|
57
57
|
|
|
58
58
|
print(f"Probability: {prob}")
|
|
59
59
|
|
|
60
|
-
return ProbNormResults(prob=prob, lo=lo_v, hi=hi_v, mu=mu,
|
|
61
|
-
sigma=sigma, plots={"norm": fig})
|
|
60
|
+
return show_plots(ProbNormResults(prob=prob, lo=lo_v, hi=hi_v, mu=mu,
|
|
61
|
+
sigma=sigma, plots={"norm": fig}))
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
def _plot(lo, hi, lo_lbl, hi_lbl, mu, sigma, prob, nrm_color,
|
lessPy/prob_tcut.py
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
|
|
12
|
-
from .utils import fmt
|
|
12
|
+
from .utils import fmt, show_plots
|
|
13
13
|
|
|
14
14
|
_BG = "#F9F9FC" # rgb(249,249,252)
|
|
15
15
|
_TAIL = "#8B475D" # palevioletred4
|
|
@@ -51,8 +51,8 @@ def prob_tcut(df, alpha=0.05, digits_d=3, y_axis=False,
|
|
|
51
51
|
fill, color_tail, nrm_color, color_t)
|
|
52
52
|
|
|
53
53
|
print(f"Probability: {cutoff}")
|
|
54
|
-
return ProbTcutResults(cutoff=cutoff, df=df, alpha=alpha,
|
|
55
|
-
plots={"tcut": fig})
|
|
54
|
+
return show_plots(ProbTcutResults(cutoff=cutoff, df=df, alpha=alpha,
|
|
55
|
+
plots={"tcut": fig}))
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
def _cut_line(fig, x, top, color):
|
lessPy/prob_znorm.py
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
|
|
14
|
+
from .utils import show_plots
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
class ProbZnormResults:
|
|
16
18
|
"""Result of prob_znorm(): mu/sigma and the plotly figure in
|
|
@@ -46,7 +48,7 @@ def prob_znorm(mu=0, sigma=1, color_border="gray10", r=0.10,
|
|
|
46
48
|
f"{round(b * 255)},{a})"
|
|
47
49
|
|
|
48
50
|
fig = _plot(mu, sigma, border, fill, main, y_axis, z)
|
|
49
|
-
return ProbZnormResults(mu=mu, sigma=sigma, plots={"znorm": fig})
|
|
51
|
+
return show_plots(ProbZnormResults(mu=mu, sigma=sigma, plots={"znorm": fig}))
|
|
50
52
|
|
|
51
53
|
|
|
52
54
|
def _gray_to_hex(color):
|