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);
我想使用 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);