在“菜单”中指定等宽字体

48

语言:R。问题:menu(..,graphics=T)函数中,我可以指定固定宽度字体吗?

解释:

最近我提出了这个问题,关于如何让用户交互式地选择数据框的一行:

df <- data.frame(a=c(9,10),b=c('hello','bananas'))
df.text <- apply( df, 1, paste, collapse=" | " )
menu(df.text,graphics=T)

enter image description here

我希望 | 对齐。目前它们没有对齐;很明显,我没有将列填充到相同的宽度。因此,我使用format使每一列都具有相同的宽度(稍后我会编写代码自动确定每列的宽度,但现在让我们忽略这个):

df.padded <- apply(df,2,format,width=8)
df.padded.text <- apply( df.padded, 1, paste, collapse=" | ")
menu( df.padded.text,graphics=T )

enter image description here

您看到它还是有点不对吗?但是,如果我查看 df.padded,我会得到:

> df.padded
     a            b           
[1,] " 9        " "hello     "
[2,] "10        " "bananas   "

因此,每个单元格肯定都填充到相同的长度。

这样做的原因可能是因为此默认字体(至少在我的系统Linux上)不是等宽字体。

因此,我的问题是: 我能否为menu(..,graphics=T)函数指定等宽字体?

更新

@RichieCotton注意到,如果您查看具有graphics=Tmenu,它会调用select.list,后者又会调用tcltk::tk_select.list

因此,看起来我必须修改tcltk选项。 来自@jverzani:

library(tcltk)
tcl("option", "add", "*Listbox.font", "courier 10")
menu(df.padded.text,graphics=T)

enter image description here

假设menu(...,graphics=T)graphics为TRUE时调用tcltk::tk_select.list,那么我猜这是一个可行的选项,因为任何能够显示图形menu的发行版都会有tcltk,因为它需要调用tk_select.list

(顺便说一句,我在文档中找不到任何提示尝试使用tcl('option','add',...),更不用说选项名是*Listbox.font了!)

另一个更新——仔细查看了select.listmenu代码后,发现在Windows上(或如果.Platform$GUI=='AQUA'——是Mac吗?),根本没有调用tcltk::tk_select.list,而只是一些内部代码。所以修改'*Listbox.font'不会影响这个。

我想我会:

  • 如果tcltk存在,加载它,将*Listbox.font设置为Courier,并显式地使用tcltk::tk_select.list
  • 如果不存在,尝试menu(...,graphics=T),至少可以获得一个图形界面(虽然不是等宽字体,但总比没有好)
  • 如果这也失败了,那就回退到menu(...,graphics=F),这肯定会起作用。

谢谢大家。


2
没有明显的选项。menu 调用 select.list,它会消失在外部代码中。你可能更有运气去修改 tcltk::tk_select.list - Richie Cotton
@RichieCotton 嗯,我想那可能是情况 :(. 我会研究 tcltk。你知道它是否在所有 R 发行版中都是标准的吗?我只想尽量减少用户需要安装的外部包数量(因为我已经有相当多了)。谢谢。 - mathematical.coffee
tcltk 在 Windows 上是标准的,但在 Linux 上不是(对于 OSX 不确定)。您可以使用 capabilities("tcltk") 测试支持情况。 - Richie Cotton
我的廉价解决方案似乎只是把问题转移了 :-( 。值得一提的是,我使用的是Ubuntu操作系统,R版本为2.13.1,capabilities("tcltk")的结果为TRUE。 - tim riffe
3
你可以通过选项命令来完成这个操作。类似于 library(tcltk); tcl("option", "add", "*Listbox.font", "times 16 bold ") 这样的代码可以实现。 - jverzani
显示剩余4条评论
2个回答

1

填充的另一种方法:

na.pad <- function(x,len){
    x[1:len]
}

makePaddedDataFrame <- function(l,...){
    maxlen <- max(sapply(l,length))
    data.frame(lapply(l,na.pad,len=maxlen),...)
}

x = c(rep("one",2))
y = c(rep("two",10))
z = c(rep("three",5))

makePaddedDataFrame(list(x=x,y=y,z=z))

na.pad() 函数利用了 R 会自动使用 NAs 填充向量的事实,如果您尝试索引不存在的元素。

makePaddedDataFrame() 只需找到最长的一个并将其余部分填充到匹配长度即可。


这将创建一个具有max(length(x), length(y), length(z))行的数据框,并对那些没有值的行、列使用NA,但我不确定它如何解决我的问题,即在menu(vectorOfDataFrame, graphics=T)中显示时,字体是等宽的或看起来是等宽的。 - mathematical.coffee

0

我不明白为什么你不想使用View(df)(获取行ID,将内容放入临时数据框并使用View命令显示)

编辑:好吧,只需使用sprintf命令

创建一个函数f来从数据框对象中提取字符串

f <- function(x,sep1) {
 sep1=format(sep1,width=8)
 xa<-gsub(" ","",as.character(x[1]))
 a1 <- nchar(xa)
 xa=format(xa,width=8)
 xb=gsub(" ","",as.character(x[2]))
 b1 <- nchar(xb)
 xb=format(xb,width=8)
 format1=paste("%-",10-a1,"s%s%-",20-b1,"s",sep="")
 concat=sprintf(format1,xa,sep1,xb)
 concat
 }

df <- data.frame(a=c(9,10),b=c('hello','bananas'))

df.text <- apply(df, 1, f, sep1="|")

menu(df.text,graphics=T)

当然,sprintf中使用的限制10、20是数据框列(a、b)中字符数的最大长度。您可以根据自己的数据更改它以反映出来。


除了那不是我的问题之外(我特别想在“menu”中使用等宽字体):请注意,“menu”和“View”函数在本质上是不同的,因为“menu”函数是用于选择项目(所以我可以说“选择一行”并返回索引/项目),而“View”函数仅用于查看 - mathematical.coffee
你考虑过使用sprintf命令吗?--请看我上面修改的编辑 - Subs
df$a变成三位数时(尝试data.frame(a=c(9,10,100),b=c('hello','bananas','x'))),这种方法就不起作用了,但你确实让我很好奇 - 在你的答案中,我注意到nchar(df.text)c(32,29) - 你怎么知道这些长度不相等的字符串会在第一个字符串的第10个字符和第二个字符串的第9个字符处对齐'|'呢? - mathematical.coffee
我又做了一些尝试,我认为你在我的问题中所放的例子df可能只是运气好而已——当列包含更一般的文本时,例如data.frame(a=c('green','eggs','wwww'),b=c('and','ham','lll')),这会因为非等宽字体而遇到麻烦,因为(例如)wl相比非常粗。我认为sprintf通常不能用于对齐data.frame列,除非字体也是等宽的,这就是我最初提出问题的原因。 - mathematical.coffee
它会对齐,尝试在 format1=paste("%-",10-a1,"s%s%-",20-b1,"s",sep="") 中的 sprintf 上使用更大的值,例如12。 (12-a1) 这些值需要根据您的字符长度进行更改。我选择了一个随机数10,但是一旦您确定了数据框中该列的最大长度,您可以确定大小。 - Subs
我知道。我曾经编写了一个版本,使用2 * maxWidth作为值,当第一列中只有数字,第二列中只有字母时,它的效果非常好,但是如果在变宽的非最后一列中放置字母(例如粗“w”与小“l”),除非字体是等宽字体或者您可以通过空格完美地补偿额外的宽度,否则就会遇到问题,这取决于字体。 - mathematical.coffee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接