davis-stats 2.2.1__tar.gz → 2.2.2__tar.gz

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 (43) hide show
  1. {davis_stats-2.2.1 → davis_stats-2.2.2}/PKG-INFO +1 -1
  2. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/visualization/boxplot.py +2 -1
  3. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/visualization/histogram.py +2 -1
  4. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/visualization/residuals.py +4 -2
  5. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/visualization/scatter.py +48 -16
  6. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats.egg-info/PKG-INFO +1 -1
  7. {davis_stats-2.2.1 → davis_stats-2.2.2}/setup.py +1 -1
  8. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/__init__.py +0 -0
  9. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/__init__.py +0 -0
  10. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/ceo_comp.xlsx +0 -0
  11. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/fired_ceo.xlsx +0 -0
  12. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/just_games.xlsx +0 -0
  13. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/m.xlsx +0 -0
  14. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/nba.xlsx +0 -0
  15. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/netflix_content.xlsx +0 -0
  16. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/new_ceo.xlsx +0 -0
  17. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/olympic_medals.xlsx +0 -0
  18. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/restate.xlsx +0 -0
  19. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/restaurants.xlsx +0 -0
  20. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/sp1500_2025.xlsx +0 -0
  21. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/sp1500_panel.xlsx +0 -0
  22. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/student_athletes.xlsx +0 -0
  23. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/sweet_things.xlsx +0 -0
  24. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/sweet_things_simple.xlsx +0 -0
  25. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/datasets/world_cup_goals.xlsx +0 -0
  26. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/practice/__init__.py +0 -0
  27. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/practice/stats_practice.py +0 -0
  28. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/reg_modeling/__init__.py +0 -0
  29. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/reg_modeling/marginal_effects.py +0 -0
  30. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/reg_modeling/reg.py +0 -0
  31. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/reg_tests/__init__.py +0 -0
  32. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/reg_tests/bp_test.py +0 -0
  33. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/reg_tests/dw_test.py +0 -0
  34. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/reg_tests/hausman_test.py +0 -0
  35. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/reg_tests/sw_test.py +0 -0
  36. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/reg_tests/vif_test.py +0 -0
  37. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/visualization/__init__.py +0 -0
  38. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats/visualization/trim.py +0 -0
  39. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats.egg-info/SOURCES.txt +0 -0
  40. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats.egg-info/dependency_links.txt +0 -0
  41. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats.egg-info/requires.txt +0 -0
  42. {davis_stats-2.2.1 → davis_stats-2.2.2}/davis_stats.egg-info/top_level.txt +0 -0
  43. {davis_stats-2.2.1 → davis_stats-2.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: davis_stats
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: davis_stats is a teaching-focused repository
5
5
  Author: Justin G. Davis
6
6
  Author-email:
@@ -10,6 +10,7 @@ def boxplot(
10
10
  title=None,
11
11
  trim_outliers=100,
12
12
  details=True,
13
+ decimals=1,
13
14
  dpi=160,
14
15
  save_dpi=300,
15
16
  figsize=(7, 4.5),
@@ -79,7 +80,7 @@ def boxplot(
79
80
  ax.ticklabel_format(style="plain", axis=value_axis)
80
81
  ax.tick_params(axis=value_axis, labelsize=11, length=5, width=1.1)
81
82
  getattr(ax, f"{value_axis}axis").set_major_formatter(
82
- FuncFormatter(lambda v, _: f"{v:,.2f}")
83
+ FuncFormatter(lambda v, _: f"{v:,.{decimals}f}")
83
84
  )
84
85
 
85
86
  if details:
@@ -12,6 +12,7 @@ def histogram(
12
12
  bins=30,
13
13
  trim_outliers=100,
14
14
  details=True,
15
+ decimals=1,
15
16
  dpi=200,
16
17
  save_dpi=300,
17
18
  figsize=(7, 4.5),
@@ -55,7 +56,7 @@ def histogram(
55
56
  ax.set_xlabel("")
56
57
  ax.tick_params(labelsize=10, length=5, width=1.1)
57
58
  ax.ticklabel_format(style="plain", axis="x")
58
- ax.xaxis.set_major_formatter(FuncFormatter(lambda v, _: f"{v:,.2f}"))
59
+ ax.xaxis.set_major_formatter(FuncFormatter(lambda v, _: f"{v:,.{decimals}f}"))
59
60
  ax.yaxis.set_major_formatter(FuncFormatter(lambda v, _: f"{v:,.0f}"))
60
61
  ax.yaxis.set_major_locator(MaxNLocator(nbins=6))
61
62
 
@@ -10,6 +10,7 @@ def residuals(
10
10
  x,
11
11
  dummies=None,
12
12
  logistic=False,
13
+ decimals=1,
13
14
  dpi=200,
14
15
  save_dpi=300,
15
16
  figsize=(7, 4.5),
@@ -45,6 +46,7 @@ def residuals(
45
46
  0, color="#c0392b", linestyle="--", linewidth=1.8, zorder=4,
46
47
  )
47
48
 
49
+ fmt = FuncFormatter(lambda v, _: f"{v:,.{decimals}f}")
48
50
  ax.grid(True, linestyle="--", linewidth=0.8, alpha=0.45)
49
51
  ax.set_axisbelow(True)
50
52
  ax.spines["top"].set_visible(False)
@@ -53,8 +55,8 @@ def residuals(
53
55
  ax.spines["bottom"].set_linewidth(1.2)
54
56
  ax.tick_params(labelsize=10, length=5, width=1.1)
55
57
  ax.ticklabel_format(style="plain")
56
- ax.xaxis.set_major_formatter(FuncFormatter(lambda v, _: f"{v:,.2f}"))
57
- ax.yaxis.set_major_formatter(FuncFormatter(lambda v, _: f"{v:,.2f}"))
58
+ ax.xaxis.set_major_formatter(fmt)
59
+ ax.yaxis.set_major_formatter(fmt)
58
60
  ax.xaxis.set_major_locator(MaxNLocator(nbins=6))
59
61
  ax.yaxis.set_major_locator(MaxNLocator(nbins=6))
60
62
 
@@ -10,6 +10,7 @@ def scatter(
10
10
  y,
11
11
  x,
12
12
  fit_line=False,
13
+ decimals=1,
13
14
  dpi=200,
14
15
  save_dpi=300,
15
16
  figsize=(7, 4.5),
@@ -18,19 +19,24 @@ def scatter(
18
19
  ):
19
20
  """
20
21
  Create a 2D or 3D scatter plot with optional fit line.
22
+
23
+ fit_line:
24
+ False — points only
25
+ "linear" — OLS of y on x (or a plane in 3D)
26
+ "quadratic" — OLS of y on x and x² (2D only)
21
27
  """
22
28
  if isinstance(x, str):
23
29
  x = [x]
24
30
 
25
31
  if len(x) == 1:
26
32
  ax = _scatter_2d(
27
- df, y, x[0], fit_line=fit_line, dpi=dpi, figsize=figsize,
28
- facecolor=facecolor,
33
+ df, y, x[0], fit_line=fit_line, decimals=decimals,
34
+ dpi=dpi, figsize=figsize, facecolor=facecolor,
29
35
  )
30
36
  else:
31
37
  ax = _scatter_3d(
32
- df, y, x[0], x[1], fit_line=fit_line, dpi=dpi, figsize=figsize,
33
- facecolor=facecolor,
38
+ df, y, x[0], x[1], fit_line=fit_line, decimals=decimals,
39
+ dpi=dpi, figsize=figsize, facecolor=facecolor,
34
40
  )
35
41
 
36
42
  fig = ax.figure
@@ -44,7 +50,18 @@ def scatter(
44
50
  return ax
45
51
 
46
52
 
47
- def _style_2d(ax):
53
+ def _fit_kind(fit_line):
54
+ if not fit_line:
55
+ return None
56
+ if fit_line == "linear":
57
+ return "linear"
58
+ if fit_line == "quadratic":
59
+ return "quadratic"
60
+ raise ValueError("fit_line must be False, 'linear', or 'quadratic'")
61
+
62
+
63
+ def _style_2d(ax, decimals):
64
+ fmt = FuncFormatter(lambda v, _: f"{v:,.{decimals}f}")
48
65
  ax.grid(True, linestyle="--", linewidth=0.8, alpha=0.45)
49
66
  ax.set_axisbelow(True)
50
67
  ax.spines["top"].set_visible(False)
@@ -53,13 +70,13 @@ def _style_2d(ax):
53
70
  ax.spines["bottom"].set_linewidth(1.2)
54
71
  ax.tick_params(labelsize=10, length=5, width=1.1)
55
72
  ax.ticklabel_format(style="plain")
56
- ax.xaxis.set_major_formatter(FuncFormatter(lambda v, _: f"{v:,.2f}"))
57
- ax.yaxis.set_major_formatter(FuncFormatter(lambda v, _: f"{v:,.2f}"))
73
+ ax.xaxis.set_major_formatter(fmt)
74
+ ax.yaxis.set_major_formatter(fmt)
58
75
  ax.xaxis.set_major_locator(MaxNLocator(nbins=6))
59
76
  ax.yaxis.set_major_locator(MaxNLocator(nbins=6))
60
77
 
61
78
 
62
- def _scatter_2d(df, y, x_var, fit_line, dpi, figsize, facecolor):
79
+ def _scatter_2d(df, y, x_var, fit_line, decimals, dpi, figsize, facecolor):
63
80
  plot_df = df[[x_var, y]].dropna()
64
81
  if plot_df.empty:
65
82
  raise ValueError("No data to plot after dropping NaNs.")
@@ -83,25 +100,35 @@ def _scatter_2d(df, y, x_var, fit_line, dpi, figsize, facecolor):
83
100
  zorder=3,
84
101
  )
85
102
 
86
- if fit_line and len(xv) >= 2:
87
- slope, intercept = np.polyfit(xv, yv, 1)
88
- x_line = np.array([xv.min(), xv.max()])
103
+ kind = _fit_kind(fit_line)
104
+ if kind is not None and len(xv) >= (3 if kind == "quadratic" else 2):
105
+ degree = 2 if kind == "quadratic" else 1
106
+ coefs = np.polyfit(xv, yv, degree)
107
+ x_line = np.linspace(xv.min(), xv.max(), 200)
108
+ y_line = np.polyval(coefs, x_line)
89
109
  ax.plot(
90
110
  x_line,
91
- slope * x_line + intercept,
111
+ y_line,
92
112
  color="#c0392b",
93
113
  linewidth=1.8,
94
114
  zorder=4,
95
115
  )
96
116
 
97
- _style_2d(ax)
98
- ax.set_title(f"{y} and {x_var}\nCorrelation: {corr:.3f}", fontsize=13, pad=10)
117
+ _style_2d(ax, decimals)
118
+ ax.set_title(
119
+ f"{y} and {x_var}\nCorrelation: {corr:.2f}",
120
+ fontsize=13, pad=10,
121
+ )
99
122
  ax.set_xlabel(x_var, fontsize=11)
100
123
  ax.set_ylabel(y, fontsize=11)
101
124
  return ax
102
125
 
103
126
 
104
- def _scatter_3d(df, y, x_var, z_var, fit_line, dpi, figsize, facecolor):
127
+ def _scatter_3d(df, y, x_var, z_var, fit_line, decimals, dpi, figsize, facecolor):
128
+ kind = _fit_kind(fit_line)
129
+ if kind == "quadratic":
130
+ raise ValueError("fit_line='quadratic' is only available for 2D scatter plots.")
131
+
105
132
  plot_df = df[[x_var, z_var, y]].dropna()
106
133
  if plot_df.empty:
107
134
  raise ValueError("No data to plot after dropping NaNs.")
@@ -122,7 +149,7 @@ def _scatter_3d(df, y, x_var, z_var, fit_line, dpi, figsize, facecolor):
122
149
  depthshade=True,
123
150
  )
124
151
 
125
- if fit_line:
152
+ if kind == "linear":
126
153
  X_data = np.column_stack(
127
154
  [plot_df[x_var], plot_df[z_var], np.ones(len(plot_df))]
128
155
  )
@@ -144,6 +171,11 @@ def _scatter_3d(df, y, x_var, z_var, fit_line, dpi, figsize, facecolor):
144
171
  shade=False,
145
172
  )
146
173
 
174
+ fmt = FuncFormatter(lambda v, _: f"{v:,.{decimals}f}")
175
+ ax.xaxis.set_major_formatter(fmt)
176
+ ax.yaxis.set_major_formatter(fmt)
177
+ ax.zaxis.set_major_formatter(fmt)
178
+
147
179
  ax.set_title(f"{y}, {x_var}, and {z_var}", fontsize=13, pad=10)
148
180
  ax.set_xlabel(x_var, fontsize=11, labelpad=8)
149
181
  ax.set_ylabel(z_var, fontsize=11, labelpad=8)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: davis_stats
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: davis_stats is a teaching-focused repository
5
5
  Author: Justin G. Davis
6
6
  Author-email:
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='davis_stats',
5
- version='2.2.1',
5
+ version='2.2.2',
6
6
  packages=find_packages(),
7
7
  package_data={
8
8
  'davis_stats': ['datasets/*.xlsx']},
File without changes