# Kaplan–Meier survival curve maker with log-rank test

> Make a Kaplan–Meier survival curve online: censoring ticks, number at risk, 95% CI band, median survival, log-rank P value and hazard ratio. PNG, SVG, CSV.

URL: https://www.labcanvas.com/tools/kaplan-meier-plot

Paste one row per subject with the time, the event (1 = event, 0 = censored) and, optionally, a group. The tool draws the Kaplan–Meier (product-limit) survival curves with censoring ticks, a 95% confidence band and the number-at-risk table under the plot. It reports the median survival with its 95% confidence interval, Greenwood standard errors, the log-rank test P value between groups and the hazard ratio of two groups, and exports the figure as PNG or SVG and the tables as CSV.

## Quick answer

- **What it does:** Draws Kaplan–Meier survival curves from time and event data and compares groups with the log-rank test.
- **Formula:** S(t) = Π over tᵢ ≤ t of (1 − dᵢ/nᵢ);  Var[Ŝ(t)] = Ŝ(t)² · Σ dᵢ / (nᵢ(nᵢ − dᵢ)) (Greenwood);  log-rank χ² = (O − E)² / V
- **Example:** In the AML maintenance trial (11 maintained, 12 not), survival at 18 weeks in the maintained group is 10/11 × 9/10 × 7/8 = 0.716 (SE 0.140); median remission is 31 weeks vs 23 weeks, log-rank χ² = 3.40, P = 0.065.

Free, in the browser, no account needed. Updated 2026-10-19.

## Features

- Kaplan–Meier product-limit estimate for one or more groups, with censoring tick marks
- Number-at-risk table aligned under the time axis
- Greenwood standard errors and a pointwise 95% confidence band: log–log (default), log (R’s default) or plain
- Median survival with its 95% confidence interval (Brookmeyer–Crowley, as R’s survfit)
- Log-rank (Mantel–Cox) test for two or more groups, with observed and expected events
- Hazard ratio of two groups by the log-rank O/E method, and the Mantel–Haenszel estimate
- Full product-limit table for each group
- Plot as PNG or SVG, tables as CSV; checked against R’s survival package and lifelines

## How to use it

1. **Paste the data**: One subject per row: time, event (1 = death, relapse or other event; 0 = censored) and an optional group. Copy the columns straight from Excel.
2. **Choose the options**: Keep the log–log confidence limits, set the time unit and, if you like, a fixed end for the time axis.
3. **Read and export**: Read the medians, the log-rank P value and the hazard ratio, then download the plot and the tables.

## At a glance

| | |
| --- | --- |
| Input | Time, event (1/0) and optional group per subject, pasted from Excel |
| Estimate | Kaplan–Meier product limit with Greenwood SE |
| Confidence limits | Pointwise 95%: log–log (default), log or plain |
| Median | With 95% CI (Brookmeyer–Crowley, as R) |
| Comparison | Log-rank \(\chi^2\) for two or more groups; hazard ratio (O/E and Mantel–Haenszel) for two |
| Checked against | R survival (survfit, survdiff) and Python lifelines on the aml data |
| Output | Plot with number at risk as PNG or SVG; tables as CSV |

## How it works

$$\hat{S}(t) = \prod_{t_i \le t} \left(1 - \frac{d_i}{n_i}\right)$$

$$\begin{aligned} &\operatorname{Var}[\hat{S}(t)] = \hat{S}(t)^2 \cdot \sum_{t_i \le t} \frac{d_i}{n_i\,(n_i - d_i)} \\ &\text{(Greenwood)} \end{aligned}$$

$$\begin{aligned} &\text{Log–log 95\% limits:} \\ &\hat{S}(t)^{\exp(\pm 1.96 \cdot \sigma(t)/\ln \hat{S}(t))}, \\ &\sigma(t)^2 = \sum \frac{d_i}{n_i\,(n_i - d_i)} \end{aligned}$$

**Product-limit estimate.** At each distinct event time \(t_i\), \(n_i\) subjects are at risk (still followed and event-free just before \(t_i\)) and \(d_i\) have the event. The survival probability is multiplied by \((1 - d_i/n_i)\) at each event time and stays flat between them (Kaplan and Meier 1958). A subject censored at time \(c\) counts as at risk at every event time up to and including \(c\), and then leaves the risk set; censoring at the same time as an event is treated as happening just after it. Censored subjects are shown as tick marks on the curve.

**Standard error and confidence band.** The standard error is Greenwood’s formula (Greenwood 1926). The 95% limits are computed on the \(\log(-\log S)\) scale by default, which keeps them inside 0–1 and makes them asymmetric near 0 and 1; this matches R’s `survfit(..., conf.type = "log-log")` and lifelines. You can switch to the log scale (R’s default, `conf.type = "log"`) or to plain limits \(\hat{S} \pm 1.96 \cdot \mathrm{SE}\) clipped to 0–1. The band is pointwise, not a simultaneous band for the whole curve.

**Median survival.** The median is the first time \(\hat{S}(t)\) falls to 0.5 or below (where the curve is flat at exactly 0.5, the midpoint of that stretch). Its 95% confidence interval runs between the times at which the lower and upper confidence limits cross 0.5 (Brookmeyer and Crowley 1982), as R’s `quantile.survfit` does; an upper limit that never crosses 0.5 is “not reached”.

**Log-rank test.** At each event time the expected number of events in group \(g\) is \(E_g = d \cdot n_g/n\) under the null hypothesis of equal survival; summing over event times gives the observed \(O_g\) and expected \(E_g\). The statistic \((O - E)^\mathsf{T} V^{-1} (O - E)\), with the hypergeometric variance \(V\), follows \(\chi^2\) with (groups − 1) degrees of freedom (Mantel 1966). With two groups the hazard ratio is estimated as \((O_1/E_1)/(O_2/E_2)\), with a 95% interval from \(\mathrm{SE}[\ln \mathrm{HR}] = \sqrt{1/E_1 + 1/E_2}\); the Mantel–Haenszel estimate \(\exp((O_1 - E_1)/V)\) is shown beside it. Both assume roughly proportional hazards, which crossing curves contradict.

Sources: Kaplan EL, Meier P. Nonparametric estimation from incomplete observations. *J Am Stat Assoc* 1958;53:457–481, [doi:10.1080/01621459.1958.10501452](https://doi.org/10.1080/01621459.1958.10501452). Brookmeyer R, Crowley J. A confidence interval for the median survival time. *Biometrics* 1982;38:29–41, [doi:10.2307/2530286](https://doi.org/10.2307/2530286). Mantel N. Evaluation of survival data and two new rank order statistics arising in its consideration. *Cancer Chemother Rep* 1966;50:163–170. Greenwood M. *The natural duration of cancer*. Reports on Public Health and Medical Subjects No. 33. London: HMSO; 1926.

## Worked example: the AML maintenance trial, checked against R

The built-in example is the acute myelogenous leukaemia trial distributed as the `aml` data set with R’s survival package: weeks in remission for 11 patients given maintenance chemotherapy and 12 who were not (a + marks a censored time).

- Maintained: 9, 13, 13+, 18, 23, 28+, 31, 34, 45+, 48, 161+
- Nonmaintained: 5, 5, 8, 8, 12, 16+, 23, 27, 30, 33, 43, 45

**The product-limit estimate by hand** for the maintained group:

| Week | At risk \(n\) | Events \(d\) | \(1 - d/n\) | \(S(t)\) | SE | 95% CI |
| --- | --- | --- | --- | --- | --- | --- |
| 9 | 11 | 1 | 10/11 | 0.9091 | 0.0867 | 0.5081 to 0.9867 |
| 13 | 10 | 1 | 9/10 | 0.8182 | 0.1163 | 0.4474 to 0.9512 |
| 18 | 8 | 1 | 7/8 | 0.7159 | 0.1397 | 0.3502 to 0.8990 |
| 23 | 7 | 1 | 6/7 | 0.6136 | 0.1526 | 0.2658 to 0.8353 |
| 31 | 5 | 1 | 4/5 | 0.4909 | 0.1642 | 0.1673 to 0.7534 |
| 34 | 4 | 1 | 3/4 | 0.3682 | 0.1627 | 0.0928 to 0.6570 |
| 48 | 2 | 1 | 1/2 | 0.1841 | 0.1535 | 0.0117 to 0.5250 |

- **Risk sets.** At week 18 only 8 patients are at risk: two relapsed (weeks 9 and 13) and one was censored at week 13. The patient censored at 13 counts as at risk at the week-13 relapse.
- **Multiply.** \(S(18) = 10/11 \times 9/10 \times 7/8 = 0.7159\).
- **Greenwood.** \(\sum d/(n(n - d))\) \(= 1/110 + 1/90 + 1/56 = 0.03808\), so \(\mathrm{SE} = 0.7159 \times \sqrt{0.03808} = 0.1397\).
- **Median.** The curve first falls below 0.5 at week 31 (0.4909), so the median remission is **31 weeks**; the lower log–log limit crosses 0.5 at week 13 and the upper never does, so the 95% CI is 13 weeks to not reached. For the nonmaintained group the median is **23 weeks** (95% CI 5 to 33).
- **Log-rank test.** Observed and expected relapses are 7 and 10.69 (maintained) and 11 and 7.31 (nonmaintained), giving \(\chi^2 = 3.40\) with 1 df and **P = 0.065**. The O/E hazard ratio, maintained vs nonmaintained, is \((7/10.69)/(11/7.31)\) = **0.44** (95% CI 0.17 to 1.11).

These numbers match R exactly: `survfit(Surv(time, status) ~ x, data = aml, conf.type = "log-log")` gives the same survival, standard errors and limits (with R’s default log limits the first row reads 0.7541 to 1.000, which the tool also gives on the log setting), and `survdiff` gives \(O = 7\) and 11, \(E = 10.69\) and 7.31, \(\chi^2 = 3.4\) on 1 df, p = 0.07. Python’s lifelines gives the same limits, medians and log-rank statistic (3.396, p = 0.0653).

## Questions

### How do I make a Kaplan–Meier curve?

For each subject record the time from the start (diagnosis, treatment, enrolment) to the event or to the last follow-up, and whether the event happened (1) or the subject was censored (0). Paste the columns here: the tool sorts the times, computes \(S(t) = \prod (1 - d/n)\) at each event time and draws the step curve with censoring ticks and the number at risk.

### How do I calculate Kaplan–Meier survival by hand?

Sort the times. At each time with an event, divide the number of events \(d\) by the number still at risk \(n\), and multiply the running survival by \((1 - d/n)\). Censored subjects do not change the survival but drop out of the risk set after their time. Example: 11 at risk and 1 event gives \(10/11 = 0.909\); then 10 at risk and 1 event gives \(0.909 \times 9/10 = 0.818\).

### What does censored mean in survival analysis?

A censored subject did not have the event while being followed: the study ended, they were lost to follow-up or they withdrew. All you know is that their time to event is longer than their follow-up time. Censored subjects count in the risk set until they leave and are drawn as tick marks on the curve.

### How is median survival calculated?

It is the first time the Kaplan–Meier curve reaches 50% or below. If the curve never falls to 50%, the median is “not reached”. Its 95% confidence interval runs from where the lower to where the upper confidence curve crosses 50% (Brookmeyer and Crowley 1982).

### How do I compare two survival curves?

Use the log-rank (Mantel–Cox) test, which compares the observed number of events in each group with the number expected if survival were the same, over the whole follow-up. Paste a group column and the tool reports \(\chi^2\), degrees of freedom and the P value, and for two groups the hazard ratio.

### Which confidence interval should I use for a Kaplan–Meier curve?

The log–log (also called exponential Greenwood) interval is generally preferred because it stays between 0 and 1 and behaves better with small numbers at risk; it is what Python’s lifelines uses and R offers as conf.type = "log-log". R’s survfit uses the log scale by default, so state which one you used.

### What does the number at risk table show?

For each time on the axis, how many subjects are still followed and event-free at that time. It tells readers how much data supports each part of the curve: the right-hand end, with few at risk, is the least certain.

### How is the hazard ratio calculated from a log-rank test?

With two groups, \(\mathrm{HR} = (O_1/E_1)/(O_2/E_2)\), the ratio of observed to expected events in each group, with a 95% interval from \(\mathrm{SE}[\ln \mathrm{HR}] = \sqrt{1/E_1 + 1/E_2}\). A Cox proportional-hazards model gives a similar estimate and handles covariates.
