CamDavidsonPilon / lifelines

Survival analysis in Python
lifelines.readthedocs.org
MIT License
2.34k stars 555 forks source link

Wrong spacing when adding a risk table to a subplot #991

Closed Godrebh closed 4 years ago

Godrebh commented 4 years ago

When plotting Kaplan Meier curves within subplots and adding the risk table, the spacing between plot and table is off and they may even overlap. This is because the y-position of the table is calculated by using the figure height, when acutally the subplot height would be necessary here.

In the function liflines.plotting.add_at_risk_counts() , I replaced the line: ax2_ypos = -0.15 * 6.0 / fig.get_figheight() with

ax_height = (ax.get_position().y1 - ax.get_position().y0) * fig.get_figheight() # axis height
ax2_ypos = -0.1 * 6.0 / ax_height

and this looks much better.

CamDavidsonPilon commented 4 years ago

oh nice! Let me try this locally, and implement this fix for the next release. Thanks!

CamDavidsonPilon commented 4 years ago

Hm, I haven't been able to reproduce the bug locally. Can you provide a small code snippet of what caused the initial problem?

Godrebh commented 4 years ago

Sure, here you go:

import lifelines
import matplotlib as mpl
import matplotlib.pyplot as plt
from lifelines.datasets import load_waltons
waltons = load_waltons()
ix = waltons['group'] == 'control'

img_no = 3

height = 4 * img_no
half_inch = 0.5 / height  # in percent height
_fig = plt.figure(figsize=(6, height), dpi=300)
gs = mpl.gridspec.GridSpec(img_no, 1)
plt.subplots_adjust(left=0.08, right=0.98, bottom=half_inch, top=1-half_inch)

for i in range(img_no):
    ax = plt.subplot(gs[i, 0])
    kmf_control = lifelines.KaplanMeierFitter()
    ax = kmf_control.fit(waltons.loc[ix]['T'], waltons.loc[ix]['E'], label='control').plot(ax=ax)
    kmf_exp = lifelines.KaplanMeierFitter()
    ax = kmf_exp.fit(waltons.loc[~ix]['T'], waltons.loc[~ix]['E'], label='exp').plot(ax=ax)
    ax = lifelines.plotting.add_at_risk_counts(kmf_exp, kmf_control, ax=ax)

plt.subplots_adjust(hspace=0.6)
plt.savefig('kaplan_meier.png')
plt.close()

With img_no = 1, everything looks fine, but the more images are added, the worse the overlap will get. The height of each subplot image here is 4 inch, but with the three subplots the figure height is 12 and this is used to calculate the y position of the table. What I propose does calculate the height of the axis, which is not exactly 4, but a bit less. I also changed the -0.15 to -0.1, because it looked a bit better.

CamDavidsonPilon commented 4 years ago

Fixed in v0.24.5