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
lessPy/radar_plotly.py ADDED
@@ -0,0 +1,201 @@
1
+ # radar_plotly.py — analog of radar.plotly.R (.radar.plotly)
2
+ #
3
+ # Renders a radar (spider) chart from ALREADY-TABULATED input:
4
+ # 1-D pandas Series: index = x categories (the axes) -> one
5
+ # polygon
6
+ # 2-D pandas DataFrame: rows = `by` levels, columns = x
7
+ # categories -> one polygon per by level, with a legend
8
+ # facets= ordered dict {facet level: Series or DataFrame}, all
9
+ # sharing the same x categories (and by levels) -> a grid
10
+ # of radar panels on a common radial scale
11
+ #
12
+ # The R renderer consumes the .radar_aggregate() bundle, whose
13
+ # facet="(All)"/by="(All)" slices collapse to exactly this
14
+ # Series/crosstab shape, so Chart()'s standard table feeds it
15
+ # directly.
16
+
17
+ import numpy as np
18
+ import pandas as pd
19
+ import plotly.graph_objects as go
20
+
21
+ from .utils import get_option
22
+ from .plotly_utils import (
23
+ BASE_COLORS, facet_layout, make_trans, plotly_style, to_hex,
24
+ )
25
+
26
+
27
+ def _theta_from_levels(k):
28
+ """Angular tick positions, degrees, one per category axis.
29
+ R analog: .plotly_theta_from_levels()"""
30
+ if k < 1:
31
+ raise ValueError("x must have at least 1 category")
32
+ return [i * 360 / k for i in range(k)]
33
+
34
+
35
+ def radar_plotly(x=None, x_name=None, by_name=None, main=None,
36
+ fill=None, opacity=1.0, digits_d=2,
37
+ val_label="Count", facets=None, facet_name=None,
38
+ n_col=None, style_opts=None):
39
+
40
+ # normalize input to an ordered list of (facet level, table);
41
+ # a non-faceted call is the single panel (None, x)
42
+ if facets is not None:
43
+ fac_levels = [str(k) for k in facets.keys()]
44
+ tabs = list(facets.values())
45
+ else:
46
+ fac_levels = [None]
47
+ tabs = [x]
48
+ n_fac = len(tabs)
49
+ first = tabs[0]
50
+
51
+ two_d = isinstance(first, pd.DataFrame)
52
+ for t in tabs:
53
+ if not isinstance(t, pd.DataFrame if two_d
54
+ else pd.Series):
55
+ raise TypeError(
56
+ "each radar table must be a pandas Series (1-D) "
57
+ "or DataFrame (2-D, rows = by levels), the same "
58
+ "shape in every facet panel")
59
+
60
+ if x_name is None:
61
+ x_name = (first.columns.name if two_d
62
+ else first.index.name) or "x"
63
+ if two_d and by_name is None:
64
+ by_name = first.index.name or "by"
65
+ if style_opts is None:
66
+ style_opts = plotly_style()
67
+ if fill is None:
68
+ fill = BASE_COLORS
69
+
70
+ if two_d:
71
+ groups = [str(g) for g in first.index]
72
+ cats = [str(c) for c in first.columns]
73
+ mats = [t.to_numpy(dtype=float) for t in tabs]
74
+ else:
75
+ groups = ["(All)"]
76
+ cats = [str(c) for c in first.index]
77
+ mats = [t.to_numpy(dtype=float).reshape(1, -1)
78
+ for t in tabs]
79
+
80
+ n_by = len(groups)
81
+ rmax = np.nanmax([np.nanmax(m) for m in mats])
82
+ if not np.isfinite(rmax):
83
+ raise ValueError("radar: all values are missing; "
84
+ "nothing to plot")
85
+
86
+ title_size = round(16 * get_option("main_size", 1))
87
+
88
+ theta_deg = _theta_from_levels(len(cats))
89
+ theta_closed = theta_deg + [theta_deg[0]]
90
+ text_labels = cats + [cats[0]]
91
+
92
+ fill_vec = [fill[i % len(fill)]
93
+ if isinstance(fill, (list, tuple)) else fill
94
+ for i in range(n_by)]
95
+ cols_hex = to_hex(fill_vec)
96
+ fills_rgba = make_trans(cols_hex, opacity)
97
+
98
+ val_spec = f":.{max(0, int(digits_d or 0))}f"
99
+ show_leg = n_by > 1
100
+
101
+ # ---- facet domains + panel title annotations -------------------
102
+ # single panel: most of the space, with breathing room (as in R)
103
+ if n_fac == 1:
104
+ domains = [dict(x=(0.08, 0.95), y=(0.05, 0.88))]
105
+ anns = []
106
+ else:
107
+ # compress panels: shift down and shrink so the main title
108
+ # has clear space (R analog: .radar.plotly domain_adjust)
109
+ def dom_adj(d):
110
+ span = (d["y"][1] - d["y"][0]) * 0.72
111
+ y1 = min(0.78, d["y"][1] - 0.10)
112
+ y0 = max(0.0, y1 - span)
113
+ d["y"] = (y0, y1)
114
+ return d
115
+
116
+ def ann_adj(i, a, d):
117
+ a["y"] = min(d["y"][1] + 0.12, 0.97)
118
+ return a
119
+
120
+ domains, anns = facet_layout(
121
+ fac_levels, facet_name or "",
122
+ domain_adjust=dom_adj,
123
+ y_base=-0.018, y_row_shift=-0.003, yanchor="bottom",
124
+ ann_adjust=ann_adj, n_col=n_col)
125
+
126
+ fig = go.Figure()
127
+ for i, (lv, mat) in enumerate(zip(fac_levels, mats)):
128
+ subplot_name = "polar" if i == 0 else f"polar{i + 1}"
129
+ fac_line = (f"{facet_name or 'Facet'}: {lv}<br>"
130
+ if n_fac > 1 else "")
131
+ for j, grp in enumerate(groups):
132
+ r_j = mat[j].tolist()
133
+ r_closed = r_j + [r_j[0]]
134
+ by_line = (f"{by_name}: {grp}<br>" if n_by > 1 else "")
135
+ fig.add_trace(go.Scatterpolar(
136
+ theta=theta_closed,
137
+ thetaunit="degrees",
138
+ r=r_closed,
139
+ mode="lines+markers",
140
+ line=dict(width=1.5, color=cols_hex[j]),
141
+ marker=dict(size=4, color=cols_hex[j]),
142
+ fill="toself",
143
+ fillcolor=fills_rgba[j],
144
+ name=grp,
145
+ text=text_labels,
146
+ hovertemplate=(
147
+ f"{x_name}: %{{text}}<br>"
148
+ f"{by_line}"
149
+ f"{fac_line}"
150
+ f"{val_label}: %{{r{val_spec}}}"
151
+ "<extra></extra>"),
152
+ subplot=subplot_name,
153
+ showlegend=show_leg and i == 0,
154
+ ))
155
+
156
+ # ---- per-panel polar layout blocks ------------------------------
157
+ # R analog: .plotly_apply_polar_layout()
158
+ lab_cex = get_option("lab_size", 1.0)
159
+ ax_cex = get_option("axis_size", 0.9)
160
+ for i, d in enumerate(domains):
161
+ nm = "polar" if i == 0 else f"polar{i + 1}"
162
+ fig.update_layout(**{nm: dict(
163
+ domain=dict(x=list(d["x"]), y=list(d["y"])),
164
+ radialaxis=dict(
165
+ visible=True, showline=True,
166
+ range=[0, rmax * 1.08],
167
+ tickfont=dict(size=round(16.0 * ax_cex)),
168
+ ),
169
+ angularaxis=dict(
170
+ type="linear", direction="clockwise",
171
+ rotation=10, tickmode="array",
172
+ tickvals=theta_deg, ticktext=cats,
173
+ tickfont=dict(size=round(14.5 * lab_cex)),
174
+ ),
175
+ )})
176
+
177
+ # legend OUTSIDE the paper (x > 1) so plotly never auto-shifts
178
+ # the polar domain to avoid legend overlap
179
+ r_margin = 110 if show_leg else 20
180
+ fig.update_layout(
181
+ title=dict(
182
+ text=main, x=0.5, xanchor="center",
183
+ y=0.97, yanchor="top",
184
+ font=dict(size=title_size,
185
+ color=to_hex(get_option("lab_color",
186
+ "black")))),
187
+ margin=dict(t=round(title_size * 2.2), b=10,
188
+ l=20 if n_fac == 1 else r_margin,
189
+ r=r_margin),
190
+ showlegend=show_leg,
191
+ annotations=anns,
192
+ legend=dict(
193
+ x=1.02, xanchor="left", y=1.0, yanchor="top",
194
+ bordercolor=to_hex(style_opts["panel_border"]),
195
+ borderwidth=1,
196
+ font=dict(size=round(18 * ax_cex)),
197
+ ),
198
+ template=None,
199
+ paper_bgcolor=to_hex(style_opts["window_fill"]),
200
+ )
201
+ return fig