# How to visualize an evolution of a distribution in time?

Suppose you have a record of distribution for each day in some period. For example, some distribution which depends on a parameter which evolves over time. Suppose we have dozens or hundreds of days. How would you visualize the change of this distribution? I want the plot to contain as much info as possible.

One way I could think of is: proxy the density function and plot these curves's evolution in 2D. It will be some form of homotopy: the initial distribution converging to the final with some smooth step. Of course here I assume smoothness.

The question is theoretical in nature but I am aiming for python realization so implementations or suggestions for libraries are also welcome.

EDIT Didn't see it was a python question. I think the idea stands, but not sure if python implementation readily available.

You might want to look into so called ridge-plots using R package ggridges (and gganimate for animation). Below is an example (obviously doesn't have to be an animation):

Code is available in this gist.

Always think about the nature of your situation: Who will be the audience for this plot? What are my goals for it? What are my data?

You state that you have a "distribution which depends on a parameter which evolves over time". If your audience is fairly sophisticated, and this is a known, studied distribution (e.g., a Weibull), then you could estimate the changing parameter for each day, plot it on a scatterplot, and smooth it with something simple like a LOWESS line.

Here's an example. These are coded in R, but they are intended to be easy to follow by people who don't use R, and should be possible to translate to Python.

library(fitdistrplus)      # we'll use this package
set.seed(9234)             # this makes the example exactly reproducible

day = rep(1:16, each=100)  # 1 through 16, each repeated 100x
y   = c()                  # an empty vector to hold the data
for(i in 1:16){            # generates data from Weibull distributions w/ the
y = c(y,                 #  shape parameter increasing (but decelerating) by day
rweibull(n=100, shape=(.5 + .1*i - .002*(i^2)), scale=1))
}
# estimate Weibull shape & scale parameters by MLE for each day
d = t(sapply(split(y, day), function(x){ fitdist(x, distr="weibull")$$estimate })) d = data.frame(day=1:16, d) d # day shape scale # 1 1 0.6311143 0.9871380 # 2 2 0.7501392 1.0168905 # 3 3 0.7510426 0.8853516 # 4 4 0.8142484 0.8701132 # 5 5 0.9081937 1.1098466 # 6 6 0.9679144 1.0668120 # 7 7 1.0347746 1.0638731 # 8 8 1.1496184 0.9775989 # 9 9 1.1724681 1.0758072 # 10 10 1.2396152 0.9975250 # 11 11 1.2519313 0.8847656 # 12 12 1.4648643 1.0801915 # 13 13 1.3258313 0.9113326 # 14 14 1.4301392 0.9699252 # 15 15 1.5494493 1.0448072 # 16 16 1.5989056 1.0133831 windows() plot(shape~day, d) lines(lowess(d$$day, d\$shape), col="red")


If the data weren't from a known distribution, you could plot multiple lines tracing fixed quantiles over time.

dq = t(sapply(split(y, day), function(x){ quantile(x, probs=c(0.25, 0.5, 0.75, 0.95)) }))
dq = data.frame(day=1:16, dq)
names(dq) = c("day", "25%", "50%", "75%", "95%")
dq
#    day       25%       50%      75%
# 1    1 0.1447001 0.5212207 1.628061
# 2    2 0.2318992 0.6657878 1.394435
# 3    3 0.1868559 0.5122787 1.618891
# 4    4 0.1665822 0.6402280 1.259112
# 5    5 0.3038764 0.6778831 1.418966
# 6    6 0.2508331 0.7469482 1.447055
# 7    7 0.2759569 0.7411599 1.527585
# 8    8 0.2774774 0.7496496 1.421123
# 9    9 0.3630679 0.9203537 1.343523
# 10  10 0.3788195 0.6613015 1.263599
# 11  11 0.3514467 0.6411170 1.110531
# 12  12 0.4697239 0.8562416 1.253663
# 13  13 0.3281270 0.6732758 1.113507
# 14  14 0.4498140 0.7440592 1.143489
# 15  15 0.4391240 0.8440031 1.371128
# 16  16 0.4726235 0.8386493 1.210914
windows()
plot(1,1, xlim=c(1,16), ylim=c(0, 7), xlab="day", ylab="value", type="n")
lines(dq$$day, dq$$25%, col="red",    lty=2)
lines(dq$$day, dq$$50%, col="black",  lty=1)
lines(dq$$day, dq$$75%, col="blue",   lty=3)
lines(dq$$day, dq$$95%, col="purple", lty=4)
legend("topright", legend=c("95%", "75%", "50%", "25%"), lty=c(4,3,1,2),
col=c("purple", "blue", "black", "red"))


If your audience won't be as sophisticated, and wouldn't know what a "Weibull" is or be thrown off by trying to follow the idea of the "75th percentile", and you want something with more pizzazz, make a panel of kernel density plots. (Admittedly, adibender's plot has more pizzazz than this.)

windows()
par(mfrow=c(4,4))
for(i in 1:16){
plot(density(y[day==i]), main=paste("day", i), xlab="", xlim=range(y),
ylim=c(0, .8), ylab="", axes=FALSE);  box()
}


Assuming you have an empirical distribution for each day, as for example a store looking at total payment by each customer, per day. You can look upon this as a time series of histograms, and that could be plotted in various ways, maybe by a series of boxplots. If you have some example data we could try various options!