Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 0 additions & 35 deletions .github/workflows/docs.yml

This file was deleted.

22 changes: 22 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the OS, Python version, and other tools you might need
build:
os: ubuntu-24.04
tools:
python: "3.13"

# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py

# Optionally, but recommended,
# declare the Python requirements required to build your documentation
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: docs/requirements.txt
12 changes: 12 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
sphinx
piccolo_theme
sphinx-autodoc-typehints
sphinx-copybutton
myst-parser
numpy
polars
tqdm
statsmodels
matplotlib
pyarrow
lifelines
28 changes: 24 additions & 4 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,36 @@

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
import os
import sys
from datetime import date
import importlib.metadata

version = importlib.metadata.version("pySEQTarget")
sys.path.insert(0, os.path.abspath("../"))

project = "pySEQTarget"
copyright = "2025, Ryan O'Dea, Alejandro Szmulewicz, Tom Palmer, Miguel Hernan"
copyright = f"{date.today().year}, Ryan O'Dea, Alejandro Szmulewicz, Tom Palmer, Miguel Hernan"
author = "Ryan O'Dea, Alejandro Szmulewicz, Tom Palmer, Miguel Hernan"
release = "0.9.0"
release = version

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = []
extensions = [
"sphinx.ext.duration",
"sphinx.ext.doctest",
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.intersphinx",
"sphinx_copybutton",
"sphinx_autodoc_typehints",
"myst_parser"
]

intersphinx_mapping = {
"py": ("https://docs.python.org/3", None)
}

templates_path = ["_templates"]
exclude_patterns = []
Expand All @@ -23,5 +43,5 @@
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = "alabaster"
html_theme = "piccolo_theme"
html_static_path = ["_static"]
17 changes: 6 additions & 11 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
.. pySEQTarget documentation master file, created by
sphinx-quickstart on Mon Nov 24 20:43:34 2025.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.

pySEQTarget documentation
=========================

Add your content using ``reStructuredText`` syntax. See the
`reStructuredText <https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html>`_
documentation for details.
.. include:: ../../README.md
:parser: myst_parser.sphinx_


.. toctree::
:maxdepth: 2
:hidden:
:caption: Contents:

sequential/seqopts
sequential/sequential
sequential/seqoutput
4 changes: 4 additions & 0 deletions docs/source/sequential/seqopts.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SEQopts
===========
.. autoclass:: pySEQTarget.SEQopts
:members:
5 changes: 5 additions & 0 deletions docs/source/sequential/seqoutput.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SEQoutput
================

.. autoclass:: pySEQTarget.SEQoutput
:members:
5 changes: 5 additions & 0 deletions docs/source/sequential/sequential.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SEQuential
====================

.. autoclass:: pySEQTarget.SEQuential
:members:
93 changes: 92 additions & 1 deletion pySEQTarget/SEQopts.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,97 @@

@dataclass
class SEQopts:
"""
Parameter builder for ``pySEQTarget.SEQuential`` analysis

:param bootstrap_nboot: Number of bootstraps to preform
:type bootstrap_nboot: int
:param bootstrap_sample: Subsampling proportion of ID-Trials gathered for each bootstrapping iteration
:type bootstrap_sample: float
:param bootstrap_CI: If bootstrapped, confidence interval level
:type bootstrap_CI: float
:param bootstrap_CI_method: If bootstrapped, confidence method generation method ['SE' or 'percentile']
:type bootstrap_CI_method: str
:param cense_colname: Column name for censoring effect (LTFU, etc.)
:type cense_colname: str
:param cense_denominator: Override to specify denominator patsy formula for censoring models
:type cense_denominator: Optional[str] or None
:param cense_numerator: Override to specify numerator patsy formula for censoring models
:type cense_numerator: Optional[str] or None
:param cense_eligible_colname: Column name to identify which rows are eligible for censoring model fitting
:type cense_eligible_colname: Optional[str] or None
:param compevent_colname: Column name specifying a competing event to the outcome
:type compevent_colname: str
:param covariates: Override to specify the outcome patsy formula for outcome model fitting
:type covariates: Optional[str] or None
:param denominator: Override to specify the outcome patsy formula for denominator model fitting
:type denominator: Optional[str] or None
:param excused: Boolean to allow excused conditions when method is censoring
:type excused: bool
:param excused_colnames: Column names (at the same length of treatment_level) specifying excused conditions
:type excused_colnames: List[str] or []
:param followup_class: Boolean to force followup values to be treated as classes
:type followup_class: bool
:param followup_include: Boolean to force regular followup values into model covariates
:type followup_include: bool
:param followup_spline: Boolean to force followup values to be fit to cubic spline
:type followup_spline: bool
:param followup_max: Maximum allowed followup in analysis
:type followup_max: int or None
:param followup_min: Minimum allowed followup in analysis
:type followup_min: int
:param hazard_estimate: Boolean to create hazard estimates
:type hazard_estimate: bool
:param indicator_baseline: How to indicate baseline columns in models
:type indicator_baseline: str
:param indicator_squared: How to indicate squared columns in models
:type indicator_baseline: str
:param km_curves: Boolean to create survival, risk, and incidence (if applicable) estimates
:type km_curves: bool
:param ncores: Number of cores to use if running in parallel
:type ncores: int
:param numerator: Override to specify the outcome patsy formula for numerator models
:type numerator: str
:param parallel: Boolean to run model fitting in parallel
:type parallel: bool
:param plot_colors: List of colors for KM plots, if applicable
:type plot_colors: List[str]
:param plot_labels: List of length treat_level to specify treatment labeling
:type plot_labels: List[str]
:param plot_title: Plot title
:type plot_title: str
:param plot_type: Type of plot to show ["risk", "survival" or "incidence" if compevent is specified]
:type plot_type: str
:param seed: RNG seed
:type seed: int
:param selection_first_trial: Boolean to only use first trial for analysis (similar to non-expanded)
:type selection_first_trial: bool
:param selection_sample: Subsampling proportion of ID-trials which did not initiate a treatment
:type selection_sample: float
:param selection_random: Boolean to randomly downsample ID-trials which did not initiate a treatment
:type selection_random: bool
:param subgroup_colname: Column name for subgroups to share the same weighting but different outcome model fits
:type subgroup_colname: str
:param treatment_level: List of eligible treatment levels within treatment_col
:type treatment_level: List[int]
:param trial_include: Boolean to force trial values into model covariates
:type trial_include: bool
:param weight_eligible_colnames: List of column names of length treatment_level to identify which rows are eligible for weight fitting
:type weight_eligible_colnames: List[str]
:param weight_min: Minimum weight
:type weight_min: float
:param weight_max: Maximum weight
:type weight_max: float or None
:param weight_lag_condition: Boolean to fit weights based on their treatment lag
:type weight_lag_condition: bool
:param weight_p99: Boolean to force weight min and max to be 1st and 99th percentile respectively
:type weight_p99: bool
:param weight_preexpansion: Boolean to fit weights on preexpanded data
:type weight_preexpansion: bool
:param weighted: Boolean to weight analysis
:type weighted: bool
"""

bootstrap_nboot: int = 0
bootstrap_sample: float = 0.8
bootstrap_CI: float = 0.95
Expand Down Expand Up @@ -38,7 +129,7 @@ class SEQopts:
plot_type: Literal["risk", "survival", "incidence"] = "risk"
seed: Optional[int] = None
selection_first_trial: bool = False
selection_probability: float = 0.8
selection_sample: float = 0.8
selection_random: bool = False
subgroup_colname: str = None
treatment_level: List[int] = field(default_factory=lambda: [0, 1])
Expand Down
50 changes: 47 additions & 3 deletions pySEQTarget/SEQoutput.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,37 @@

@dataclass
class SEQoutput:
"""
Collector class for results from ``SEQuential``

:param options: Options used in the SEQuential process
:type options: SEQopts or None
:param method: Method of analysis ['ITT', 'dose-response', or 'censoring']
:type method: str
:param numerator_models: Numerator models, if applicable, from the weighting process
:type numerator_models: List[ResultsWrapper] or None
:param denominator_models: Denominator models, if applicable, from the weighting process
:type denominator_models: List[ResultsWrapper] or None
:param compevent_models: Competing event models, if applicable
:type compevent_models: List[ResultsWrapper] or None
:param weight_statistics: Weight statistics once returned back to the expanded dataset
:type weight_statistics: dict or None
:param hazard: Hazard ratio if applicable
:type hazard: pl.DataFrame or None
:param km_data: Dataframe of risk, survival, and incidence data if applicable at all followups
:type km_data: pl.DataFrame or None
:param km_graph: Figure of survival, risk, or incidence over followup times
:type km_graph: matplotlib.figure.Figure or None
:param risk_ratio: Dataframe of risk ratios, compared between treatments and subgroups
:type risk_ratio: pl.DataFrame or None
:param risk_difference: Dataframe of risk differences, compared between treatments and subgroups
:type risk_difference: pl.DataFrame or None
:param time: Timings for every step of the process completed thus far
:type time: dict or None
:param diagnostic_tables: Diagnostic tables for unique and nonunique outcome events and treatment switches
:type diagnostic_tables: dict or None
"""

options: SEQopts = None
method: str = None
numerator_models: List[ResultsWrapper] = None
Expand All @@ -25,12 +56,20 @@ class SEQoutput:
time: dict = None
diagnostic_tables: dict = None

def plot(self):
def plot(self) -> None:
"""
Prints the kaplan-meier graph
"""
print(self.km_graph)

def summary(
self, type=Optional[Literal["numerator", "denominator", "outcome", "compevent"]]
):
) -> List:
"""
Returns a list of model summaries of either the numerator, denominator, outcome, or competing event models
:param type: Indicator for which model list you would like returned
:type type: str
"""
match type:
case "numerator":
models = self.numerator_models
Expand All @@ -57,7 +96,12 @@ def retrieve_data(
"nonunique_switches",
]
],
):
) -> pl.DataFrame:
"""
Getter for data stored within ``SEQoutput``
:param type: Data which you would like to access, ['km_data', 'hazard', 'risk_ratio', 'risk_difference', 'unique_outcomes', 'nonunique_outcomes', 'unique_switches', 'nonunique_switches']
:type type: str
"""
match type:
case "hazard":
data = self.hazard
Expand Down
Loading
Loading