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

发布于 2025-01-03 02:56:40 字数 2397 浏览 0 评论 0原文

语言: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)

在此处输入图像描述

我希望 | 对齐。他们现在不这样做;公平地说,我没有将列填充到相同的宽度。因此,我使用 format 使每一列具有相同的宽度(稍后我将编写代码来自动确定每列的宽度,但现在让我们忽略它):

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

在此处输入图像描述

看看它怎么仍然不稳定?然而,如果我查看 df.padded ,我会得到:

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

所以每个单元格肯定都被填充到相同的长度。

这样做的原因可能是因为它的默认字体(无论如何,在我的系统上,Linux)不是固定宽度的。

所以我的问题是: 我可以为 menu(..,graphics=T) 函数指定固定宽度字体吗?

更新

@RichieCotton 注意到,如果您查看 menu对于graphics=T,它会调用select.list,而select.list又会调用tcltk::tk_select.list

所以看起来我必须为此修改 tcltk 选项。来自 @jverzani:

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

在此处输入图像描述

鉴于 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),这肯定会起作用。

谢谢大家。

Language: R. Question: Can I specify fixed width font for the menu(..,graphics=T) function?

Explanation:

I recently asked this question on how to have a user select a row of a data frame interactively:

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

I'd like the | to line up. They don't at the moment; fair enough, I haven't padded out the columns to the same width. So I use format to get every column to the same width (later I'll write code to automagically determine the width per column, but let's ignore that for now):

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

See how it's still wonky? Yet, if I look at df.padded, I get:

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

So each cell is definitely padded out to the same length.

The reason for this is probably because the default font for this (on my system anyway, Linux) is not fixed width.

So my question is:
Can I specify fixed width font for the menu(..,graphics=T) function?

Update

@RichieCotton noticed that if you look at menu with graphics=T it calls select.list, which in turn calls tcltk::tk_select.list.

So it looks like I'll have to modify tcltk options for this. From @jverzani:

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

enter image description here

Given that menu(...,graphics=T) calls tcltk::tk_select.list when graphics is TRUE, my guess is that this is a viable option, as any distro that would be capable of displaying the graphical menu in the first place would also have tcltk on it, since it needs to call tk_select.list.

(As an aside, I can't find anything in the documentation that would give me the hint to try tcl('option','add',...), let alone that the option was called *Listbox.font!)

Another update -- had a closer look at the select.list and menu code, and it turns out on Windows (or if .Platform$GUI=='AQUA' -- is that Mac?), the tcltk::tk_select.list isn't called at all, and it's just some internal code instead. So modifying '*Listbox.font' won't affect this.

I guess I'll just:

  • if tcltk is there, load it, set the *Listbox.font to courier, and use tcltk::tk_select.list explicitly
  • if it isn't there, try menu(...,graphics=T) to at least get a graphical interface (which won't be monospace, but is better than nothing)
  • if that fails too, then just fallback to menu(...,graphics=F), which will definitely work.

Thanks all.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

千纸鹤带着心事 2025-01-10 02:56:40

另一种填充方法:

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 将自动用 NA 填充向量。

makePaddedDataFrame() 只是找到最长的一个并将其余的填充到匹配的长度。

Another approach to padding:

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))

The na.pad() function exploits the fact that R will automatically pad a vector with NAs if you try to index non-existent elements.

makePaddedDataFrame() just finds the longest one and pads the rest up to a matching length.

我一直都在从未离去 2025-01-10 02:56:40

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

编辑:好吧,只需使用 sprintf command

创建一个函数 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 中使用的限制是最大的length 为数据帧列 (a,b) 中的字符数。您可以更改它以根据您的数据反映它。

I don't understand why you don't want to use View(df) (get the rowid, put the contents into temp. data frame and display it with the View command)

Edit: well, just use sprintf command

Create a function f to extract the strings from the data frame object

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)

Of course the limits used in sprintf 10, 20 are maximum length for the number of characters in the data-frame column (a,b). You can change it to reflect it according to your data.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文