我经常在GNU R / ggplot中绘制图形以进行一些与字节有关的测量。内置的轴标签可以是纯数字或科学计数法,即1 MB = 1e6。我想使用SI前缀(Kilo = 1e3,Mega = 1e6,Giga = 1e9等),即轴应标记为1.5K,5K,1M,150M,4G等。

我目前使用以下代码:

si_num <- function (x) {

  if (!is.na(x)) {
    if (x > 1e6) {
      chrs <- strsplit(format(x, scientific=12), split="")[[1]];
      rem <- chrs[seq(1,length(chrs)-6)];
      rem <- append(rem, "M");
    }

    else if (x > 1e3) {
      chrs <- strsplit(format(x, scientific=12), split="")[[1]];
      rem <- chrs[seq(1,length(chrs)-3)];
      rem <- append(rem, "K");
    }
    else {
      return(x);
    }

    return(paste(rem, sep="", collapse=""));
  }
  else return(NA);
}

si_vec <- function(x) {
  sapply(x, FUN=si_num);
}

library("ggplot2");

bytes=2^seq(0,20) + rnorm(21, 4, 2);
time=bytes/(1e4 + rnorm(21, 100, 3)) + 8;

my_data = data.frame(time, bytes);

p <- ggplot(data=my_data, aes(x=bytes, y=time)) +
     geom_point() +
     geom_line() +
     scale_x_log10("Message Size [Byte]", labels=si_vec) +
     scale_y_continuous("Round-Trip-Time [us]");
p;


我想知道这种解决方案是否可以改进,因为我的解决方案在每个图中都需要大量样板代码。

最佳答案

我使用library("sos"); findFn("{SI prefix}")查找sitools软件包。

构造数据:

bytes <- 2^seq(0,20) + rnorm(21, 4, 2)
time <- bytes/(1e4 + rnorm(21, 100, 3)) + 8
my_data <- data.frame(time, bytes)


加载包:

library("sitools")
library("ggplot2")


创建图:

(p <- ggplot(data=my_data, aes(x=bytes, y=time)) +
     geom_point() +
     geom_line() +
     scale_x_log10("Message Size [Byte]", labels=f2si) +
     scale_y_continuous("Round-Trip-Time [us]"))


我不确定这与您的功能相比如何,但至少有人在编写它时遇到了麻烦……

我稍微修改了您的代码样式-行尾的分号无害,但通常是MATLAB或C编码器的标志...

编辑:我最初定义了通用格式设置功能

si_format <- function(...) {
    function(x) f2si(x,...)
}


遵循(例如)scales::comma_format的格式,但是在这种情况下似乎没有必要-只是我不完全理解的更深层次的ggplot2魔术的一部分。

OP的代码给我提供了一个不太正确的答案:最右边的轴刻度是“ 1000K”而不是“ 1M”-可以通过将>1e6测试更改为>=1e6来解决。另一方面,f2si使用小写的k-我不知道是否需要K(将结果包装在toupper()中可以解决此问题)。

OP结果(si_vec):



我的结果(f2si):

关于r - ggplot2轴标签中的SI前缀,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13973644/

10-12 20:19