【问题标题】:Histogram with "negative" logarithmic scale in RR中具有“负”对数刻度的直方图
【发布时间】:2013-01-08 10:00:40
【问题描述】:

我有一个包含一些异常值的数据集,如下所示

x <- rnorm(1000,0,20)
x <- c(x, 500, -500)

如果我们将其绘制在线性 x 轴刻度上,我们会看到

histogram(x)

我用这个有用的线程想出了一个很好的方法来把它放在对数刻度上: how to use a log scale for y-axis of histogram in R?

mat <- data.frame(x)
ggplot(ee, aes(x = xx)) + geom_histogram(colour="darkblue", size=1, fill="blue") + scale_x_log10()

但是,我希望第二个示例中的 x 轴标签与第一个示例的 x 轴标签匹配,除了一种“负对数” - 即第一个刻度(从中心向左移动)可能是 -1 ,那么下一个可能是-10,下一个是-100,但都是等距的。这有意义吗?

【问题讨论】:

  • 我不明白你在问什么。您是否希望将图中的负面数据(目前被忽略)包含在某处?
  • 我不认为负面数据被忽略了,我相信它正在被绘制?但是 x 轴上的值被记录?
  • 当你记录一个负数的日志时,你认为你会得到什么......?
  • @JimBo:你看到的只是正面数据。虽然当您在粗略的直方图上查看它时,这些数据可能看起来很正常(或接近它),但您实际拥有的是反映对数正态数据 - 即两个独立的分布,一个正数和一个负数,即都是(非常粗略地)对数正态分布的。
  • NA - 所以我想我建议您记录负数的绝对值,然后将它们绘制在直方图上的对数刻度上。那有意义吗?作为“挤压”直方图的一种方式。

标签: r ggplot2 histogram


【解决方案1】:

我不确定我是否理解您的目标,但是当您想要一个类似对数的变换但有零或负值时,反双曲正弦变换asinh() 通常是一个不错的选择。对于大值,它类似于对数,并为所有实值定义。有关讨论、详细信息和其他选项,请参阅 Rob Hyndman's blogthis question on stats.stackexchange.com

如果这是一种可接受的方法,您可以为 ggplot 创建自定义比例。下面的代码演示了如何创建和使用自定义比例(带有自定义中断),以及 asinh() 转换的可视化。

library(ggplot2)
library(scales)

limits <- 100
step <- 0.005
demo <- data.frame(x=seq(from=-1*limits,to=limits,by=step))

asinh_trans <- function(){
  trans_new(name = 'asinh', transform = function(x) asinh(x), 
            inverse = function(x) sinh(x))
}

ggplot(demo,aes(x,x))+geom_point(size=2)+
     scale_y_continuous(trans = 'asinh',breaks=c(-100,-50,-10,-1,0,1,10,50,100))+
     theme_bw()

ggplot(demo,aes(x,x))+geom_point(size=2)+
     scale_x_continuous(trans = 'asinh',breaks=c(0,1,10,50,100))+
     scale_y_log10(breaks=c(0,1,10,50,100))+ # zero won't plot
     xlab("asinh() scale")+ylab("log10 scale")+
     theme_bw()

【讨论】:

  • 这看起来不错,我只需要考虑一下,确保 xaxis 在正确的位置!
  • 嗯 - 它似乎导致直方图中的“下降”在 0 附近。如果它有助于澄清我的问题,我正在寻找:类似于第一个直方图的东西,但引入了 xaxis -所以它绘制相同的数据,但不是 xaxis 标记是 -600 -400 -200 0 200 400 600,我希望标记类似于 -1000 -100 -10 -1 0 - 10 100 1000,与数字之间的距离相等。据我了解,这应该会导致直方图更加伸展,并引入异常值,但峰值会在 0 左右?虽然我可能错了。
  • 嗯 - 如果我执行 10^x 然后在对数刻度上绘制会怎么样 - 那么我只需要重新调整轴......这有意义吗?
  • 不,峰值不会在 0 左右。您会有所下降,因为您正在制作宽度不等的垃圾箱,并且较小的垃圾箱中的物品较少。即使您像我演示的那样使用 ifelse() 或其他逻辑测试对正值、零值和负值做不同的事情(即 -log(-x) 表示负值和 0 表示 0),制作自定义镜像对数刻度,你仍然会有一个有两个峰值的直方图。
  • 您可以在 ggplot 之外计算 bin 及其内容,可能使用 cut() 或 Hmisc 的 cut2() 并确保零附近的 bin 更宽,以便获得一个峰值。我认为您需要使用 geom_bar() 并明确传递 x、y 和宽度,而不是让 ggplot 计算。
【解决方案2】:

意识到这个问题已经相当老了,我决定还是回答它,因为我遇到了完全相同的问题。

我看到上面的一些答案误解了你原来的问题。我认为这是一个有效的可视化问题,我在下面概述了我的解决方案,希望对其他人也有用。

我的方法是使用 ggplot 并为 xy 轴(以及自定义中断生成器)创建自定义日志转换

library(ggplot2)
library(scales)

# Create custom log-style x axis transformer (...,-10,-3,-1,0,1,3,10,...)
custom_log_x_trans <- function()
  trans_new("custom_log_x",
            transform = function (x) ( sign(x)*log(abs(x)+1) ),
            inverse = function (y) ( sign(y)*( exp(abs(y))-1) ),
            domain = c(-Inf,Inf))

# Custom log x breaker (...,-10,-3,-1,0,1,3,10,...)
custom_x_breaks <- function(x)
{ 
  range <- max(abs(x), na.rm=TRUE)

  return (sort( c(0,
                  sapply(0:log10(range), function(z) (10^z) ),
                  sapply(0:log10(range/3), function(z) (3*10^z) ),
                  sapply(0:log10(range), function(z) (-10^z) ),
                  sapply(0:log10(range/3), function(z) (-3*10^z) )
  )))
}

# Create custom log-style y axis transformer (0,1,3,10,...)
custom_log_y_trans <- function()
  trans_new("custom_log_y",
            transform = function (x) ( log(abs(x)+1) ),
            inverse = function (y) ( exp(abs(y))-1 ),
            domain = c(0,Inf))

# Custom log y breaker (0,1,3,10,...)
custom_y_breaks <- function(x)
{ 
  max_y <- length(x)

  range <- max(abs(max_y), na.rm=TRUE)

  return (sort( c(0,
                  sapply(0:log10(range), function(z) (10^z) ),
                  sapply(0:log10(range/3), function(z) (3*10^z) )
  )))
}

ggplot(data=mat) +
  geom_histogram(aes(x=x,fill=..count..), 
                 binwidth = 1, color="black", size=0.1) +
  scale_fill_gradient("Count", low = "steelblue", high = "red") +
  coord_trans(x="custom_log_x",y="custom_log_y") +
  scale_x_continuous(breaks = custom_x_breaks(mat$x)) +
  scale_y_continuous(breaks = custom_y_breaks(mat$x)) +
  theme(axis.text.x=element_text(angle=90,hjust=1,vjust=0.5))  + 
  theme_bw()

这给了我以下情节。

注意:

  • 该图还包括着色方案,以直观地显示每个条的绝对值。
  • 随着x 的增加,箱子变得越来越薄(对数转换的副作用)

在任何一种情况下,两个异常值都清晰可见

【讨论】:

    【解决方案3】:

    我找到了一种作弊的方法。我说“作弊”,因为它实际上分别绘制了数据的负面和正面部分。因此,您无法比较负面和正面数据。但只能分别显示正负部分的分布。

    其中一个问题是,如果您的数据中有零值,它将不会显示在图中。

    reverselog_trans <- function(base = exp(1)) {
      trans <- function(x) -log(x, base)
      inv <- function(x) base^(-x)
      trans_new(paste0("reverselog-", format(base)), trans, inv, 
                log_breaks(base = base), 
                domain = c(1e-100, Inf))
    }
    
    quartz();
    
    
    dist1 <- ggplot(data=df.meltFUAC) +
      geom_point(alpha=1,aes(x=deltaU.deltaUltrasensitivity,y=deltaF.deltaFitness, 
                             colour=deltaF.w_c)) + 
      scale_x_continuous(name = expression(Delta * S[ult]), 
                         limits=c(1e-7,1),trans = "log10",breaks=c(1e-01,1e-03,1e-05),
                         labels=c("1e-01","1e-03","1e-05")) + 
      scale_y_continuous(name = expression(paste(Delta, " Fitness")),trans = "log10", 
                         limits = c(1e-7,1), breaks=c(1e-01,1e-03,1e-05),
                         labels=c("1e-01","1e-03","1e-05")) +
      theme_bw() +
      theme(legend.position = "none", axis.title.x=element_blank(),strip.background=element_blank(),
            panel.border=element_rect(colour = "black"),panel.grid.major=element_blank(),
            panel.grid.minor=element_blank(),plot.background=element_blank(),
            plot.margin=unit(c(0,0,0,-11),"mm"))
    
    dist2 <- ggplot(data=df.meltFUAC, aes(x=-deltaU.deltaUltrasensitivity,y=deltaF.deltaFitness, 
                                          colour=deltaF.w_c)) +
      geom_point(alpha=1) + 
      scale_x_continuous(name = expression(Delta * sqrt(S[ult] %.% S[amp])),limits=c(1,1e-7),
                         trans = reverselog_trans(10),breaks=c(1e-01,1e-03,1e-05),
                         labels=c("-1e-01","-1e-03","-1e-05")) +
      scale_y_continuous(name = expression(paste(Delta, " Fitness")),trans = "log10", 
                         limits = c(1e-7,1), breaks=c(1e-01,1e-03,1e-05),
                         labels=c("1e-01","1e-03","1e-05")) +
      theme_bw() +
      theme(legend.position = "none",strip.background=element_blank(),panel.border=element_rect(colour = "black"),
            axis.text.y=element_blank(), axis.ticks.y=element_blank(), axis.title.y=element_blank(),
            axis.line.y=element_line(colour="black",size=1,linetype="solid"),axis.title.x=element_blank(),
            panel.grid.major=element_blank(),panel.grid.minor=element_blank(),plot.background=element_blank(),
            plot.margin=unit(c(0,-8,0,2.5),"mm"))
    
    hist0 <- ggplot(data=df.meltFUAC, aes(deltaF.deltaFitness,fill=deltaF.w_c)) +
      #geom_histogram(alpha = 0.5, aes(y=..density..),position = 'identity') +
      geom_density(alpha = 0.5, aes(colour=deltaF.w_c)) +
      scale_x_continuous(name = expression(paste(Delta, " Fitness")), 
                         limits=c(1e-7,1),trans = "log10",breaks=c(1e-01,1e-03,1e-05),
                         labels=c("1e-01","1e-03","1e-05")) + 
      scale_y_continuous(name = "Density", limits=c(0,0.6)) + 
      theme_bw() +
      theme(legend.position = "none", axis.title.x=element_blank(),strip.background=element_blank(),
            axis.text.y=element_blank(), axis.ticks.y=element_blank(), axis.title.y=element_blank(),
            axis.text.x=element_blank(), axis.ticks.x=element_blank(), axis.title.x=element_blank(),
            panel.border=element_rect(colour = "black"),panel.grid.major=element_blank(),
            panel.grid.minor=element_blank(),plot.background=element_blank(),
            plot.margin=unit(c(0,5,2.5,-2.5),"mm")) +
      coord_flip()
    
    hist1 <- ggplot(data=df.meltFUAC, aes(deltaU.deltaUltrasensitivity,fill=deltaF.w_c)) +
      #geom_histogram(alpha = 0.5, aes(y=..density..),position = 'identity') +
      geom_density(alpha = 0.5, aes(colour=deltaF.w_c)) +
      scale_x_continuous(name = expression(Delta * S[ult]), 
                         limits=c(1e-7,1),trans = "log10",breaks=c(1e-01,1e-03,1e-05),
                         labels=c("1e-01","1e-03","1e-05")) + 
      scale_y_continuous(name = "Density", limits=c(0,0.6)) + 
      theme_bw() +
      theme(legend.position = "none", axis.title.x=element_blank(),strip.background=element_blank(),
            axis.text.y=element_blank(), axis.ticks.y=element_blank(), axis.title.y=element_blank(),
            axis.text.x=element_blank(), axis.ticks.x=element_blank(), axis.title.x=element_blank(),
            axis.line.x=element_line(colour="black",size=1,linetype="solid"),
            panel.border=element_rect(colour = "black"),panel.grid.major=element_blank(),
            panel.grid.minor=element_blank(),plot.background=element_blank(),
            plot.margin=unit(c(5,0,-2.5,2),"mm"))
    
    hist2 <- ggplot(data=df.meltFUAC, aes(-deltaU.deltaUltrasensitivity,fill=deltaF.w_c)) +
      #geom_histogram(alpha = 0.5, aes(y=..density..),position = 'identity') +
      geom_density(alpha = 0.5, aes(colour=deltaF.w_c)) +
      scale_x_continuous(name = expression(Delta * S[ult]),limits=c(1,1e-7),
                         trans = reverselog_trans(10),breaks=c(1e-01,1e-03,1e-05),
                         labels=c("-1e-01","-1e-03","-1e-05")) +
      scale_y_continuous(name = "Density", limits=c(0,0.6)) + 
      theme_bw() +
      theme(legend.position = "none",strip.background=element_blank(),panel.border=element_rect(colour = "black"),
            axis.text.y=element_blank(), axis.ticks.y=element_blank(), axis.title.y=element_blank(),
            axis.text.x=element_blank(), axis.ticks.x=element_blank(), axis.title.x=element_blank(),
            axis.line.y=element_line(colour="black",size=1,linetype="solid"),
            axis.line.x=element_line(colour="black",size=1,linetype="solid"),
            panel.grid.major=element_blank(),panel.grid.minor=element_blank(),plot.background=element_blank(),
            plot.margin=unit(c(5,-8,-2.5,2.5),"mm"))
    
    
    
    grid.newpage();
    pushViewport(viewport(layout = grid.layout(3, 3, widths = unit(c(4,4,2),"null"),
                                               heights=unit(c(2,7.5,0.5),"null"))));
    vplayout <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y);
    
    print(dist2, vp = vplayout(2, 1));
    print(dist1, vp = vplayout(2, 2));
    print(hist2, vp = vplayout(1, 1));
    print(hist1, vp = vplayout(1, 2));
    print(hist0, vp = vplayout(2, 3));
    grid.text(expression(Delta * Ultrasensitivity),vp = vplayout(3,1:2),x = unit(0.55, "npc"), 
              y = unit(0.9, "npc"),gp=gpar(fontsize=12, col="black"));
    
    dev.copy2pdf(file=sprintf("%s/_dist/dist_hist_deltaF_deltaU_wc_01vs10.pdf", resultDir));
    dev.off();
    

    这是它得到的图表(但您需要手动放置图例):

    或者更简单的:

    reverselog_trans <- function(base = exp(1)) {
      trans <- function(x) -log(x, base)
      inv <- function(x) base^(-x)
      trans_new(paste0("reverselog-", format(base)), trans, inv, 
                log_breaks(base = base), 
                domain = c(1e-100, Inf))
    }
    
    quartz();
    
    hist1 <- ggplot(deltaF, aes(deltaFitness,fill=w_c)) + guides(fill=guide_legend(title=expression(omega[c]))) + geom_histogram(alpha = 0.5, aes(y=..density..),position = 'identity') + geom_density(alpha = 0.05, aes(colour=w_c)) + scale_x_continuous(name = expression(paste(Delta, " Fitness")),trans = "log10");
    hist1 <- hist1 + scale_y_continuous(name = "Density", limits=c(0,1));
    #hist1 <- hist1 + theme(panel.background=element_blank(),panel.border=element_blank(),axis.line.x=element_blank(),axis.line.y=element_line(colour="black",linetype="solid",size=1),axis.title.x=element_blank(),panel.grid.major=element_blank(),panel.grid.minor=element_blank(),plot.background=element_blank(),plot.margin=unit(c(5,5,0,5),"mm"));
    hist1 <- hist1 + theme_bw();
    hist1 <- hist1 + theme(strip.background=element_blank(),panel.border=element_rect(colour = "black"),axis.title.x=element_blank(),panel.grid.major=element_blank(),panel.grid.minor=element_blank(),plot.background=element_blank(),plot.margin=unit(c(5,5,0,5),"mm"));
    hist1 <- hist1 + scale_color_discrete(name=expression(omega[c]));# + geom_vline(xintercept=0, colour="grey", size = 1);# + geom_hline(yintercept=0, colour="grey", size = 0.5);
    
    hist2 <- ggplot(deltaU, aes(deltaUltrasensitivity,fill=w_c)) + geom_histogram(alpha = 0.5, aes(y=..density..),position = 'identity') + geom_density(alpha = 0.05, aes(colour=w_c))  + scale_x_continuous(name = expression(paste(Delta, " Ultrasensitivity")), limits=c(1e-7,1),trans = "log10",breaks=c(1e-01,1e-03,1e-05),labels=c("1e-01","1e-03","1e-05"));
    hist2 <- hist2 + scale_y_continuous(name = "Density",limits=c(0,1)) ;#+ geom_vline(xintercept=0, colour="grey", size = 1);# + geom_hline(yintercept=0, colour="grey", size = 0.5);
    #hist2 <- hist2 + theme(legend.position = "none", axis.title.x=element_blank(),panel.background=element_blank(),panel.border=element_blank(),panel.grid.major=element_blank(),panel.grid.minor=element_blank(),plot.background=element_blank(),plot.margin=unit(c(0,5,0,-7.5),"mm"));
    hist2 <- hist2 + theme_bw();
    hist2 <- hist2 + theme(legend.position = "none", axis.title.x=element_blank(),strip.background=element_blank(),panel.border=element_rect(colour = "black"),panel.grid.major=element_blank(),panel.grid.minor=element_blank(),plot.background=element_blank(),plot.margin=unit(c(0,5,0,-7.5),"mm"));
    # + ggtitle("Positive part")
    
    hist3 <- ggplot(deltaU, aes(-deltaUltrasensitivity,fill=w_c)) + geom_histogram(alpha = 0.5, aes(y=..density..),position = 'identity') + geom_density(alpha = 0.05, aes(colour=w_c)) + scale_x_continuous(name = expression(paste(Delta, " Ultrasensitivity")), limits=c(1,1e-7),trans = reverselog_trans(10),breaks=c(1e-01,1e-03,1e-05),labels=c("-1e-01","-1e-03","-1e-05"));
    hist3 <- hist3 + scale_y_continuous(name = "Density", limits=c(0,1));# + geom_hline(yintercept=0, colour="black", size = 0.5);
    #hist3 <- hist3 + theme(legend.position = "none",panel.background=element_blank(),axis.text.y=element_blank(), axis.ticks.y=element_blank(), axis.title.y=element_blank(),axis.line.y=element_line(colour="black",size=1,linetype="solid"),axis.title.x=element_blank(),panel.grid.major=element_blank(),panel.grid.minor=element_blank(),plot.background=element_blank(),plot.margin=unit(c(0,-7.5,0,5),"mm"));
    hist3 <- hist3 + theme_bw();
    hist3 <- hist3 + theme(legend.position = "none",strip.background=element_blank(),panel.border=element_rect(colour = "black"),axis.text.y=element_blank(), axis.ticks.y=element_blank(), axis.title.y=element_blank(),axis.line.y=element_line(colour="black",size=1,linetype="solid"),axis.title.x=element_blank(),panel.grid.major=element_blank(),panel.grid.minor=element_blank(),plot.background=element_blank(),plot.margin=unit(c(0,-7.5,0,5),"mm"));
    # + ggtitle("Negative part")
    
    grid.newpage();
    pushViewport(viewport(layout = grid.layout(4, 2, widths = unit(c(5,5),"null"),heights=unit(c(4.6,0.4,4.6,0.4),"null"))));
    vplayout <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y);
    print(hist1, vp = vplayout(1, 1:2));  # key is to define vplayout
    grid.text(expression(paste(Delta, " Fitness")),vp = vplayout(2,1:2),x = unit(0.5, "npc"), y = unit(0.9, "npc"),gp=gpar(fontsize=12, col="black"));
    print(hist3, vp = vplayout(3, 1));
    print(hist2, vp = vplayout(3, 2));
    grid.text(expression(paste(Delta, " Ultrasensitivity")),vp = vplayout(4,1:2),x = unit(0.5, "npc"), y = unit(0.9, "npc"),gp=gpar(fontsize=12, col="black"));
    
    
    dev.copy2pdf(file=sprintf("%s/deltaF_deltaU_wc_01vs10.pdf", resultDir));
    dev.off();
    

    这是我得到的图表:

    【讨论】:

    • w_c 我想用你的颜色是什么颜色?
    • @aliocee 我刚刚使用了 ggplot。当您为两个数据选择颜色时,它会自动生成这样不同的颜色。您可以通过引用来模拟此调色板:stackoverflow.com/questions/8197559/…
    【解决方案4】:

    为什么要使用 ggplot2 解决方案?您的第一个绘图是使用 lattice histogram 函数完成的,这就是您应该停留的地方。只需在histogram 函数中直接应用对数变换,使用nint 参数指定直方图箱的数量,并使用type 参数在“计数”或“密度”之间进行选择。我认为你在那里得到了你需要的一切,但也许我错过了你问题的一些关键细节......

    library(lattice)
    histogram(log10(x), nint=50, type="count")
    

    【讨论】:

    • 问题是,数据应该在 0 左右达到峰值,通过 log10 你会丢失所有的负数据。我想要的是类似于第一个直方图的东西,但是轴在对数刻度上,负数和正数(我知道这可能没有意义......)基本上我想要这样一个刻度的轴,这样你就可以看到异常值(+500/-500),但您也可以更好地看到 0 附近的分布。这在我的脑海中是有道理的,但它似乎会引起混乱,所以我所说的很可能没有意义!
    猜你喜欢
    • 1970-01-01
    • 2021-12-01
    • 2010-11-17
    • 2011-12-16
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多