Skip to content

Commit f501af5

Browse files
committed
convert survival plot to using plotnine
1 parent 0f21f8c commit f501af5

1 file changed

Lines changed: 54 additions & 30 deletions

File tree

flexynesis/utils.py

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@
3535
from lifelines import KaplanMeierFitter
3636
from lifelines.utils import concordance_index
3737
from lifelines import CoxPHFitter
38+
from lifelines.statistics import logrank_test, multivariate_logrank_test
39+
40+
from plotnine import (
41+
ggplot, aes, geom_step, labs, theme_minimal,
42+
ggtitle, annotate, theme, element_text,
43+
scale_color_manual, scale_color_gradient, scale_color_brewer
44+
)
45+
3846

3947
from sklearn.cluster import KMeans
4048
from sklearn.metrics import silhouette_score
@@ -45,7 +53,6 @@
4553
from sklearn.preprocessing import StandardScaler
4654
import ot
4755

48-
from plotnine import ggplot, aes, geom_point, scale_color_manual, scale_color_gradient, labs, theme_minimal
4956

5057
def plot_dim_reduced(matrix, labels, method='pca', color_type='categorical'):
5158
"""
@@ -801,42 +808,59 @@ def print_summary_stats(dataset):
801808

802809
def plot_kaplan_meier_curves(durations, events, categorical_variable):
803810
"""
804-
Plots Kaplan-Meier survival curves for different groups defined by a categorical variable.
805-
806-
Parameters:
807-
- durations: An array-like object of survival times or durations.
808-
- events: An array-like object indicating whether an event (e.g., death) occurred (1) or was censored (0).
809-
- categorical_variable: An array-like object defining groups for plotting different survival curves.
811+
Plots Kaplan-Meier survival curves using plotnine and annotates log-rank test p-values.
810812
"""
811-
# Initialize the Kaplan-Meier fitter
812-
kmf = KaplanMeierFitter()
813-
814-
# Ensure data is in a pandas DataFrame for easy handling
813+
# Prepare DataFrame
815814
data = pd.DataFrame({
816815
'Duration': durations,
817816
'Event': events,
818817
'Group': categorical_variable
819818
})
820-
821-
# Plot survival curves for each category
822-
plt.figure(figsize=(10, 6))
819+
820+
kmf = KaplanMeierFitter()
821+
survival_curves = []
822+
823+
# Fit Kaplan-Meier for each group and collect survival data
824+
for group in data['Group'].unique():
825+
group_data = data[data['Group'] == group]
826+
kmf.fit(group_data['Duration'], group_data['Event'], label=str(group))
827+
surv_df = kmf.survival_function_.reset_index()
828+
surv_df.columns = ['Time', 'Survival']
829+
surv_df['Group'] = str(group)
830+
survival_curves.append(surv_df)
831+
832+
# Combine all curves
833+
plot_data = pd.concat(survival_curves)
834+
835+
# Compute log-rank p-value
823836
categories = data['Group'].unique()
824-
for category in categories:
825-
# Select data for the group
826-
group_data = data[data['Group'] == category]
827-
828-
# Fit the model
829-
kmf.fit(durations=group_data['Duration'], event_observed=group_data['Event'], label=str(category))
830-
831-
# Plot the survival curve for the group
832-
kmf.plot_survival_function()
833-
834-
plt.title('Kaplan-Meier Survival Curves by Group')
835-
plt.xlabel('Time')
836-
plt.ylabel('Survival Probability')
837-
plt.legend(title='Group')
838-
plt.grid(True)
839-
plt.show()
837+
p_text = ""
838+
if len(categories) == 2:
839+
group1 = data[data['Group'] == categories[0]]
840+
group2 = data[data['Group'] == categories[1]]
841+
result = logrank_test(group1['Duration'], group2['Duration'],
842+
event_observed_A=group1['Event'],
843+
event_observed_B=group2['Event'])
844+
p_text = f"Log-rank p = {result.p_value:.4f}"
845+
elif len(categories) > 2:
846+
result = multivariate_logrank_test(data['Duration'], data['Group'], data['Event'])
847+
p_text = f"Multivariate log-rank p = {result.p_value:.4f}"
848+
else:
849+
p_text = "Only one group — log-rank test not applicable"
850+
851+
# Create plot
852+
p = (
853+
ggplot(plot_data, aes(x='Time', y='Survival', color='Group'))
854+
+ geom_step()
855+
+ labs(x='Time', y='Survival Probability', color='Group')
856+
+ ggtitle('Kaplan-Meier Survival Curves by Group')
857+
+ annotate("text", x=plot_data['Time'].max() * 0.6, y=0.1, label=p_text, size=10, ha='left')
858+
+ theme_minimal()
859+
+ theme(legend_title=element_text(size=10, weight='bold'))
860+
+ scale_color_brewer(type='qual', palette='Set1')
861+
)
862+
863+
return p
840864

841865

842866
def plot_hazard_ratios(cox_model):

0 commit comments

Comments
 (0)