R 中具有两个 y 轴的累积图

Cumulative Diagrams in R with two y-axes

我想使用 R 从给定的向量和一个频率向量中绘制以下累积图。我该怎么做以及如何添加第二个 y 轴?

我尝试了 hist() 和 barplot() 但没有成功...

(实际上向量要大得多并且包含很多不同的数字...)

## store the data
df <- data.frame(value=c(10,10,20,20,30), freq=c(1,0.5,0.5,0.5,1) );
df;
##   value freq
## 1    10  1.0
## 2    10  0.5
## 3    20  0.5
## 4    20  0.5
## 5    30  1.0

## compute floor cutoffs; use one above top floor
floors <- floor(min(df$value)/10):ceiling(max(df$value)/10+1)*10;
floors;
## [1] 10 20 30 40

## compute which floor cutoff applies to each value
df$floor <- floors[apply(outer(df$value,floors,`-`),1,function(x) which.min(ifelse(x>=0,x,NA)))];
df;
##   value freq floor
## 1    10  1.0    10
## 2    10  0.5    10
## 3    20  0.5    20
## 4    20  0.5    20
## 5    30  1.0    30

## aggregate the floor frequencies
df2 <- transform(merge(data.frame(floor=floors),aggregate(freq~floor,df,sum),all.x=T),freq=ifelse(is.na(freq),0,freq));
df2;
##   floor freq
## 1    10  1.5
## 2    20  1.0
## 3    30  1.0
## 4    40  0.0

## compute the cumulative frequencies for each floor; must be careful to invert the floor order for greater-than-or-equal logic
df2 <- df2[order(df2$floor,decreasing=T),];
df2$cumfreq <- cumsum(df2$freq);
df2;
##   floor freq cumfreq
## 4    40  0.0     0.0
## 3    30  1.0     1.0
## 2    20  1.0     2.0
## 1    10  1.5     3.5

## order by floor ascending to prepare for plotting
df2 <- df2[order(df2$floor),];
df2;
##   floor freq cumfreq
## 1    10  1.5     3.5
## 2    20  1.0     2.0
## 3    30  1.0     1.0
## 4    40  0.0     0.0

## precompute ticks; use one xtick above max floor, although we won't label it
xtick <- c(floors,max(floors)+10);
xtick;
## [1] 10 20 30 40 50
ytick1 <- 0:floor(max(df2$cumfreq));
ytick1;
## [1] 0 1 2 3
ytick2 <- seq(0,max(df2$cumfreq),len=3);
ytick2;
## [1] 0.00 1.75 3.50

## global params
par(xaxs='i',yaxs='i',mar=c(5,5,3,5)+0.1);

## draw the plot and axes
plot(NA,xlim=c(min(xtick),max(xtick)),ylim=c(min(c(ytick1,ytick2)),max(c(ytick1,ytick2))),axes=F,xlab='',ylab='');
rect(df2$floor,0,df2$floor+10,df2$cumfreq,border=NA,col='blue')
axis(1,xtick,c(paste0('≥',df2$floor),NA),pos=0);
axis(2,ytick1);
axis(4,ytick2,paste0(ytick2/max(df2$cumfreq)*100,'%'),las=1);