You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ggplot的facet_wrap对两个列表数据分面绘图?

问题描述

我有两个向量列表,一个存储188段旋律的半音数据,另一个存储每段旋律的时间线(以秒为单位)。希望用ggplot为每段旋律绘制图表,查看旋律随时间的变化趋势。用plot()绘制单个旋律正常,但不知道如何组织dataframe/tibble来实现分面绘图。

附上测试数据:

library(lubridate)

melodylist<-list(c(11L, 4L, 11L, 12L, 11L, 7L, 9L, 11L, NA, 11L, 12L, 14L, 12L, 
9L, 7L, 5L, 4L, 11L, 4L, 11L, 12L, 11L, 7L, 9L, 11L, NA, 11L, 
12L, 14L, 12L, 9L, 7L, 5L, 4L, NA, 9L, 7L, 12L, 11L, 9L, 14L, 
12L, 11L, 9L, NA, 12L, 11L, 12L, 14L, 7L, 11L, 12L, 9L, 7L, NA, 
7L, 12L, 11L, 9L, 4L, 7L, 5L, 4L),
c(9L, 7L, 9L, 12L, 14L, 12L, 11L, 9L, NA, 9L, 5L, 7L, 9L, 7L, 
5L, 4L, 2L, 9L, 7L, 9L, 12L, 14L, 12L, 11L, 9L, NA, 9L, 5L, 7L, 
9L, 7L, 5L, 4L, 2L, NA, 2L, 5L, 7L, 5L, 7L, 9L, NA, 9L, 14L, 
12L, 14L, 16L, 12L, 11L, 9L, NA, 9L, 12L, 9L, 12L, 7L, 5L, 2L, 
4L, 2L, 9L, 7L, 5L, 4L, 2L))

timelist<-list(new("Period", .Data = c(0, 2, 3, 4, 5, 6, 7, 8, 9, 9.5, 10, 11, 
12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 26.5, 
27, 28, 29, 30, 31, 32, 33, 34, 34.5, 35, 36, 37, 38, 38.5, 39.5, 
40, 41, 42, 42.5, 43, 44, 45, 46, 47, 47.5, 48, 49, 50, 50.5, 
51, 52, 53, 54, 55, 56, 57), year = c(0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), month = c(0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), day = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 
    hour = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0), minute = c(0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
new("Period", .Data = c(0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
13, 14, 14.5, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 
29, 30, 31, 32, 32.5, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 
43.5, 44, 45, 46, 47, 48, 49, 50, 51, 51.5, 52.5, 53.5, 54.5, 
55.5, 56.5, 57, 57.5, 58.5, 59.5, 0.5, 1, 1.5, 2.5), year = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0), month = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0), day = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), hour = c(0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), minute = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 
1)))

注:无需担心NA值,原本用humdrum格式输出为".",绘图时无问题。曾尝试将列表直接放入dataframe,但ggplot无法识别这种格式。

解决方案

要实现分面绘图,核心是把数据整理成**长格式(long format)**的dataframe,每一行对应一个时间点的音高数据,同时标记所属的旋律编号。

步骤1:加载必要的包

除了lubridate,还需要tidyverse(包含dplyr和ggplot2)来处理数据和绘图:

library(tidyverse)
library(lubridate)

步骤2:将列表转换为长格式数据框

使用map2_df同时遍历两个列表,将每段旋律的时间、音高和编号组合成统一的数据框:

# 遍历旋律和时间列表,生成带旋律编号的长格式数据
melody_data <- map2_df(melodylist, timelist, function(mel, time) {
  tibble(
    time = as.numeric(time),  # 将Period对象转换为数值型秒数
    pitch = mel
  )
}, .id = "melody_id")  # .id参数自动为每个旋律分配唯一标识

步骤3:用ggplot绘制分面图

使用facet_wrap()按旋律编号生成独立子图:

ggplot(melody_data, aes(x = time, y = pitch)) +
  geom_line() +  # 绘制旋律折线
  geom_point(na.rm = TRUE) +  # 标记每个音高点(忽略NA)
  facet_wrap(~melody_id, ncol = 4) +  # 按旋律分面,每行显示4个图表
  labs(x = "时间(秒)", y = "半音音高") +
  theme_bw()

关键说明

  • as.numeric(time):把lubridate的Period对象转换为数值型秒数,确保ggplot能识别为连续变量。
  • map2_df:来自purrr包,高效遍历两个配对列表并合并结果为数据框,替代手动循环。
  • facet_wrap(~melody_id):自动为每个旋律生成独立子图,ncol参数可调整每行显示的子图数量,适配188段旋律的展示需求。

内容的提问来源于stack exchange,提问作者IMIAD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 23:33:09