Copy and paste this code to run the demo:
using Pkg
Pkg.activate(temp=true)
Pkg.add(["CensoredDistributions", "Distributions", "UnicodePlots"])
include(download("https://gist.github.com/seabbs/3cbd4e5bcdba30deec3081ba3838d556/raw/censoreddistributions-demo-gist.jl"))
=== CensoredDistributions.jl Demo ===
This package extends Distributions.jl to support censored distributions
commonly needed in epidemiological applications.
Starting with a LogNormal(1.5, 0.75) distribution
This could represent, for example, an incubation period distribution.
Primary event censoring window: Uniform(0, 7)
This represents uncertainty in when the initial event (e.g., exposure) occurred.
1. TRUE DISTRIBUTION (no censoring)
This is our baseline - the actual underlying distribution
2. PRIMARY CENSORING + TRUNCATION
Primary censoring accounts for uncertainty in the timing of the initial event
Truncation removes unobserved values (e.g., delays > 10 days)
Created: primary_censored(LogNormal, Uniform(0,7)) truncated at 10
3. WITHIN INTERVAL CENSORING
Interval censoring accounts for discrete observation windows
E.g., symptoms reported to the nearest day rather than exact time
Created: interval_censored(LogNormal, 1.0) - observations rounded to nearest day
4. DOUBLE INTERVAL CENSORING
Combines primary event uncertainty + interval censoring + truncation
This is the most realistic scenario for epidemiological data
Created: double_interval_censored with all effects combined
=== CUMULATIVE DISTRIBUTION FUNCTION COMPARISON ===
CDFs show the probability of observing a value ≤ x
CDF Comparison:
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Censoring Comparison⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
┌────────────────────────────────────────────────────────────────────────────────┐
0.9 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⢀⣴⣋⣀⣀⣀⣀⣀⣸│ True
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠉⠉⠉⠉⠉⠉⠉⠉⠀⠀⠀⠀⠀⣠⣞⣹⠤⠴⠒⠒⠋⠉⠉⠁│ Primary + Truncated
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⢀⣀⡤⠤⠖⠒⡫⠟⠁⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀│ Within Interval [1,10]
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠉⠉⠉⠉⠉⠉⠉⢉⣠⠤⠖⠒⠉⠉⠀⠀⢀⡴⠋⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀│ Double Censored
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠤⠤⠤⠤⠤⠤⣤⠼⠖⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠔⠋⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⣀⡤⠒⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣸⠖⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣞⣁⣀⣀⣀⣀⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠤⠤⠤⢤⡤⠾⠭⠼⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⢻⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢀⡤⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠔⠋⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⢾⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠞⠁⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡴⠋⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⢴⠛⠒⠒⠒⠒⠒⠒⠚⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠒⣲⠞⠓⠒⠒⠒⠚⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠚⠁⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⠖⠉⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠔⠋⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⢶⠛⠒⠒⠒⠒⠒⠒⠚⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠖⠋⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⡶⠚⠓⠒⠒⠒⠒⠚⠀⠀⠀⠀⠀⠀⠀⣀⠴⠾⠭⠤⠤⠤⠤⠼⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠖⢻⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⠤⠒⠋⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
│⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠴⠋⠁⠀⢸⠀⠀⠀⠀⠀⣀⣠⢤⠶⠾⠭⠤⠤⠤⠤⠼⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
0 │⣀⣀⣀⣀⣀⣀⣤⣤⣒⣛⣓⣒⣒⣒⣶⣾⠤⠶⠶⠯⠭⠥⠤⠼⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
└────────────────────────────────────────────────────────────────────────────────┘
⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀10⠀
=== SAMPLING FROM CENSORED DISTRIBUTIONS ===
Generating 1000 samples from each distribution to show their shapes
Drawing 1000 samples from each distribution...
✓ True distribution samples generated
✓ Primary censored + truncated samples generated
✓ Within interval censored samples generated
✓ Double interval censored samples generated
=== HISTOGRAM COMPARISON ===
Histograms show how censoring affects the observed distribution shape
True Distribution:
This is what we would observe with perfect measurement
True LogNormal
┌ ┐
[ 0.0, 5.0) ┤███████████████████████████████████ 559
[ 5.0, 10.0) ┤████████████████████▎ 305
[10.0, 15.0) ┤█████▊ 94
[15.0, 20.0) ┤█▍ 22
[20.0, 25.0) ┤▌ 9
[25.0, 30.0) ┤▍ 5
[30.0, 35.0) ┤▎ 3
[35.0, 40.0) ┤▏ 1
[40.0, 45.0) ┤ 0
[45.0, 50.0) ┤▏ 1
[50.0, 55.0) ┤ 0
[55.0, 60.0) ┤▏ 1
└ ┘
Frequency
Primary Censoring + Truncated:
Notice how primary event uncertainty shifts the distribution
Primary Censored + Truncated [0,10]
┌ ┐
[ 0.0, 1.0) ┤▎ 1
[ 1.0, 2.0) ┤████▋ 21
[ 2.0, 3.0) ┤████████████▎ 55
[ 3.0, 4.0) ┤██████████████████▍ 83
[ 4.0, 5.0) ┤█████████████████████▊ 99
[ 5.0, 6.0) ┤███████████████████████████████████ 159
[ 6.0, 7.0) ┤█████████████████████████████████▎ 151
[ 7.0, 8.0) ┤█████████████████████████████▌ 134
[ 8.0, 9.0) ┤█████████████████████████████████▋ 153
[ 9.0, 10.0) ┤███████████████████████████████▋ 144
└ ┘
Frequency
Within Interval Censoring:
Interval censoring creates a 'discretised' version of the continuous distribution
Within Interval [1,10]
┌ ┐
[ 0.0, 1.0) ┤███████▋ 40
[ 1.0, 2.0) ┤██████████████████████████▏ 137
[ 2.0, 3.0) ┤███████████████████████████████████ 184
[ 3.0, 4.0) ┤████████████████████████████████▊ 173
[ 4.0, 5.0) ┤████████████████████████▎ 127
[ 5.0, 6.0) ┤███████████████▏ 79
[ 6.0, 7.0) ┤█████████████▌ 71
[ 7.0, 8.0) ┤██████████████▋ 77
[ 8.0, 9.0) ┤████████▌ 45
[ 9.0, 10.0) ┤██████▌ 34
[10.0, 11.0) ┤██████▍ 33
└ ┘
Frequency
Double Interval Censored:
This combines all censoring effects - most realistic for real epidemiological data
Double Censored (primary + truncation + interval)
┌ ┐
[ 0.0, 1.0) ┤▎ 1
[ 1.0, 2.0) ┤██▎ 11
[ 2.0, 3.0) ┤███████████▊ 61
[ 3.0, 4.0) ┤███████████████▉ 82
[ 4.0, 5.0) ┤██████████████████████▌ 116
[ 5.0, 6.0) ┤██████████████████████████▍ 135
[ 6.0, 7.0) ┤███████████████████████████████▎ 160
[ 7.0, 8.0) ┤███████████████████████████████████ 180
[ 8.0, 9.0) ┤██████████████████████████████▎ 155
[ 9.0, 10.0) ┤███████████████████▍ 99
└ ┘
Frequency
=== SUMMARY ===
CensoredDistributions.jl enables:
• Primary event censoring (uncertainty in initial event timing)
• Interval censoring (discrete observation windows)
• Truncation (removing unobserved values)
• Combinations of all censoring types
• Full integration with Distributions.jl API (pdf, cdf, rand, etc.)
• Efficient analytical solutions where possible
This is essential for realistic epidemiological modelling!
- Primary censoring shifts the distribution later due to uncertain event timing
- Interval censoring discretises continuous distributions to match observation windows
- Double censoring combines both effects for realistic epidemiological modelling
- UnicodePlots provides terminal-based visualisation perfect for Julia REPL exploration
Perfect for understanding how censoring affects your epidemiological models!