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.
Files changed (48) hide show
  1. lessPy/ANOVA.py +5 -5
  2. lessPy/Chart.py +386 -88
  3. lessPy/Correlation.py +2 -2
  4. lessPy/Logit.py +2 -2
  5. lessPy/Regression.py +6 -4
  6. lessPy/X.py +279 -42
  7. lessPy/XY.py +814 -158
  8. lessPy/__init__.py +12 -2
  9. lessPy/_themes.py +5007 -0
  10. lessPy/bc_items_plotly.py +31 -18
  11. lessPy/bc_plotly.py +23 -7
  12. lessPy/bubble_plotly.py +17 -2
  13. lessPy/corCFA.py +3 -3
  14. lessPy/corProp.py +2 -2
  15. lessPy/corReflect.py +2 -2
  16. lessPy/corReorder.py +2 -2
  17. lessPy/corScree.py +3 -3
  18. lessPy/data/StockPrice.csv +1401 -1386
  19. lessPy/details.py +17 -4
  20. lessPy/dn_plotly.py +65 -45
  21. lessPy/freq_poly_plotly.py +12 -5
  22. lessPy/getColors.py +247 -20
  23. lessPy/hier_plotly.py +36 -9
  24. lessPy/hs_plotly.py +16 -4
  25. lessPy/plotly_utils.py +78 -9
  26. lessPy/plt_mat_plotly.py +74 -2
  27. lessPy/plt_time.py +10 -3
  28. lessPy/prob_norm.py +3 -3
  29. lessPy/prob_tcut.py +3 -3
  30. lessPy/prob_znorm.py +3 -1
  31. lessPy/rcolors.py +461 -0
  32. lessPy/simCImean.py +3 -3
  33. lessPy/simCLT.py +3 -3
  34. lessPy/simFlips.py +3 -3
  35. lessPy/simMeans.py +3 -3
  36. lessPy/stats_out.py +257 -11
  37. lessPy/style.py +160 -0
  38. lessPy/sunflower_plotly.py +140 -0
  39. lessPy/ttest.py +5 -5
  40. lessPy/utils.py +43 -6
  41. lessPy/vbs_plotly.py +16 -5
  42. lessPy/x_console.py +763 -0
  43. {lesspython-0.2.0.dist-info → lesspython-0.3.0.dist-info}/METADATA +6 -2
  44. lesspython-0.3.0.dist-info/RECORD +89 -0
  45. lesspython-0.2.0.dist-info/RECORD +0 -84
  46. {lesspython-0.2.0.dist-info → lesspython-0.3.0.dist-info}/WHEEL +0 -0
  47. {lesspython-0.2.0.dist-info → lesspython-0.3.0.dist-info}/licenses/LICENSE +0 -0
  48. {lesspython-0.2.0.dist-info → lesspython-0.3.0.dist-info}/top_level.txt +0 -0
lessPy/bc_items_plotly.py CHANGED
@@ -20,7 +20,7 @@ from .utils import get_option, pretty
20
20
  from .plotly_utils import (
21
21
  as_plotly_color, auto_text_color, axis_cat, axis_format,
22
22
  axis_num, legend_style, plot_border, plotly_style, to_hex,
23
- x_grid,
23
+ x_grid, y_grid,
24
24
  )
25
25
 
26
26
  # theme -> the two sequential palettes of the divergent fill
@@ -91,24 +91,31 @@ def items_table(cols, names):
91
91
  return frq, wm, numeric
92
92
 
93
93
 
94
- def items_stats_lines(frq, wm, title, numeric=True):
94
+ def items_stats_lines(frq, wm, title, numeric=True, with_sum=False):
95
95
  """'Frequencies of Responses by Variable': one row per item,
96
96
  its counts and its mean. R analog: .prntbl(t(x), 0) with the
97
- Mean column of .bc.main() multi"""
98
- t = frq.T
97
+ Mean column of .bc.main() multi. with_sum adds the Sum column of
98
+ the bubble plot frequency matrix, whose Mean column follows at
99
+ one space and is sized to the mean at three decimals, as
100
+ .dpmat.main() writes it"""
101
+ t = frq.T.copy()
102
+ if with_sum:
103
+ t["Sum"] = t.sum(axis=1)
99
104
  rows = [str(r) for r in t.index]
100
105
  max_c1 = max(len(r) for r in rows) + 2
101
106
  widths = [max(4, max(len(str(c)),
102
107
  max(len(f"{v:.0f}") for v in t[c])) + 1)
103
108
  for c in t.columns]
104
- mx = max(len(f"{round(v, 2):.15g}") for v in wm if np.isfinite(v))
109
+ mx = max(len(f"{round(v, 3 if with_sum else 2):.15g}")
110
+ for v in wm if np.isfinite(v))
111
+ sep = " " if with_sum else " "
105
112
  hdr = " " * max_c1 + "".join(str(c).rjust(w)
106
113
  for c, w in zip(t.columns, widths))
107
- lines = [title, "", hdr + " " + "Mean".rjust(mx + 1)]
114
+ lines = [title, "", hdr + sep + "Mean".rjust(mx + 1)]
108
115
  for r in t.index:
109
116
  ln = (" " + str(r)).rjust(max_c1) + "".join(
110
117
  f"{v:.0f}".rjust(w) for v, w in zip(t.loc[r], widths))
111
- lines.append(ln + " " + f"{wm[r]:.3f}".rjust(mx + 1))
118
+ lines.append(ln + sep + f"{wm[r]:.3f}".rjust(mx + 1))
112
119
  if not numeric:
113
120
  lines += ["", "Computation of the mean based on coding "
114
121
  "response categories from 1 to "
@@ -120,9 +127,11 @@ def bc_items_plotly(frq, order, fill, labels="%", labels_size=None,
120
127
  labels_cut=0.04, stack100=False, x_lab="",
121
128
  y_lab="", legend_title="Responses", main=None,
122
129
  digits_d=0, axis_fmt="K", axis_x_pre="",
123
- rotate_x=0, rotate_y=0, style_opts=None):
124
- """One horizontal bar per item, stacked by response. frq:
125
- responses x items counts; order: the items bottom to top."""
130
+ rotate_x=0, rotate_y=0, horiz=True,
131
+ style_opts=None):
132
+ """One bar per item, stacked by response. frq: responses x items
133
+ counts; order: the items bottom to top, or left to right when
134
+ horiz=False (the vertical chart)."""
126
135
  if style_opts is None:
127
136
  style_opts = plotly_style()
128
137
  cnt = frq[order].to_numpy(dtype=float)
@@ -147,7 +156,9 @@ def bc_items_plotly(frq, order, fill, labels="%", labels_size=None,
147
156
  f"{c:.0f}")
148
157
  for s, c in zip(share[i], cnt[i])]
149
158
  fig.add_trace(go.Bar(
150
- x=mat[i], y=list(order), orientation="h", name=str(r),
159
+ x=mat[i] if horiz else list(order),
160
+ y=list(order) if horiz else mat[i],
161
+ orientation="h" if horiz else "v", name=str(r),
151
162
  marker=dict(color=fills[i % len(fills)],
152
163
  line=dict(width=0)),
153
164
  text=txt, textposition="inside",
@@ -155,7 +166,8 @@ def bc_items_plotly(frq, order, fill, labels="%", labels_size=None,
155
166
  textfont=dict(size=txt_size,
156
167
  color=txt_cols[i % len(txt_cols)]),
157
168
  customdata=np.stack([cnt[i], share[i]], axis=-1),
158
- hovertemplate=(f"%{{y}}<br>{legend_title}: {r}"
169
+ hovertemplate=(("%{y}" if horiz else "%{x}")
170
+ + f"<br>{legend_title}: {r}"
159
171
  "<br>Count: %{customdata[0]:.0f}"
160
172
  "<br>% of item: %{customdata[1]:.1%}"
161
173
  "<extra></extra>"),
@@ -167,11 +179,12 @@ def bc_items_plotly(frq, order, fill, labels="%", labels_size=None,
167
179
  d = 2
168
180
  else:
169
181
  d = digits_d
170
- x_ax = axis_num(x_lab, axT, axis_format(axT, d, axis_fmt,
171
- axis_x_pre))
172
- x_ax.update(range=[0, axT[-1] * (1 if stack100 else 1.02)])
173
- y_ax = axis_cat(y_lab)
174
- y_ax.update(categoryorder="array", categoryarray=list(order))
182
+ val_ax = axis_num(x_lab if horiz else y_lab, axT,
183
+ axis_format(axT, d, axis_fmt, axis_x_pre))
184
+ val_ax.update(range=[0, axT[-1] * (1 if stack100 else 1.02)])
185
+ cat_ax = axis_cat(y_lab if horiz else x_lab)
186
+ cat_ax.update(categoryorder="array", categoryarray=list(order))
187
+ x_ax, y_ax = (val_ax, cat_ax) if horiz else (cat_ax, val_ax)
175
188
  if rotate_x:
176
189
  x_ax["tickangle"] = -rotate_x
177
190
  if rotate_y:
@@ -181,7 +194,7 @@ def bc_items_plotly(frq, order, fill, labels="%", labels_size=None,
181
194
  fig.update_layout(
182
195
  barmode="stack", bargap=0.2,
183
196
  xaxis=x_ax, yaxis=y_ax,
184
- shapes=x_grid(axT) + plot_border(),
197
+ shapes=(x_grid(axT) if horiz else y_grid(axT)) + plot_border(),
185
198
  legend=leg, template=None,
186
199
  plot_bgcolor=to_hex(style_opts["panel_fill"]),
187
200
  paper_bgcolor=to_hex(style_opts["window_fill"]),
lessPy/bc_plotly.py CHANGED
@@ -506,7 +506,7 @@ def bc_facet_plotly(x, x_name=None, facet_name=None,
506
506
  n_col=1, axis_fmt="K", axis_x_pre="",
507
507
  rotate_x=0, rotate_y=0,
508
508
  by_tbls=None, by_name=None, beside=False,
509
- val_name=None, legend_title=None,
509
+ val_name=None, legend_title=None, horiz=True,
510
510
  style_opts=None):
511
511
  """Faceted bar chart: one panel per facet level, on a shared
512
512
  value axis with horizontal bars, as in the lattice Trellis bar
@@ -586,7 +586,8 @@ def bc_facet_plotly(x, x_name=None, facet_name=None,
586
586
  f"<br>{facet_name}: {lv}")
587
587
  for cc, v in zip(cats, row)]
588
588
  fig.add_trace(go.Bar(
589
- x=row, y=cats, orientation="h",
589
+ x=row if horiz else cats, y=cats if horiz else row,
590
+ orientation="h" if horiz else "v",
590
591
  marker=dict(color=fill_vec, opacity=alpha_fill,
591
592
  line=dict(color=border_vec, width=1)),
592
593
  hoverinfo="text", hovertext=hover,
@@ -604,24 +605,39 @@ def bc_facet_plotly(x, x_name=None, facet_name=None,
604
605
  f"<br>{facet_name}: {lv}")
605
606
  for cc, v in zip(cats, vals)]
606
607
  fig.add_trace(go.Bar(
607
- x=vals, y=cats, orientation="h", name=b,
608
+ x=vals if horiz else cats, y=cats if horiz else vals,
609
+ orientation="h" if horiz else "v", name=b,
608
610
  legendgroup=b, showlegend=(i == 0),
609
611
  marker=dict(color=clr, opacity=alpha_fill,
610
612
  line=dict(color=brd, width=1)),
611
613
  hoverinfo="text", hovertext=hover,
612
614
  ), row=r, col=c)
613
615
 
614
- finish_facet(fig, fac_levels, ax, x_lab, y_lab, gridT1=axT1,
615
- style_opts=style_opts, y_cat=cats, n_col=n_col)
616
+ if horiz:
617
+ finish_facet(fig, fac_levels, ax, x_lab, y_lab, gridT1=axT1,
618
+ style_opts=style_opts, y_cat=cats, n_col=n_col)
619
+ else:
620
+ # the vertical chart: categories along x, the shared value
621
+ # scale up the side of every panel
622
+ finish_facet(fig, fac_levels,
623
+ {"axT2": axT1, "axL2": ax["axL1"]},
624
+ y_lab, x_lab, gridT1=None, style_opts=style_opts,
625
+ n_col=n_col, x_cat=cats)
616
626
  if grouped:
617
627
  fig.update_layout(
618
628
  barmode="group" if beside else "stack",
619
629
  showlegend=True,
620
630
  legend=dict(title=dict(text=(legend_title
621
631
  if legend_title is not None
622
- else by_name)),
632
+ else by_name),
633
+ font=dict(color=to_hex(
634
+ style_opts["lab_color"]))),
635
+ font=dict(color=to_hex(style_opts["lab_color"])),
623
636
  traceorder="normal"))
624
- fig.update_xaxes(range=[axT1[0], axT1[-1]]) # includes zero
637
+ if horiz:
638
+ fig.update_xaxes(range=[axT1[0], axT1[-1]]) # includes zero
639
+ else:
640
+ fig.update_yaxes(range=[axT1[0], axT1[-1]])
625
641
  if rotate_x:
626
642
  fig.update_xaxes(tickangle=-rotate_x)
627
643
  if rotate_y:
lessPy/bubble_plotly.py CHANGED
@@ -63,6 +63,7 @@ def bubble_plotly(x=None, x_name=None, y_name=None, by_name=None,
63
63
  labels_decimals=None,
64
64
  label_min_px=26, label_autocontrast=True,
65
65
  facet_tbls=None, facet_name=None, n_col=None,
66
+ shares=False, label_min_value=None,
66
67
  style_opts=None):
67
68
 
68
69
  if labels is None:
@@ -98,8 +99,11 @@ def bubble_plotly(x=None, x_name=None, y_name=None, by_name=None,
98
99
 
99
100
  # "prop" plots proportions, which digits_d (0 for counts)
100
101
  # would flatten to "0"
102
+ # a percentage of a proportion reads in whole numbers, as the
103
+ # percentages of counts do
101
104
  lbl_d = (int(labels_decimals) if labels_decimals is not None
102
105
  else (2 if labels == "prop"
106
+ else 0 if (shares and labels == "%")
103
107
  else max(0, int(digits_d))))
104
108
  trace_mode = "markers" if labels == "off" else "markers+text"
105
109
  # None = the default (R's labels_position %||% "in")
@@ -377,6 +381,11 @@ def bubble_plotly(x=None, x_name=None, y_name=None, by_name=None,
377
381
 
378
382
  total = np.nansum(mat)
379
383
  share_tot = mat / total if total > 0 else np.zeros(mat.shape)
384
+ # values that are already proportions, each by group's distribution
385
+ # over x, are their own percentages: a share of the table total
386
+ # would divide them again by the number of groups
387
+ if shares:
388
+ share_tot = np.nan_to_num(mat)
380
389
  col_tot = np.nansum(mat, axis=0)
381
390
  with np.errstate(invalid="ignore", divide="ignore"):
382
391
  share_x = np.where(col_tot > 0, mat / col_tot, 0.0)
@@ -407,8 +416,14 @@ def bubble_plotly(x=None, x_name=None, y_name=None, by_name=None,
407
416
  else:
408
417
  txt = _label_text(row, share_tot[i], labels, digits_d,
409
418
  lbl_d)
410
- label_show = [t if np.isfinite(dp) and dp >= label_min_px
411
- else "" for t, dp in zip(txt, diam_px)]
419
+ # a bubble labels its value when it is large enough to hold
420
+ # it; label_min_value states that as a value instead, as
421
+ # R's bubble plot frequency matrix does (power/2.5 * max)
422
+ label_show = ([t if np.isfinite(v) and v > label_min_value
423
+ else "" for t, v in zip(txt, row)]
424
+ if label_min_value is not None else
425
+ [t if np.isfinite(dp) and dp >= label_min_px
426
+ else "" for t, dp in zip(txt, diam_px)])
412
427
  customdata = [dict(xcat=c, bycat=g, pct_x=float(px),
413
428
  pct_tot=float(pt))
414
429
  for c, px, pt in zip(cats, share_x[i],
lessPy/corCFA.py CHANGED
@@ -19,7 +19,7 @@ import re
19
19
  import numpy as np
20
20
  import pandas as pd
21
21
 
22
- from .utils import fmt, get_option
22
+ from .utils import fmt, get_option, show_plots
23
23
 
24
24
 
25
25
  def _mimm(R, cuts, NItems, NF, Iter):
@@ -203,10 +203,10 @@ def corCFA(R, model=None, factors=None, min_cor=0.10,
203
203
  plots = {}
204
204
  if heat_map:
205
205
  plots["heatmap"] = _cfa_heatmap(Rout, items, fcols)
206
- return corCFAResults(
206
+ return show_plots(corCFAResults(
207
207
  if_cor=if_cor, ff_cor=ff_cor, communalities=commun,
208
208
  alpha=alpha, omega=omega, pred=pred, resid=res,
209
- plots=plots)
209
+ plots=plots))
210
210
 
211
211
 
212
212
  def _cfa_text(items, fcols, cuts, alpha, omega, iter, if_cor,
lessPy/corProp.py CHANGED
@@ -11,7 +11,7 @@
11
11
  import numpy as np
12
12
  import pandas as pd
13
13
 
14
- from .utils import get_option
14
+ from .utils import get_option, show_plots
15
15
 
16
16
 
17
17
  def corProp(R, main=None, heat_map=True):
@@ -48,7 +48,7 @@ def corProp(R, main=None, heat_map=True):
48
48
  if heat_map:
49
49
  plots["heatmap"] = _heatmap(out, main)
50
50
  out.attrs["plots"] = plots
51
- return out
51
+ return show_plots(out)
52
52
 
53
53
 
54
54
  def _heatmap(df, main):
lessPy/corReflect.py CHANGED
@@ -11,7 +11,7 @@
11
11
  import numpy as np
12
12
  import pandas as pd
13
13
 
14
- from .utils import get_option
14
+ from .utils import get_option, show_plots
15
15
 
16
16
 
17
17
  def corReflect(R, vars, main=None, heat_map=True):
@@ -47,7 +47,7 @@ def corReflect(R, vars, main=None, heat_map=True):
47
47
  if heat_map:
48
48
  plots["heatmap"] = _heatmap(out, main)
49
49
  out.attrs["plots"] = plots
50
- return out
50
+ return show_plots(out)
51
51
 
52
52
 
53
53
  def _heatmap(df, main):
lessPy/corReorder.py CHANGED
@@ -11,7 +11,7 @@
11
11
  import numpy as np
12
12
  import pandas as pd
13
13
 
14
- from .utils import get_option
14
+ from .utils import get_option, show_plots
15
15
 
16
16
  # R hclust method -> scipy linkage method. scipy 'ward' is R's
17
17
  # ward.D2 (squared updates); ward.D has no scipy equivalent, so
@@ -70,7 +70,7 @@ def corReorder(R, order="hclust", hclust_type="complete",
70
70
  pass
71
71
  out.attrs["plots"] = plots
72
72
  out.attrs["order"] = label
73
- return out
73
+ return show_plots(out)
74
74
 
75
75
 
76
76
  def _chain(S, nv, first):
lessPy/corScree.py CHANGED
@@ -11,7 +11,7 @@ import pandas as pd
11
11
  from .plotly_utils import (
12
12
  axis_format, axis_num, plot_border, plotly_style, to_hex,
13
13
  x_grid)
14
- from .utils import fmt, get_option, pretty
14
+ from .utils import fmt, get_option, pretty, show_plots
15
15
 
16
16
 
17
17
  class corScreeResults:
@@ -54,8 +54,8 @@ def corScree(R, main=None):
54
54
  "differences": _scree_plot(
55
55
  ev_diff, "Differences of Successive Eigenvalues",
56
56
  main)}
57
- return corScreeResults(eigenvalues=ev, differences=ev_diff,
58
- plots=plots)
57
+ return show_plots(corScreeResults(eigenvalues=ev, differences=ev_diff,
58
+ plots=plots))
59
59
 
60
60
 
61
61
  def _scree_plot(y, y_lab, main):