Skip to content

Commit 4d38516

Browse files
committed
#53 tidy up and add some docstrings
1 parent 20eb82d commit 4d38516

File tree

6 files changed

+46
-29
lines changed

6 files changed

+46
-29
lines changed

CONTRIBUTING.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pip install -r requirements-dev.txt
2929
pip install -r requirements-docs.txt
3030
```
3131

32+
It may also be necessary to [install](https://pandoc.org/installing.html) `pandoc`. On a mac, I run `brew install pandoc`.
33+
3234
5. You may also need to run this to get pre-commit checks working
3335

3436
```
@@ -60,6 +62,14 @@ make clean && make html
6062

6163
Docs are built in `docs/_build`, but these docs are _not_ committed to the GitHub repository due to `.gitignore`.
6264

65+
## Remote documentation
66+
67+
Documentation is hosted on https://causalpy.readthedocs.io/. New remote builds are triggered automatically whenever there is an update to the `main` branch.
68+
69+
The `.readthedocs.yaml` file contains the configurations for the remote build.
70+
71+
If there are autodoc issues/errors in remote builds of the docs, we need to add all package dependencies (in `requirements.txt`) into the list `autodoc_mock_imports` in `docs/config.py`.
72+
6373
## New releases [work in progress]
6474

6575
1. Bump the release version in `causalpy/version.py`. This is automatically read by `setup.py` and `docs/config.py`.

causalpy/plot_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44
def plot_xY(x, Y, ax, plot_hdi_kwargs=dict()):
5-
"""Utility function to plot HDI intervals"""
5+
"""Utility function to plot HDI intervals."""
66
quantiles = Y.quantile(
77
(0.025, 0.25, 0.5, 0.75, 0.975), dim=("chain", "draw")
88
).transpose()

causalpy/pymc_experiments.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313

1414
class ExperimentalDesign:
15+
"""Base class"""
16+
1517
prediction_model = None
1618

1719
def __init__(self, prediction_model=None, **kwargs):
@@ -22,6 +24,8 @@ def __init__(self, prediction_model=None, **kwargs):
2224

2325

2426
class TimeSeriesExperiment(ExperimentalDesign):
27+
"""A class to analyse time series quasi-experiments"""
28+
2529
def __init__(self, data, treatment_time, formula, prediction_model=None, **kwargs):
2630
super().__init__(prediction_model=prediction_model, **kwargs)
2731
self.treatment_time = treatment_time
@@ -71,6 +75,7 @@ def __init__(self, data, treatment_time, formula, prediction_model=None, **kwarg
7175
self.post_impact_cumulative = self.post_impact.cumsum(dim="obs_ind")
7276

7377
def plot(self):
78+
"""Plot the results"""
7479
fig, ax = plt.subplots(3, 1, sharex=True, figsize=(7, 8))
7580

7681
# pre-intervention period
@@ -107,6 +112,7 @@ def plot(self):
107112

108113
class SyntheticControl(TimeSeriesExperiment):
109114
def plot(self):
115+
"""Plot the results"""
110116
fig, ax = super().plot()
111117
# plot control units as well
112118
ax[0].plot(self.datapre.index, self.pre_X, "-", c=[0.8, 0.8, 0.8], zorder=1)
@@ -119,7 +125,12 @@ class InterruptedTimeSeries(TimeSeriesExperiment):
119125

120126

121127
class DifferenceInDifferences(ExperimentalDesign):
122-
"""Note: there is no pre/post intervention data distinction for DiD, we fit all the data available."""
128+
"""A class to analyse data from Difference in Difference settings.
129+
130+
.. Note::
131+
132+
There is no pre/post intervention data distinction for DiD, we fit all the data available.
133+
"""
123134

124135
def __init__(
125136
self,
@@ -183,6 +194,7 @@ def __init__(
183194
)
184195

185196
def plot(self):
197+
"""Plot the results"""
186198
fig, ax = plt.subplots()
187199

188200
# Plot raw data
@@ -272,7 +284,13 @@ def plot(self):
272284

273285

274286
class RegressionDiscontinuity(ExperimentalDesign):
275-
"""Note: there is no pre/post intervention data distinction, we fit all the data available."""
287+
"""
288+
A class to analyse regression discontinuity experiments.
289+
290+
.. Note::
291+
292+
There is no pre/post intervention data distinction for DiD, we fit all the data available.
293+
"""
276294

277295
def __init__(
278296
self,
@@ -337,9 +355,16 @@ def __init__(
337355
)
338356

339357
def _is_treated(self, x):
358+
"""Returns true is `x` is greater than or equal to the treatment threshold
359+
360+
.. admonition::
361+
362+
Assumes treatment is given to those ABOVE the treatment threshold.
363+
"""
340364
return np.greater_equal(x, self.treatment_threshold)
341365

342366
def plot(self):
367+
"""Plot the results"""
343368
fig, ax = plt.subplots()
344369
# Plot raw data
345370
sns.scatterplot(
@@ -373,6 +398,7 @@ def plot(self):
373398
return (fig, ax)
374399

375400
def summary(self):
401+
"""Print text output summarising the results"""
376402
print("Difference in Differences experiment")
377403
print(f"Formula: {self.formula}")
378404
print(f"Running variable: {self.running_variable_name}")

causalpy/pymc_models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def _data_setter(self, X):
2121
pm.set_data({"X": X})
2222

2323
def fit(self, X, y, coords):
24+
"""Draw samples from posterior, prior predictive, and posterior predictive distributions."""
2425
self.build_model(X, y, coords)
2526
with self.model:
2627
self.idata = pm.sample()
@@ -29,6 +30,7 @@ def fit(self, X, y, coords):
2930
return self.idata
3031

3132
def predict(self, X):
33+
"""Predict data given input data `X`"""
3234
self._data_setter(X)
3335
with self.model: # sample with new input data
3436
post_pred = pm.sample_posterior_predictive(
@@ -37,6 +39,7 @@ def predict(self, X):
3739
return post_pred
3840

3941
def score(self, X, y):
42+
"""Score the predictions $R^2$ given inputs X and outputs y."""
4043
yhat = self.predict(X)
4144
yhat = az.extract(yhat, group="posterior_predictive", var_names="y_hat").mean(
4245
dim="sample"
@@ -48,6 +51,7 @@ class WeightedSumFitter(ModelBuilder):
4851
"""Used for synthetic control experiments"""
4952

5053
def build_model(self, X, y, coords):
54+
"""Defines the PyMC model"""
5155
with self:
5256
self.add_coords(coords)
5357
n_predictors = X.shape[1]
@@ -60,7 +64,10 @@ def build_model(self, X, y, coords):
6064

6165

6266
class LinearRegression(ModelBuilder):
67+
"""Custom PyMC model for linear regression"""
68+
6369
def build_model(self, X, y, coords):
70+
"""Defines the PyMC model"""
6471
with self:
6572
self.add_coords(coords)
6673
X = pm.MutableData("X", X, dims=["obs_ind", "coeffs"])

docs/conf.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,6 @@
1414

1515
sys.path.insert(0, os.path.abspath("../"))
1616

17-
18-
# Need to mock the package dependencies in order for autodoc to work when docs are remotely built on readthedocs
19-
# from mock import Mock as MagicMock
20-
21-
22-
# class Mock(MagicMock):
23-
# @classmethod
24-
# def __getattr__(cls, name):
25-
# return MagicMock()
26-
27-
28-
# MOCK_MODULES = [
29-
# "arviz",
30-
# "matplotlib",
31-
# "numpy",
32-
# "pandas",
33-
# "patsy",
34-
# "pymc",
35-
# "scipy",
36-
# "seaborn",
37-
# "sklearn",
38-
# "xarray",
39-
# ]
40-
# sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES)
41-
4217
# autodoc_mock_imports
4318
# This avoids autodoc breaking when it can't find packages imported in the code.
4419
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_mock_imports

requirements-docs.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
ipykernel
22
linkify-it-py
3-
# mock
43
myst_parser
54
nbsphinx
65
pathlib

0 commit comments

Comments
 (0)