我经常在GNU R/ggplot中绘制图形,用于与字节相关的一些测量.内置轴标签是普通数字或科学记数法,即1兆字节= 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;
Run Code Online (Sandbox Code Playgroud)
我想知道这个解决方案是否可以改进,因为我的每个图表都需要很多样板代码.
Ben*_*ker 27
我曾经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)
Run Code Online (Sandbox Code Playgroud)
加载包:
library("sitools")
library("ggplot2")
Run Code Online (Sandbox Code Playgroud)
创建情节:
(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]"))
Run Code Online (Sandbox Code Playgroud)
我不确定这与你的功能相比如何,但至少有其他人去编写它的麻烦......
我修改了你的代码风格 - 行末端的分号是无害的,但通常是MATLAB或C编码器的标志......
编辑:我最初定义了一个通用的格式化函数
si_format <- function(...) {
function(x) f2si(x,...)
}
Run Code Online (Sandbox Code Playgroud)
遵循(例如)的格式scales::comma_format,但在这种情况下似乎没有必要 - 只是ggplot2我不完全理解的更深层魔法的一部分.
OP的代码给出了我认为不正确的答案:最右边的轴刻度是"1000K"而不是"1M" - 这可以通过将>1e6测试更改为来修复>=1e6.另一方面,f2si使用小写k- 我不知道是否K需要(包装结果toupper()可以解决这个问题).
OP结果(si_vec):

我的结果(f2si):

更新:该软件包的最新版本scales包括打印可读标签的功能。
在这种情况下,label_bytes可以使用:
library(ggplot2)
library(scales)
bytes <- 2^seq(0,20) + rnorm(21, 4, 2)
my_data <- data.frame(
bytes=as.integer(bytes),
time=bytes / (1e4 + rnorm(21, 100, 3)) + 8
)
ggplot(data=my_data, aes(x=bytes, y=time)) +
geom_point() +
geom_line() +
scale_x_log10("Message Size [Byte]", labels=label_bytes()) +
scale_y_continuous("Round-Trip-Time [us]")
Run Code Online (Sandbox Code Playgroud)
或者,如果您更喜欢 IEC 单位(KiB = 2^10、MiB = 2 ^ 20、 ...),请指定labels=label_bytes(units = "auto_binary")。对于结果,请查看下面原始答案中的第二个图,因为结果非常相似。
原答案
对于字节来说,有gdata::humanReadable. humanReadable支持 SI 前缀(1000 字节 = 1 KB)以及IEC 定义的二进制前缀(1024 字节 = 1 KiB)。
该函数humanReadableLabs允许自定义参数并处理NA值:
humanReadableLabs <- function(...) {
function(x) {
sapply(x, function(val) {
if (is.na(val)) {
return("")
} else {
return(
humanReadable(val, ...)
)
}
})
}
}
Run Code Online (Sandbox Code Playgroud)
现在可以直接更改标签以使用 SI 前缀和“字节”作为单位:
library(ggplot2)
library(gdata)
bytes <- 2^seq(0,20) + rnorm(21, 4, 2)
my_data <- data.frame(
bytes=as.integer(bytes),
time=bytes / (1e4 + rnorm(21, 100, 3)) + 8
)
humanReadableLabs <- function(...) {...}
ggplot(data=my_data, aes(x=bytes, y=time)) +
geom_point() +
geom_line() +
scale_x_log10("Message Size [Byte]", labels=humanReadableLabs(standard="SI")) +
scale_y_continuous("Round-Trip-Time [us]")
Run Code Online (Sandbox Code Playgroud)
IEC 前缀通过省略 来绘制standard="SI"。请注意,还必须指定中断以获得清晰易读的值。
ggplot(data=my_data, aes(x=bytes, y=time)) +
geom_point() +
geom_line() +
scale_x_log10("Message Size [Byte]", labels=humanReadableLabs()) +
scale_y_continuous("Round-Trip-Time [us]")
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2204 次 |
| 最近记录: |