Ok so this is just a starting point that people could use to formulate a better answer to the question. It uses the packcircles package to (surprisingly) pack circles. It doesn't qualify all of your criteria, but can serve as a useful starting point. We're just going to pretend that the eruptions
column from the faithful dataset is your time variable.
library(packcircles)
#> Warning: package 'packcircles' was built under R version 4.0.2
library(ggplot2)
library(scales)
library(ggrepel)
# Setup some data, suppose we'd like to label 5 samples
set.seed(0)
faith2 <- faithful
faith2$label <- ""
faith2$label[sample(nrow(faith2), 5)] <- LETTERS[1:5]
# Initialise circle pack data
init <- data.frame(
x = faith2$eruptions,
y = runif(nrow(faith2)),
areas = rescale(faith2$waiting, to = c(0.01, 0.1))
)
# Use the repelling layout
res <- circleRepelLayout(
init,
xlim = range(init$x) + c(-1, 1),
ylim = c(0, Inf),
xysizecols = c(1, NA, 3),
sizetype = "radius",
weights = 0.1
)
# Prepare for ggplot2
df <- circleLayoutVertices(res$layout)
df <- cbind(df, faith2[df$id,])
This is showing that the circles are reasonably placed with respect to our fake time variable.
# Plot
ggplot(df, aes(x, y, group = id)) +
geom_polygon(aes(fill = eruptions,
colour = I(ifelse(nzchar(label), "black", NA)))) +
scale_fill_viridis_c() +
coord_equal()

And this is showing that the circle size is reasonably corresponding to a different variable.
ggplot(df, aes(x, y, group = id)) +
geom_polygon(aes(fill = waiting,
colour = I(ifelse(nzchar(label), "black", NA)))) +
scale_fill_viridis_c() +
coord_equal()

Created on 2020-07-11 by the reprex package (v0.3.0)
There are few flaws in this, notably it doesn't satisfy the 2nd criterion (circles aren't hugging the axis). Also, for reasons beyond my understanding, the packcircles layout couldn't place about 12% of datapoints, which are assigned NaN
in df
. Anyway, hopefully somebody smarter than me will do a better job at this.