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

如何在自组织映射(SOM)的每个单元内绘制折线图?

在六边形SOM单元内嵌入谱线图的实现方案

我明白你现在的困境——自己画了SOM的六边形网格,但不知道怎么把每个神经元的谱线图塞进去。其实核心是在基础绘图的每个六边形区域内创建子绘图窗口,下面给你一步步的提示和代码修改方案:

核心思路

每个六边形都有自己的坐标范围,我们需要在绘制完六边形后,定位到这个范围内部,然后绘制对应的谱线数据。这里推荐用grid包的视口(viewport)方案,它比纯基础绘图更灵活,不容易搞乱绘图参数。

步骤1:提前计算全局谱线范围(关键)

为了让所有神经元的谱线图比例一致,方便对比,先计算所有编码数据的y轴范围:

y_range <- range(som_obj$codes)

步骤2:修改循环,在每个六边形内添加谱线图

我们可以利用grid和gridBase包实现基础绘图与网格视口的结合,精准控制子图位置。修改你的plotCluster函数如下:

library(grid)
library(gridBase)

plotCluster <- function(som_obj, cutree.obj , col_palette){
 if (som_obj$grid$topo != "hexagonal"){
 stop("function assumes hexagonal SOM")
 }
 # 提前计算谱线的全局y范围,保证所有子图比例一致
 y_range <- range(som_obj$codes)
 n_vars <- ncol(som_obj$codes)
 
 Hexagon <- function (x, y, unitcell = 1, col = "grey", border=NA) {
 polygon(c(x, x, x + unitcell/2, x + unitcell, x + unitcell, x + unitcell/2), 
         c(y + unitcell * 0.125, y + unitcell * 0.875, y + unitcell * 1.125, 
           y + unitcell * 0.875, y + unitcell * 0.125, y - unitcell * 0.125), 
         col = col, border=border)
 }
 
 # 初始化基础绘图
 plot(0, 0, type = "n", axes = FALSE, 
      xlim=c(0, som_obj$grid$xdim), ylim=c(0, som_obj$grid$ydim), 
      xlab="", ylab= "", asp=1, main= "Clusters with Spectra")
 
 if(!is.null(col_palette)){
 ColorCode = col_palette[cutree.obj]
 } else{
 ColorCode <- as.factor(cutree.obj)
 }
 
 offset <- 0.5 #offset for the hexagons when moving up a row
 ind <- 1
 unitcell <- 1
 
 for (row in 1:som_obj$grid$ydim) {
 for (column in 0:(som_obj$grid$xdim - 1)) {
   # 绘制六边形
   Hexagon(column + offset, row - 1, col = ColorCode[ind])
   
   # ---------- 新增:绘制内部谱线图 ----------
   # 计算当前六边形的中心坐标与子图尺寸(留边距避免贴边框)
   x_center <- column + offset + unitcell/2
   y_center <- (row - 1) + unitcell*0.5
   x_width <- unitcell * 0.8
   y_height <- unitcell * 0.9
   
   # 创建网格视口,定位到当前六边形中心
   pushViewport(viewport(x = x_center, y = y_center,
                         width = x_width, height = y_height,
                         just = c("center", "center")))
   
   # 切换到基础绘图的视口环境
   vps <- baseViewports()
   pushViewport(vps$inner, vps$figure, vps$plot)
   
   # 绘制谱线:隐藏坐标轴、边框,用全局y范围统一比例
   par(mar = c(0, 0, 0, 0), bg = NA)
   plot(1:n_vars, som_obj$codes[ind, ], type = "l", 
        axes = FALSE, xlab = "", ylab = "",
        xlim = c(1, n_vars), ylim = y_range,
        col = "black", lwd = 1)
   
   # 弹出嵌套的视口,回到全局绘图环境
   popViewport(3)
   popViewport()
   # ----------------------------------------
   
   ind <- ind +1
 }
 offset <- ifelse(offset == 0.5, 0, 0.5) # 修正原offset判断逻辑,保证六边形交错排列
 }
}

关键细节解释

  1. 全局y范围:y_range确保所有谱线图的纵轴刻度一致,不会因为单个神经元的数据导致比例失调,方便对比不同神经元的谱线趋势。
  2. 视口定位:viewport的坐标参数对应六边形中心,设置子图尺寸时留边距,避免谱线贴到六边形边框影响美观。
  3. 参数重置:par(mar = c(0,0,0,0))去掉子图的边距,bg = NA保证子图背景透明,不覆盖六边形的聚类颜色。
  4. offset修正:原代码的offset <- ifelse(offset, 0, 0.5)逻辑有问题,改成判断是否等于0.5,才能正确实现六边形的交错排列。

替代方案:纯基础绘图实现

如果不想依赖grid包,也可以用par(new=TRUE)在当前画布上叠加子图,核心是计算六边形边界后设置新的绘图窗口:

# 在绘制完Hexagon后添加:
x_min <- column + offset
x_max <- column + offset + unitcell
y_min <- (row -1) - unitcell*0.125
y_max <- (row -1) + unitcell*1.125

old_par <- par(no.readonly = TRUE)
on.exit(par(old_par))
par(new = TRUE)
plot.window(xlim = c(x_min, x_max), ylim = c(y_min, y_max), asp = 1)
# 把谱线的x轴映射到六边形的x范围
x_vals <- seq(x_min, x_max, length.out = n_vars)
lines(x_vals, som_obj$codes[ind, ], col = "black", lwd = 1)
par(new = FALSE)

这种方法代码更简单,但容易因为绘图参数叠加出现问题(比如坐标轴残留),所以更推荐grid的视口方案。

内容的提问来源于stack exchange,提问作者Olorin.G

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:51:02