惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

TaoSecurity Blog
TaoSecurity Blog
Jina AI
Jina AI
雷峰网
雷峰网
月光博客
月光博客
The GitHub Blog
The GitHub Blog
WordPress大学
WordPress大学
B
Blog RSS Feed
美团技术团队
C
CXSECURITY Database RSS Feed - CXSecurity.com
小众软件
小众软件
Security Latest
Security Latest
Microsoft Azure Blog
Microsoft Azure Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
Cybersecurity and Infrastructure Security Agency CISA
Last Week in AI
Last Week in AI
A
Arctic Wolf
Latest news
Latest news
Attack and Defense Labs
Attack and Defense Labs
I
Intezer
F
Fortinet All Blogs
罗磊的独立博客
MongoDB | Blog
MongoDB | Blog
Webroot Blog
Webroot Blog
S
Secure Thoughts
Help Net Security
Help Net Security
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
V
Visual Studio Blog
P
Proofpoint News Feed
博客园 - 【当耐特】
P
Privacy International News Feed
V
Vulnerabilities – Threatpost
Stack Overflow Blog
Stack Overflow Blog
Know Your Adversary
Know Your Adversary
云风的 BLOG
云风的 BLOG
Hacker News: Ask HN
Hacker News: Ask HN
L
LINUX DO - 最新话题
H
Help Net Security
爱范儿
爱范儿
酷 壳 – CoolShell
酷 壳 – CoolShell
S
SegmentFault 最新的问题
Forbes - Security
Forbes - Security
T
Tailwind CSS Blog
量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tenable Blog
Cloudbric
Cloudbric
N
News and Events Feed by Topic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog

Homepage on Yihui Xie | 谢益辉

Bye, Stack Overflow - Yihui Xie | 谢益辉 Converting testthat Tests to testit - Yihui Xie | 谢益辉 Reflections on AI-assisted Programming - Yihui Xie | 谢益辉 Preliminary Support for Typst in knitr - Yihui Xie | 谢益辉 R.I.P., Tomas Kalibera - Yihui Xie | 谢益辉 An Introduction to xfun - Yihui Xie | 谢益辉 tinyimg: An R Package for Compressing Images - Yihui Xie | 谢益辉 The Surprising Slowness of `textConnection()` in R - Yihui Xie | 谢益辉 A CDN-backed CTAN Mirror: `tlnet.yihui.org` - Yihui Xie | 谢益辉 Announcing TinyTeX Binaries for arm64 and musl-based Linux - Yihui Xie | 谢益辉 TinyTeX on macOS: No More Messing with `/usr/local/bin` - Yihui Xie | 谢益辉 R.I.P., John Fox - Yihui Xie | 谢益辉 R.I.P., Fritz Leisch - Yihui Xie | 谢益辉 Bye, Hex Stickers - Yihui Xie | 谢益辉 Navigating CRAN's Reverse Dependency Check Logs - Yihui Xie | 谢益辉
Viewing Nested Lists with `xfun::tabset()` - Yihui Xie | 谢益辉
Yihui Xie · 2026-02-08 · via Homepage on Yihui Xie | 谢益辉

An interactive way to explore complex data structures in R and alternative to str()

2026-02-08

Complex nested lists in R can be difficult to explore and understand at a glance. The str() function is helpful for examining structure, but large nested lists can quickly become overwhelming.

While I was writing the documentation for tabsets in litedown, I almost laughed at myself for the support for nested tabsets, because I had no idea why anyone would want this feature. However, I suddenly realized that it can be a very useful tool for exploring nested lists in an interactive way, so I wrote a quick implementation: xfun::tabset().

Introduction

The xfun::tabset() function converts a (potentially nested) list into an interactive tabset representation in Markdown format. The tab titles are derived from the names of list members, and the tab content displays the values of those members. When a list member is itself a list, it is represented recursively with a child tabset, creating a hierarchical, interactive interface.

The hierarchy of tabs allows you to explore complex nested structures without being overwhelmed by a long str() output. Each level of nesting gets its own set of tabs, making it easy to navigate through the data. You only see one tab at a time, and you can click through to explore deeper levels of the structure as needed.

Usage

You can pass any object to xfun::tabset(), e.g., the penguins dataset:

xfun::tabset(penguins)

And it will display the structure of the dataset in a tabbed format like this:

  • species

     Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
    
  • island

     Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
    
  • bill_len

     num [1:344] 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
    
  • bill_dep

     num [1:344] 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
    
  • flipper_len

     int [1:344] 181 186 195 NA 193 190 181 195 193 190 ...
    
  • body_mass

     int [1:344] 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
    
  • sex

     Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
    
  • year

     int [1:344] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...
    
  • attr(*)

    • row.names

       int [1:344] 1 2 3 4 5 6 7 8 9 10 ...
      
    • class

       chr "data.frame"
      

Note that if the object has attributes, they will be displayed in the last tab titled attr(*) (e.g., names and classes).

By default, tabset() uses the str() function to display the structure of bottom-level elements. This gives you a concise summary of what each component contains. However, you can customize this display by passing a function to the second argument, e.g.,

# show the full content of each element instead of the structure
xfun::tabset(penguins, dput)

# show the default print output of each element
xfun::tabset(penguins, print)

The power of tabset() really shines when working with deeply nested structures. Consider a recorded plot object, which is the most complicated data structure I can think of in base R:1

plot(1:10)
p = recordPlot()
xfun::tabset(p)

Generalization

I didn’t spend much time on this function, but it definitely has the potential to be generalized to display richer content in the tabs, such as tables, images, or even interactive visualizations. As a quick example, we can use the following function to display numeric vectors as stem-and-leaf plots and factors as frequency tables:

xfun::tabset(penguins, function(x) {
  if (is.numeric(x)) stem(x) else {
    if (is.factor(x)) c(table(x)) else str(x)
  }
})

I’ll leave this as an exercise for readers who are interested in exploring the possibilities further. If you are curious about how xfun::tabset() is implemented, you can check out its source code, which is actually quite short.2

You may also need to read the documentation on tabsets in litedown to understand the Markdown/HTML structure of tabsets, which is the basis for this function.

Next time when you want to str(), you may consider giving xfun::tabset() a try.

Donate

As a freelancer (currently working as a contractor) and a dad of three kids, I truly appreciate your donation to support my writing and open-source software development! Your contribution helps me cope with financial uncertainty better, so I can spend more time on producing high-quality content and software. You can make a donation through methods below.

  • Venmo: @yihui_xie, or Zelle: [email protected]

  • Paypal

    • If you have a Paypal account, you can follow the link https://paypal.me/YihuiXie or find me on Paypal via my email [email protected]. Please choose the payment type as “Family and Friends” (instead of “Goods and Services”) to avoid extra fees.

    • If you don’t have Paypal, you may donate through this link via your debit or credit card. Paypal will charge a fee on my side.

  • Other ways:

    WeChat Pay (微信支付:谢益辉) Alipay (支付宝:谢益辉)
    WeChat Pay QR code Alipay QR code

When sending money, please be sure to add a note “gift” or “donation” if possible, so it won’t be treated as my taxable income but a genuine gift. Needless to say, donation is completely voluntary and I appreciate any amount you can give.

Please feel free to email me if you prefer a different way to give. Thank you very much!

I’ll give back a significant portion of the donations to the open-source community and charities. For the record, I received about $30,000 in total (before tax) in 2024-25, and gave back about $15,000 (after tax).