Префиксы SI в метках оси ggplot2

Я часто рисую графики в GNU R/ggplot для некоторых измерений, связанных с байтами. Ярлыки встроенных осей представляют собой либо простые числа, либо научную нотацию, то есть 1 мегабайт = 1е6. Вместо этого я хотел бы использовать префиксы 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;

Я хотел бы знать, можно ли улучшить это решение, поскольку для каждого графика требуется много кода шаблона.

Ответ 1

Я использовал 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...

edit. Сначала я определил общую функцию форматирования

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

следуя формату (например, scales::comma_format), но в этом случае это кажется ненужным - только часть более глубокой магии ggplot2, которую я не совсем понимаю.

Код OP дает то, что кажется мне не совсем правильным: самый правый тик оси - "1000K", а не "1M" - это можно исправить, изменив тест >1e6 на >=1e6. С другой стороны, f2si использует нижний регистр k - я не знаю, требуется ли k (обертка результатов в toupper() может исправить это).

Результаты OP (si_vec):

enter image description here

Мои результаты (f2si):

enter image description here