davis-stats 2.2__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 (45) hide show
  1. {davis_stats-2.2 → davis_stats-2.2.2}/PKG-INFO +2 -3
  2. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/__init__.py +2 -1
  3. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/__init__.py +20 -0
  4. davis_stats-2.2.2/davis_stats/datasets/sweet_things.xlsx +0 -0
  5. davis_stats-2.2.2/davis_stats/datasets/sweet_things_simple.xlsx +0 -0
  6. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/visualization/boxplot.py +2 -1
  7. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/visualization/histogram.py +2 -1
  8. davis_stats-2.2.2/davis_stats/visualization/residuals.py +74 -0
  9. davis_stats-2.2.2/davis_stats/visualization/scatter.py +194 -0
  10. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats.egg-info/PKG-INFO +2 -3
  11. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats.egg-info/SOURCES.txt +2 -0
  12. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats.egg-info/requires.txt +0 -1
  13. {davis_stats-2.2 → davis_stats-2.2.2}/setup.py +2 -3
  14. davis_stats-2.2/davis_stats/visualization/residuals.py +0 -25
  15. davis_stats-2.2/davis_stats/visualization/scatter.py +0 -128
  16. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/ceo_comp.xlsx +0 -0
  17. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/fired_ceo.xlsx +0 -0
  18. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/just_games.xlsx +0 -0
  19. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/m.xlsx +0 -0
  20. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/nba.xlsx +0 -0
  21. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/netflix_content.xlsx +0 -0
  22. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/new_ceo.xlsx +0 -0
  23. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/olympic_medals.xlsx +0 -0
  24. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/restate.xlsx +0 -0
  25. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/restaurants.xlsx +0 -0
  26. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/sp1500_2025.xlsx +0 -0
  27. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/sp1500_panel.xlsx +0 -0
  28. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/student_athletes.xlsx +0 -0
  29. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/datasets/world_cup_goals.xlsx +0 -0
  30. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/practice/__init__.py +0 -0
  31. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/practice/stats_practice.py +0 -0
  32. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/reg_modeling/__init__.py +0 -0
  33. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/reg_modeling/marginal_effects.py +0 -0
  34. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/reg_modeling/reg.py +0 -0
  35. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/reg_tests/__init__.py +0 -0
  36. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/reg_tests/bp_test.py +0 -0
  37. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/reg_tests/dw_test.py +0 -0
  38. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/reg_tests/hausman_test.py +0 -0
  39. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/reg_tests/sw_test.py +0 -0
  40. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/reg_tests/vif_test.py +0 -0
  41. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/visualization/__init__.py +0 -0
  42. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats/visualization/trim.py +0 -0
  43. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats.egg-info/dependency_links.txt +0 -0
  44. {davis_stats-2.2 → davis_stats-2.2.2}/davis_stats.egg-info/top_level.txt +0 -0
  45. {davis_stats-2.2 → davis_stats-2.2.2}/setup.cfg +0 -0
@@ -1,17 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: davis_stats
3
- Version: 2.2
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:
7
7
  Keywords: statistics,data science,business analytics
8
- Requires-Python: >=3.7
8
+ Requires-Python: >=3.11
9
9
  Requires-Dist: pandas>=3.0.6
10
10
  Requires-Dist: openpyxl>=3.0.0
11
11
  Requires-Dist: numpy>=1.20.0
12
12
  Requires-Dist: matplotlib>=3.11.2
13
13
  Requires-Dist: scipy>=1.6.0
14
- Requires-Dist: seaborn>=0.12.0
15
14
  Requires-Dist: statsmodels>=0.14.0
16
15
  Requires-Dist: ipympl>=0.8.0
17
16
  Requires-Dist: linearmodels>=7.0
@@ -19,4 +19,5 @@ from .datasets import (
19
19
  ceo_comp, netflix_content, olympic_medals,
20
20
  restaurants, world_cup_goals, just_games,
21
21
  nba, fired_ceo, restate, new_ceo, sp1500_2025,
22
- sp1500_panel, student_athletes, m)
22
+ sp1500_panel, student_athletes, m, sweet_things,
23
+ sweet_things_simple)
@@ -19,6 +19,8 @@ class DataFrames:
19
19
  _sp1500_panel = None
20
20
  _student_athletes = None
21
21
  _m = None
22
+ _sweet_things = None
23
+ _sweet_things_simple = None
22
24
 
23
25
  @property
24
26
  def ceo_comp(self):
@@ -104,6 +106,18 @@ class DataFrames:
104
106
  self._m = pd.read_excel(DATA_DIR / 'm.xlsx')
105
107
  return self._m
106
108
 
109
+ @property
110
+ def sweet_things(self):
111
+ if self._sweet_things is None:
112
+ self._sweet_things = pd.read_excel(DATA_DIR / 'sweet_things.xlsx')
113
+ return self._sweet_things
114
+
115
+ @property
116
+ def sweet_things_simple(self):
117
+ if self._sweet_things_simple is None:
118
+ self._sweet_things_simple = pd.read_excel(DATA_DIR / 'sweet_things_simple.xlsx')
119
+ return self._sweet_things_simple
120
+
107
121
  _datasets = DataFrames()
108
122
 
109
123
 
@@ -148,3 +162,9 @@ def student_athletes():
148
162
 
149
163
  def m():
150
164
  return _datasets.m
165
+
166
+ def sweet_things():
167
+ return _datasets.sweet_things
168
+
169
+ def sweet_things_simple():
170
+ return _datasets.sweet_things_simple
@@ -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
 
@@ -0,0 +1,74 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ from matplotlib.ticker import FuncFormatter, MaxNLocator
4
+ from ..reg_modeling.reg import reg
5
+
6
+
7
+ def residuals(
8
+ df,
9
+ y,
10
+ x,
11
+ dummies=None,
12
+ logistic=False,
13
+ decimals=1,
14
+ dpi=200,
15
+ save_dpi=300,
16
+ figsize=(7, 4.5),
17
+ save_path=None,
18
+ facecolor="white",
19
+ ):
20
+ """
21
+ Plot residuals vs fitted values to check linearity.
22
+ """
23
+ results = reg(df, y, x, dummies=dummies, logistic=logistic, silent=True)
24
+ if results is None:
25
+ print("Error: Could not fit regression model")
26
+ return
27
+
28
+ fitted = np.asarray(results.fittedvalues, dtype=float)
29
+ resid = np.asarray(results.resid, dtype=float)
30
+
31
+ fig, ax = plt.subplots(figsize=figsize, dpi=dpi, facecolor=facecolor)
32
+ fig.patch.set_facecolor(facecolor)
33
+ ax.set_facecolor(facecolor)
34
+
35
+ ax.scatter(
36
+ fitted,
37
+ resid,
38
+ s=32,
39
+ c="#7eb6d9",
40
+ alpha=0.78,
41
+ edgecolors="#1f1f1f",
42
+ linewidths=0.45,
43
+ zorder=3,
44
+ )
45
+ ax.axhline(
46
+ 0, color="#c0392b", linestyle="--", linewidth=1.8, zorder=4,
47
+ )
48
+
49
+ fmt = FuncFormatter(lambda v, _: f"{v:,.{decimals}f}")
50
+ ax.grid(True, linestyle="--", linewidth=0.8, alpha=0.45)
51
+ ax.set_axisbelow(True)
52
+ ax.spines["top"].set_visible(False)
53
+ ax.spines["right"].set_visible(False)
54
+ ax.spines["left"].set_linewidth(1.2)
55
+ ax.spines["bottom"].set_linewidth(1.2)
56
+ ax.tick_params(labelsize=10, length=5, width=1.1)
57
+ ax.ticklabel_format(style="plain")
58
+ ax.xaxis.set_major_formatter(fmt)
59
+ ax.yaxis.set_major_formatter(fmt)
60
+ ax.xaxis.set_major_locator(MaxNLocator(nbins=6))
61
+ ax.yaxis.set_major_locator(MaxNLocator(nbins=6))
62
+
63
+ ax.set_title("Residuals vs Fitted Values", fontsize=13, pad=10)
64
+ ax.set_xlabel("Fitted Values", fontsize=11)
65
+ ax.set_ylabel("Residuals", fontsize=11)
66
+
67
+ fig.tight_layout()
68
+ if save_path is not None:
69
+ fig.savefig(
70
+ save_path, dpi=save_dpi, facecolor=facecolor,
71
+ bbox_inches="tight", pad_inches=0.15,
72
+ )
73
+ plt.show(block=False)
74
+ return ax
@@ -0,0 +1,194 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ import pandas as pd
4
+ from matplotlib.ticker import FuncFormatter, MaxNLocator
5
+ from mpl_toolkits.mplot3d import Axes3D # noqa: F401
6
+
7
+
8
+ def scatter(
9
+ df,
10
+ y,
11
+ x,
12
+ fit_line=False,
13
+ decimals=1,
14
+ dpi=200,
15
+ save_dpi=300,
16
+ figsize=(7, 4.5),
17
+ save_path=None,
18
+ facecolor="white",
19
+ ):
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)
27
+ """
28
+ if isinstance(x, str):
29
+ x = [x]
30
+
31
+ if len(x) == 1:
32
+ ax = _scatter_2d(
33
+ df, y, x[0], fit_line=fit_line, decimals=decimals,
34
+ dpi=dpi, figsize=figsize, facecolor=facecolor,
35
+ )
36
+ else:
37
+ ax = _scatter_3d(
38
+ df, y, x[0], x[1], fit_line=fit_line, decimals=decimals,
39
+ dpi=dpi, figsize=figsize, facecolor=facecolor,
40
+ )
41
+
42
+ fig = ax.figure
43
+ fig.tight_layout()
44
+ if save_path is not None:
45
+ fig.savefig(
46
+ save_path, dpi=save_dpi, facecolor=facecolor,
47
+ bbox_inches="tight", pad_inches=0.15,
48
+ )
49
+ plt.show(block=False)
50
+ return ax
51
+
52
+
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}")
65
+ ax.grid(True, linestyle="--", linewidth=0.8, alpha=0.45)
66
+ ax.set_axisbelow(True)
67
+ ax.spines["top"].set_visible(False)
68
+ ax.spines["right"].set_visible(False)
69
+ ax.spines["left"].set_linewidth(1.2)
70
+ ax.spines["bottom"].set_linewidth(1.2)
71
+ ax.tick_params(labelsize=10, length=5, width=1.1)
72
+ ax.ticklabel_format(style="plain")
73
+ ax.xaxis.set_major_formatter(fmt)
74
+ ax.yaxis.set_major_formatter(fmt)
75
+ ax.xaxis.set_major_locator(MaxNLocator(nbins=6))
76
+ ax.yaxis.set_major_locator(MaxNLocator(nbins=6))
77
+
78
+
79
+ def _scatter_2d(df, y, x_var, fit_line, decimals, dpi, figsize, facecolor):
80
+ plot_df = df[[x_var, y]].dropna()
81
+ if plot_df.empty:
82
+ raise ValueError("No data to plot after dropping NaNs.")
83
+
84
+ xv = plot_df[x_var].to_numpy(dtype=float)
85
+ yv = plot_df[y].to_numpy(dtype=float)
86
+ corr = float(pd.Series(xv).corr(pd.Series(yv)))
87
+
88
+ fig, ax = plt.subplots(figsize=figsize, dpi=dpi, facecolor=facecolor)
89
+ fig.patch.set_facecolor(facecolor)
90
+ ax.set_facecolor(facecolor)
91
+
92
+ ax.scatter(
93
+ xv,
94
+ yv,
95
+ s=32,
96
+ c="#7eb6d9",
97
+ alpha=0.78,
98
+ edgecolors="#1f1f1f",
99
+ linewidths=0.45,
100
+ zorder=3,
101
+ )
102
+
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)
109
+ ax.plot(
110
+ x_line,
111
+ y_line,
112
+ color="#c0392b",
113
+ linewidth=1.8,
114
+ zorder=4,
115
+ )
116
+
117
+ _style_2d(ax, decimals)
118
+ ax.set_title(
119
+ f"{y} and {x_var}\nCorrelation: {corr:.2f}",
120
+ fontsize=13, pad=10,
121
+ )
122
+ ax.set_xlabel(x_var, fontsize=11)
123
+ ax.set_ylabel(y, fontsize=11)
124
+ return ax
125
+
126
+
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
+
132
+ plot_df = df[[x_var, z_var, y]].dropna()
133
+ if plot_df.empty:
134
+ raise ValueError("No data to plot after dropping NaNs.")
135
+
136
+ fig = plt.figure(figsize=figsize, dpi=dpi, facecolor=facecolor)
137
+ fig.patch.set_facecolor(facecolor)
138
+ ax = fig.add_subplot(111, projection="3d", facecolor=facecolor)
139
+
140
+ ax.scatter(
141
+ plot_df[x_var],
142
+ plot_df[z_var],
143
+ plot_df[y],
144
+ s=32,
145
+ c="#7eb6d9",
146
+ alpha=0.78,
147
+ edgecolors="#1f1f1f",
148
+ linewidths=0.45,
149
+ depthshade=True,
150
+ )
151
+
152
+ if kind == "linear":
153
+ X_data = np.column_stack(
154
+ [plot_df[x_var], plot_df[z_var], np.ones(len(plot_df))]
155
+ )
156
+ y_data = plot_df[y].to_numpy(dtype=float)
157
+ coeffs, *_ = np.linalg.lstsq(X_data, y_data, rcond=None)
158
+ a, b, c = coeffs
159
+
160
+ x_surf = np.linspace(plot_df[x_var].min(), plot_df[x_var].max(), 12)
161
+ z_surf = np.linspace(plot_df[z_var].min(), plot_df[z_var].max(), 12)
162
+ X_mesh, Z_mesh = np.meshgrid(x_surf, z_surf)
163
+ Y_mesh = a * X_mesh + b * Z_mesh + c
164
+ ax.plot_surface(
165
+ X_mesh,
166
+ Z_mesh,
167
+ Y_mesh,
168
+ color="#c0392b",
169
+ alpha=0.28,
170
+ edgecolor="none",
171
+ shade=False,
172
+ )
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
+
179
+ ax.set_title(f"{y}, {x_var}, and {z_var}", fontsize=13, pad=10)
180
+ ax.set_xlabel(x_var, fontsize=11, labelpad=8)
181
+ ax.set_ylabel(z_var, fontsize=11, labelpad=8)
182
+ ax.set_zlabel(y, fontsize=11, labelpad=8)
183
+ ax.tick_params(labelsize=9, length=4, width=1.0)
184
+
185
+ ax.zaxis._axinfo["juggled"] = (1, 2, 0)
186
+ ax.invert_xaxis()
187
+ ax.invert_yaxis()
188
+ ax.view_init(elev=25, azim=135)
189
+
190
+ grid = (0.55, 0.55, 0.55, 0.35)
191
+ ax.xaxis._axinfo["grid"]["color"] = grid
192
+ ax.yaxis._axinfo["grid"]["color"] = grid
193
+ ax.zaxis._axinfo["grid"]["color"] = grid
194
+ return ax
@@ -1,17 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: davis_stats
3
- Version: 2.2
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:
7
7
  Keywords: statistics,data science,business analytics
8
- Requires-Python: >=3.7
8
+ Requires-Python: >=3.11
9
9
  Requires-Dist: pandas>=3.0.6
10
10
  Requires-Dist: openpyxl>=3.0.0
11
11
  Requires-Dist: numpy>=1.20.0
12
12
  Requires-Dist: matplotlib>=3.11.2
13
13
  Requires-Dist: scipy>=1.6.0
14
- Requires-Dist: seaborn>=0.12.0
15
14
  Requires-Dist: statsmodels>=0.14.0
16
15
  Requires-Dist: ipympl>=0.8.0
17
16
  Requires-Dist: linearmodels>=7.0
@@ -19,6 +19,8 @@ davis_stats/datasets/restaurants.xlsx
19
19
  davis_stats/datasets/sp1500_2025.xlsx
20
20
  davis_stats/datasets/sp1500_panel.xlsx
21
21
  davis_stats/datasets/student_athletes.xlsx
22
+ davis_stats/datasets/sweet_things.xlsx
23
+ davis_stats/datasets/sweet_things_simple.xlsx
22
24
  davis_stats/datasets/world_cup_goals.xlsx
23
25
  davis_stats/practice/__init__.py
24
26
  davis_stats/practice/stats_practice.py
@@ -3,7 +3,6 @@ openpyxl>=3.0.0
3
3
  numpy>=1.20.0
4
4
  matplotlib>=3.11.2
5
5
  scipy>=1.6.0
6
- seaborn>=0.12.0
7
6
  statsmodels>=0.14.0
8
7
  ipympl>=0.8.0
9
8
  linearmodels>=7.0
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='davis_stats',
5
- version='2.2',
5
+ version='2.2.2',
6
6
  packages=find_packages(),
7
7
  package_data={
8
8
  'davis_stats': ['datasets/*.xlsx']},
@@ -12,11 +12,10 @@ setup(
12
12
  'numpy>=1.20.0',
13
13
  'matplotlib>=3.11.2',
14
14
  'scipy>=1.6.0',
15
- 'seaborn>=0.12.0',
16
15
  'statsmodels>=0.14.0',
17
16
  'ipympl>=0.8.0',
18
17
  'linearmodels>=7.0'],
19
- python_requires='>=3.7',
18
+ python_requires='>=3.11',
20
19
  author='Justin G. Davis',
21
20
  author_email='',
22
21
  description='''
@@ -1,25 +0,0 @@
1
- import matplotlib.pyplot as plt
2
- from ..reg_modeling.reg import reg
3
-
4
- def residuals(df, y, x, dummies=None, logistic=False, dpi=150, figsize=(6, 4)):
5
- """
6
- Plot residuals vs fitted values to check linearity.
7
- """
8
- results = reg(df, y, x, dummies=dummies, logistic=logistic, silent=True)
9
-
10
- if results is None:
11
- print("Error: Could not fit regression model")
12
- return
13
-
14
- residuals = results.resid
15
- fitted = results.fittedvalues
16
-
17
- plt.figure(figsize=figsize, dpi=dpi)
18
- plt.scatter(fitted, residuals, alpha=0.5, edgecolors='k', linewidth=0.5)
19
- plt.axhline(y=0, color='r', linestyle='--', linewidth=2)
20
- plt.xlabel('Fitted Values', fontsize=12)
21
- plt.ylabel('Residuals', fontsize=12)
22
- plt.title('Residuals vs Fitted Values', fontsize=14, fontweight='bold')
23
- plt.grid(True, alpha=0.3)
24
- plt.tight_layout()
25
- plt.show()
@@ -1,128 +0,0 @@
1
- import seaborn as sns
2
- import matplotlib.pyplot as plt
3
- import numpy as np
4
- from mpl_toolkits.mplot3d import Axes3D
5
-
6
- def scatter(df, y, x, fit_line=False, dpi=150, figsize=(6, 4)):
7
- """
8
- Create a 2D or 3D scatter plot with optional fit line.
9
- """
10
-
11
- # Convert x to list if string
12
- if isinstance(x, str):
13
- x = [x]
14
-
15
- # Determine plot type based on number of x variables
16
- if len(x) == 1:
17
- # 2D scatter plot
18
- x_var = x[0]
19
-
20
- # Calculate correlation coefficient
21
- corr = df[x_var].corr(df[y])
22
-
23
- # Set style
24
- sns.set_style("whitegrid")
25
-
26
- # Create figure
27
- fig, ax = plt.subplots(figsize=figsize, dpi=dpi)
28
-
29
- # Create scatter plot
30
- if fit_line:
31
- sns.regplot(data=df,
32
- x=x_var,
33
- y=y,
34
- scatter_kws={'alpha':0.5},
35
- line_kws={'color': 'red'},
36
- ci=None)
37
- else:
38
- sns.scatterplot(data=df,
39
- x=x_var,
40
- y=y,
41
- alpha=0.5)
42
-
43
- # Customize plot
44
- plt.title(f'{y} and {x_var}\nCorrelation: {corr:.3f}', pad=15)
45
- plt.xlabel(x_var)
46
- plt.ylabel(y)
47
-
48
- # Adjust layout
49
- plt.tight_layout()
50
-
51
- else:
52
- # 3D scatter plot (use first 2 variables from x list)
53
- x_var = x[0]
54
- z_var = x[1]
55
-
56
- # Create 3D figure
57
- fig = plt.figure(figsize=figsize, dpi=dpi)
58
- ax = fig.add_subplot(111, projection='3d')
59
-
60
- # Remove NaN values for plotting
61
- plot_df = df[[x_var, z_var, y]].dropna()
62
-
63
- # Create 3D scatter plot
64
- scatter = ax.scatter(plot_df[x_var], plot_df[z_var], plot_df[y],
65
- c=plot_df[y], cmap='RdYlBu_r', s=50,
66
- edgecolor='black', linewidth=0.5,
67
- alpha=0.8)
68
-
69
- # Add colorbar
70
- cbar = plt.colorbar(scatter, ax=ax, pad=0.15, shrink=0.8)
71
- cbar.set_label(y, rotation=270, labelpad=15)
72
-
73
- # Add best-fit plane if requested
74
- if fit_line:
75
- # Prepare data for plane fitting: y = a*x + b*z + c
76
- X_data = np.column_stack([plot_df[x_var], plot_df[z_var], np.ones(len(plot_df))])
77
- y_data = plot_df[y].values
78
-
79
- # Fit plane using least squares
80
- coeffs, residuals, rank, s = np.linalg.lstsq(X_data, y_data, rcond=None)
81
- a, b, c = coeffs
82
-
83
- # Create mesh grid for the regression plane
84
- x_surf = np.linspace(plot_df[x_var].min(), plot_df[x_var].max(), 20)
85
- z_surf = np.linspace(plot_df[z_var].min(), plot_df[z_var].max(), 20)
86
- X_mesh, Z_mesh = np.meshgrid(x_surf, z_surf)
87
-
88
- # Calculate y values for the plane
89
- Y_mesh = a * X_mesh + b * Z_mesh + c
90
-
91
- # Plot the regression plane
92
- surf = ax.plot_surface(X_mesh, Z_mesh, Y_mesh,
93
- alpha=0.4, cmap='coolwarm',
94
- edgecolor='black', linewidth=0.5,
95
- rstride=1, cstride=1,
96
- antialiased=True)
97
-
98
- # Set title
99
- title = f'{y}, {x_var}, and {z_var}'
100
-
101
- # Set axis labels
102
- ax.set_xlabel(x_var, labelpad=10)
103
- ax.set_ylabel(z_var, labelpad=10)
104
- ax.set_zlabel(y, labelpad=10)
105
-
106
- # Move z-axis to left side
107
- ax.zaxis._axinfo['juggled'] = (1, 2, 0)
108
-
109
- # Flip axes
110
- ax.invert_xaxis()
111
- ax.invert_yaxis()
112
-
113
- # Adjust viewing angle
114
- ax.view_init(elev=25, azim=135)
115
-
116
- # Grid styling
117
- ax.xaxis._axinfo["grid"]['color'] = (0.5, 0.5, 0.5, 0.5)
118
- ax.yaxis._axinfo["grid"]['color'] = (0.5, 0.5, 0.5, 0.5)
119
- ax.zaxis._axinfo["grid"]['color'] = (0.5, 0.5, 0.5, 0.5)
120
-
121
- # Set title
122
- ax.set_title(title, pad=15)
123
-
124
- # Adjust layout
125
- plt.tight_layout()
126
-
127
- # Show plot
128
- plt.show()
File without changes