lessPython 0.1.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 (82) hide show
  1. lessPy/ANOVA.py +680 -0
  2. lessPy/Chart.py +1055 -0
  3. lessPy/Correlation.py +236 -0
  4. lessPy/Flows.py +116 -0
  5. lessPy/Logit.py +615 -0
  6. lessPy/Prop_test.py +267 -0
  7. lessPy/Regression.py +1491 -0
  8. lessPy/VariableLabels.py +119 -0
  9. lessPy/X.py +426 -0
  10. lessPy/XY.py +2007 -0
  11. lessPy/__init__.py +60 -0
  12. lessPy/anova_rmd.py +227 -0
  13. lessPy/bc_plotly.py +575 -0
  14. lessPy/bubble_plotly.py +470 -0
  15. lessPy/corCFA.py +316 -0
  16. lessPy/corEFA.py +220 -0
  17. lessPy/corPrint.py +45 -0
  18. lessPy/corProp.py +73 -0
  19. lessPy/corRead.py +48 -0
  20. lessPy/corReflect.py +72 -0
  21. lessPy/corReorder.py +161 -0
  22. lessPy/corScree.py +87 -0
  23. lessPy/data/Anova_1way.csv +25 -0
  24. lessPy/data/Anova_2way.csv +49 -0
  25. lessPy/data/Anova_rb.csv +8 -0
  26. lessPy/data/Anova_rbf.csv +49 -0
  27. lessPy/data/Anova_sp.csv +57 -0
  28. lessPy/data/BodyMeas.csv +341 -0
  29. lessPy/data/Cars93.csv +94 -0
  30. lessPy/data/Employee.csv +38 -0
  31. lessPy/data/Employee_lbl.csv +9 -0
  32. lessPy/data/FreqTable99.csv +5 -0
  33. lessPy/data/Jackets.csv +1026 -0
  34. lessPy/data/Learn.csv +35 -0
  35. lessPy/data/Mach4.csv +352 -0
  36. lessPy/data/Mach4_lbl.csv +21 -0
  37. lessPy/data/Reading.csv +101 -0
  38. lessPy/data/StockPrice.csv +1489 -0
  39. lessPy/data/WeightLoss.csv +11 -0
  40. lessPy/datasets.py +46 -0
  41. lessPy/date_infer.py +112 -0
  42. lessPy/details.py +314 -0
  43. lessPy/dn_plotly.py +495 -0
  44. lessPy/dot_plotly.py +385 -0
  45. lessPy/freq_poly_plotly.py +324 -0
  46. lessPy/getColors.py +399 -0
  47. lessPy/hier_plotly.py +352 -0
  48. lessPy/hs_plotly.py +395 -0
  49. lessPy/logit_rmd.py +410 -0
  50. lessPy/order_by.py +94 -0
  51. lessPy/pie_plotly.py +292 -0
  52. lessPy/pivot.py +158 -0
  53. lessPy/plotly_utils.py +787 -0
  54. lessPy/plt_add.py +129 -0
  55. lessPy/plt_contour.py +192 -0
  56. lessPy/plt_contour_facet.py +194 -0
  57. lessPy/plt_forecast.py +677 -0
  58. lessPy/plt_mat_plotly.py +201 -0
  59. lessPy/plt_plotly.py +216 -0
  60. lessPy/plt_smooth.py +170 -0
  61. lessPy/plt_time.py +143 -0
  62. lessPy/prob_norm.py +111 -0
  63. lessPy/prob_tcut.py +131 -0
  64. lessPy/prob_znorm.py +110 -0
  65. lessPy/radar_plotly.py +201 -0
  66. lessPy/reg_rmd.py +754 -0
  67. lessPy/rename.py +33 -0
  68. lessPy/reshape.py +95 -0
  69. lessPy/showColors.py +130 -0
  70. lessPy/simCImean.py +165 -0
  71. lessPy/simCLT.py +265 -0
  72. lessPy/simFlips.py +104 -0
  73. lessPy/simMeans.py +146 -0
  74. lessPy/stats_out.py +189 -0
  75. lessPy/ttest.py +641 -0
  76. lessPy/utils.py +235 -0
  77. lessPy/vbs_plotly.py +545 -0
  78. lesspython-0.1.0.dist-info/METADATA +93 -0
  79. lesspython-0.1.0.dist-info/RECORD +82 -0
  80. lesspython-0.1.0.dist-info/WHEEL +5 -0
  81. lesspython-0.1.0.dist-info/licenses/LICENSE +338 -0
  82. lesspython-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,324 @@
1
+ # freq_poly_plotly.py — analog of freq_poly.plotly.R
2
+ #
3
+ # Frequency polygon: per-group bin counts on SHARED breaks (the
4
+ # bins arrive from X() computed over all the data, so every
5
+ # group's polygon is comparable), vertices at the bin midpoints,
6
+ # closed to zero one bin-width beyond the first and last
7
+ # midpoints. Modeled on dn_plotly, as freq_poly.plotly() is
8
+ # modeled on dn.plotly(); binning is local (pd.cut), no
9
+ # dependency on the histogram code path. fill_area=False (X's
10
+ # area_fill "off"): lines only, with a marker at each vertex but
11
+ # not at the two zero-closing endpoints.
12
+ #
13
+ # facet= draws one panel per level on the shared breaks and a
14
+ # shared count scale, first level in the bottom panel — an
15
+ # EXTENSION beyond R, where X() still stops with "Facets not yet
16
+ # working with density or freq_poly plots". With by=, each panel
17
+ # overlays one polygon per group present in it; proportions are
18
+ # per group within a panel.
19
+
20
+ import math
21
+
22
+ import numpy as np
23
+ import pandas as pd
24
+ import plotly.graph_objects as go
25
+
26
+ from .utils import get_option, pretty
27
+ from .plotly_utils import (
28
+ auto_opacity, axis_format, axis_num, facet_fig,
29
+ facet_panels, finish_facet, get_tick_fmt,
30
+ legend_style, make_trans, plot_border, plotly_style, to_hex,
31
+ x_grid,
32
+ )
33
+
34
+
35
+ def _poly_counts(xg, breaks, proportion):
36
+ """Bin counts of xg on the shared breaks (right-closed, as in
37
+ R's hist); proportions are within-group."""
38
+ cats = pd.cut(pd.Series(xg), breaks, right=True,
39
+ include_lowest=True)
40
+ yv = cats.value_counts(sort=False).to_numpy(dtype=float)
41
+ if proportion and yv.sum() > 0:
42
+ yv = yv / yv.sum()
43
+ return yv
44
+
45
+
46
+ def freq_poly_plotly(x, by=None, x_name=None, by_name=None,
47
+ facet=None, facet_order=None, facet_name=None,
48
+ facet2=None, facet2_order=None,
49
+ facet2_name=None,
50
+ breaks=None, proportion=False,
51
+ fill=None, fill_area=True,
52
+ x_lab=None, y_lab=None, main=None,
53
+ n_col=1, axis_fmt="K", axis_x_pre="",
54
+ axis_y_pre="", digits_d=3,
55
+ style_opts=None):
56
+
57
+ if breaks is None or len(breaks) < 2:
58
+ raise ValueError("breaks (bin edges) required, length >= 2")
59
+ if style_opts is None:
60
+ style_opts = plotly_style()
61
+ if x_name is None:
62
+ x_name = getattr(x, "name", None) or "x"
63
+ if x_lab is None:
64
+ x_lab = x_name
65
+ if y_lab is None:
66
+ y_lab = (f"Proportion of {x_name}" if proportion
67
+ else f"Count of {x_name}")
68
+
69
+ if facet is not None:
70
+ return _fp_facet(x, facet, facet_order, x_name,
71
+ facet_name, breaks, proportion, fill,
72
+ fill_area, x_lab, y_lab, digits_d, main,
73
+ style_opts, by=by, by_name=by_name,
74
+ n_col=n_col, facet2=facet2,
75
+ facet2_order=facet2_order,
76
+ facet2_name=facet2_name,
77
+ axis_fmt=axis_fmt,
78
+ axis_x_pre=axis_x_pre)
79
+
80
+ x = np.asarray(x, dtype=float)
81
+
82
+ # --- groups ---
83
+ if by is None:
84
+ groups = ["Series 1"]
85
+ else:
86
+ by = pd.Series(by).astype(str)
87
+ groups = sorted(by.dropna().unique().tolist())
88
+ G = len(groups)
89
+
90
+ # groups need distinguishable hues: default to the palette
91
+ if fill is None:
92
+ if G > 1:
93
+ from .plotly_utils import BASE_COLORS
94
+ fill = BASE_COLORS
95
+ else:
96
+ fill = get_option("bar_fill_cont", "#96AAC3")
97
+
98
+ # --- bin geometry, counts per group on the shared breaks ---
99
+ breaks = [float(b) for b in breaks]
100
+ left = np.array(breaks[:-1])
101
+ right = np.array(breaks[1:])
102
+ mids = (left + right) / 2
103
+ step = mids[1] - mids[0] if len(mids) > 1 else 1.0
104
+
105
+ polys, ymax = [], 0.0
106
+ for gname in groups:
107
+ xg = x if by is None else x[(by == gname).to_numpy()]
108
+ xg = xg[np.isfinite(xg)]
109
+ yv = _poly_counts(xg, breaks, proportion)
110
+ polys.append(yv)
111
+ ymax = max(ymax, float(yv.max()))
112
+
113
+ # --- ticks ---
114
+ gridT1 = pretty(float(mids.min()), float(mids.max()))
115
+ gridL1 = axis_format(gridT1, digits_d, axis_fmt,
116
+ axis_x_pre)
117
+ gridT2 = pretty(0, ymax, n=6)
118
+ fmt2 = get_tick_fmt(gridT2, digits_d)
119
+ gridL2 = [f"{v:.{digits_d}f}" if fmt2 else f"{v:g}"
120
+ for v in gridT2]
121
+
122
+ # --- colors ---
123
+ alpha_fill = auto_opacity(G, "fill")
124
+ alpha_line = auto_opacity(G, "lines")
125
+ fill_list = [fill[g % len(fill)]
126
+ if isinstance(fill, (list, tuple)) else fill
127
+ for g in range(G)]
128
+ fill_rgba = [make_trans(c, alpha_fill) for c in fill_list]
129
+ line_rgba = [make_trans(c, alpha_line) for c in fill_list]
130
+ pt_rgba = [make_trans(c, 1) for c in fill_list] # vertices
131
+
132
+ fig = go.Figure()
133
+ for g, gname in enumerate(groups):
134
+ xx = np.concatenate([[mids[0] - step], mids,
135
+ [mids[-1] + step]])
136
+ yy = np.concatenate([[0], polys[g], [0]])
137
+ hover = [
138
+ (f"{x_name}: {xv:.6g}"
139
+ f"<br>{y_lab}: {round(float(yv), digits_d):g}")
140
+ for xv, yv in zip(xx, yy)
141
+ ]
142
+ if G > 1 and by_name:
143
+ hover = [f"{by_name}: {gname}<br>{h}" for h in hover]
144
+ # lines only: mark the vertices, not the zero endpoints
145
+ marker = (None if fill_area
146
+ else dict(color=pt_rgba[g],
147
+ size=[0] + [7.5] * len(mids) + [0],
148
+ line=dict(width=0)))
149
+ fig.add_trace(go.Scatter(
150
+ x=xx, y=yy,
151
+ name=gname if G > 1 else None,
152
+ mode="lines" if fill_area else "lines+markers",
153
+ line=dict(color=line_rgba[g], width=2.2),
154
+ marker=marker,
155
+ fill="tozeroy" if fill_area else "none",
156
+ fillcolor=fill_rgba[g] if fill_area else None,
157
+ hoverinfo="text", hovertext=hover,
158
+ showlegend=G > 1,
159
+ ))
160
+
161
+ # --- axes, grid, layout ---
162
+ ax_x = axis_num(x_lab, gridT1, gridL1)
163
+ ax_y = axis_num(y_lab, gridT2, gridL2)
164
+ ax_y.update(showgrid=True,
165
+ gridcolor=to_hex(style_opts["grid_col"]),
166
+ gridwidth=1, griddash="dot")
167
+
168
+ fig.update_layout(
169
+ xaxis=ax_x,
170
+ yaxis=ax_y,
171
+ shapes=x_grid(gridT1) + plot_border(),
172
+ template=None,
173
+ plot_bgcolor=to_hex(style_opts["panel_fill"]),
174
+ paper_bgcolor=to_hex(style_opts["window_fill"]),
175
+ )
176
+
177
+ if G > 1:
178
+ fig.update_layout(legend=legend_style(by_name, style_opts))
179
+
180
+ if main:
181
+ title_size = round(16 * get_option("main_size", 1))
182
+ fig.update_layout(
183
+ title=dict(text=main, x=0.5, xanchor="center",
184
+ y=0.99, yanchor="top",
185
+ font=dict(size=title_size,
186
+ color=to_hex(get_option(
187
+ "lab_color", "black")))),
188
+ margin=dict(t=round(title_size * 2.2)))
189
+ return fig
190
+
191
+
192
+ def _fp_facet(x, facet, facet_order, x_name, facet_name, breaks,
193
+ proportion, fill, fill_area, x_lab, y_lab, digits_d,
194
+ main, style_opts, by=None, by_name=None, n_col=1,
195
+ facet2=None, facet2_order=None, facet2_name=None,
196
+ axis_fmt="K", axis_x_pre=""):
197
+ """One frequency-polygon panel per facet level: shared breaks,
198
+ shared count scale, per-group proportions. With by=, one
199
+ polygon per group within each panel, legend from the first
200
+ panel showing a group; a group absent from a panel draws no
201
+ polygon there. facet2: the two-facet grid, rows = facet2
202
+ levels."""
203
+ x = np.asarray(x, dtype=float)
204
+ ok = np.isfinite(x)
205
+ x, facet = x[ok], np.asarray(facet)[ok]
206
+ if facet2 is not None:
207
+ facet2 = np.asarray(facet2)[ok]
208
+ if facet_order is None:
209
+ facet_order = sorted(set(facet))
210
+ labels, pos, panel_sel, n_row_g, n_col = facet_panels(
211
+ facet, facet_order, facet2, facet2_order,
212
+ facet_name, facet2_name, n_col)
213
+ n_f = len(labels)
214
+
215
+ if by is None:
216
+ groups = [None]
217
+ else:
218
+ by = pd.Series(by).astype(str).to_numpy()[ok]
219
+ groups = sorted(set(by))
220
+ G = len(groups)
221
+
222
+ if fill is None:
223
+ if G > 1:
224
+ from .plotly_utils import BASE_COLORS
225
+ fill = BASE_COLORS
226
+ else:
227
+ fill = get_option("bar_fill_cont", "#96AAC3")
228
+
229
+ breaks = [float(b) for b in breaks]
230
+ left = np.array(breaks[:-1])
231
+ right = np.array(breaks[1:])
232
+ mids = (left + right) / 2
233
+ step = mids[1] - mids[0] if len(mids) > 1 else 1.0
234
+
235
+ # polys[i][g] is None for an absent (facet, group) cell
236
+ polys = [[None] * G for _ in range(n_f)]
237
+ ymax = 0.0
238
+ for i in range(n_f):
239
+ in_lvl = panel_sel[i]
240
+ for g, gname in enumerate(groups):
241
+ sel = (in_lvl if gname is None
242
+ else in_lvl & (by == gname))
243
+ if not sel.any():
244
+ continue
245
+ yv = _poly_counts(x[sel], breaks, proportion)
246
+ polys[i][g] = yv
247
+ ymax = max(ymax, float(yv.max()))
248
+
249
+ axT1 = pretty(float(mids.min()), float(mids.max()))
250
+ axT2 = pretty(0, ymax, n=6)
251
+ fmt2 = get_tick_fmt(axT2, digits_d)
252
+ ax = dict(axT1=axT1,
253
+ axL1=axis_format(axT1, digits_d, axis_fmt,
254
+ axis_x_pre),
255
+ axT2=axT2,
256
+ axL2=[f"{v:.{digits_d}f}" if fmt2 else f"{v:g}"
257
+ for v in axT2])
258
+
259
+ alpha_fill = auto_opacity(G, "fill")
260
+ alpha_line = auto_opacity(G, "lines")
261
+ fill_list = [fill[g % len(fill)]
262
+ if isinstance(fill, (list, tuple)) else fill
263
+ for g in range(G)]
264
+ fill_rgba = [make_trans(c, alpha_fill) for c in fill_list]
265
+ line_rgba = [make_trans(c, alpha_line) for c in fill_list]
266
+ pt_rgba = [make_trans(c, 1) for c in fill_list]
267
+
268
+ fig = facet_fig(n_row_g, n_col)
269
+ seen = set() # legend once per group
270
+ for i, lab in enumerate(labels):
271
+ row, p_col = pos[i]
272
+ panel_txt = (lab if facet2 is not None
273
+ else f"{facet_name}: {lab}")
274
+ for g, gname in enumerate(groups):
275
+ yv = polys[i][g]
276
+ if yv is None:
277
+ continue
278
+ xx = np.concatenate([[mids[0] - step], mids,
279
+ [mids[-1] + step]])
280
+ yy = np.concatenate([[0], yv, [0]])
281
+ hover = [
282
+ (f"{x_name}: {xv:.6g}"
283
+ f"<br>{y_lab}: {round(float(hv), digits_d):g}"
284
+ f"<br>{panel_txt}")
285
+ for xv, hv in zip(xx, yy)
286
+ ]
287
+ if gname is not None and by_name:
288
+ hover = [f"{by_name}: {gname}<br>{h}"
289
+ for h in hover]
290
+ marker = (None if fill_area
291
+ else dict(color=pt_rgba[g],
292
+ size=[0] + [7.5] * len(mids)
293
+ + [0],
294
+ line=dict(width=0)))
295
+ show = G > 1 and gname not in seen
296
+ seen.add(gname)
297
+ fig.add_trace(go.Scatter(
298
+ x=xx, y=yy,
299
+ name=gname if G > 1 else None,
300
+ legendgroup=gname if G > 1 else None,
301
+ mode="lines" if fill_area else "lines+markers",
302
+ line=dict(color=line_rgba[g], width=2.2),
303
+ marker=marker,
304
+ fill="tozeroy" if fill_area else "none",
305
+ fillcolor=fill_rgba[g] if fill_area else None,
306
+ hoverinfo="text", hovertext=hover,
307
+ showlegend=show,
308
+ ), row=row, col=p_col)
309
+
310
+ finish_facet(fig, labels, ax, x_lab, y_lab, n_col=n_col,
311
+ gridT1=axT1, style_opts=style_opts, pos=pos)
312
+ if G > 1:
313
+ fig.update_layout(legend=legend_style(by_name,
314
+ style_opts))
315
+ if main:
316
+ title_size = round(16 * get_option("main_size", 1))
317
+ fig.update_layout(
318
+ title=dict(text=main, x=0.5, xanchor="center",
319
+ y=0.99, yanchor="top",
320
+ font=dict(size=title_size,
321
+ color=to_hex(get_option(
322
+ "lab_color", "black")))),
323
+ margin=dict(t=round(title_size * 2.2)))
324
+ return fig