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

求助:如何在ggplot2中实现自定义半填充圆形形状?

问题:在ggplot2中实现半填充圆形数据标记

数据集包含shape列,取值为0、1、2、3,对应四种数据标记需求:

  • 0:仅显示轮廓的空心圆
  • 1:左半部分填充的圆形
  • 2:右半部分填充的圆形
  • 3:完全填充的圆形

R内置形状代码无半填充圆形选项,尝试用grid包自定义形状函数后,在ggplot2中调用时出现错误:自定义形状无法显示,且对应数据行被移除,需寻求有效实现方法。


用户尝试的自定义形状代码

library(grid)

# Define custom point shapes
half_filled_left <- function(size) {
  polygonGrob(x = c(-0.5, 0.5, 0.5, -0.5), 
              y = c(-0.5, -0.5, 0.5, 0.5),
              gp = gpar(col = "black", fill = "yellow"))
  arc <- seq(0, pi, length.out = 100)
  linesGrob(x = cos(arc) * 0.5, 
            y = sin(arc) * 0.5, 
            gp = gpar(col = "black", lwd = size / 5))
}

half_filled_right <- function(size) {
  polygonGrob(x = c(-0.5, 0.5, 0.5, -0.5), 
              y = c(-0.5, -0.5, 0.5, 0.5), 
              gp = gpar(col = "black", fill = "red"))
  arc <- seq(pi, 2*pi, length.out = 100)
  linesGrob(x = cos(arc) * 0.5, 
            y = sin(arc) * 0.5, 
            gp = gpar(col = "black", lwd = size / 5))
}

用户尝试的ggplot2代码

newdata_small %>%
  ggplot(aes(x=as.numeric(F6_GR),
             y=emmean,
             shape=shape)) + #shape = condition 
  geom_errorbar(aes(ymin=emmean-SE, 
                    ymax=emmean+SE), 
                width=.2, position = pd) +
  geom_line(position = pd)+
  geom_point(position = pd, size=5) +
  theme_classic() +
  ggtitle("Small Populations \n")+
  scale_shape_manual(name= "Heat Waves",
                     labels=c("No heat waves", "Initial heat wave only",
                              "Final heat wave only ", "Initial & final heat wave"), 
                     values = c("0" = 1,  # Circle outline  only
                                "1" = half_filled_left(5),  # Half filled circle left side
                                "2" = half_filled_right(5),  # Half filled circle right side
                                "3" = 16))   # Default filled circle

有效解决方案

方法一:使用ggpmisc包的geom_custom()自定义形状

scale_shape_manual仅支持整数/字符类型的内置形状代码,无法直接传入grob对象。通过ggpmisc::geom_custom()可以渲染自定义grob图形,步骤如下:

  1. 加载依赖包
library(ggplot2)
library(grid)
library(ggpmisc)
library(dplyr)
  1. 重写自定义形状函数,返回组合后的grobTree对象
# 左半填充圆形
half_filled_left <- function(x, y, size, colour = "black", fill = "yellow") {
  # 填充左半区域的矩形
  poly_grob <- polygonGrob(
    x = x + c(-0.5, 0, 0, -0.5) * size / 5,
    y = y + c(-0.5, -0.5, 0.5, 0.5) * size / 5,
    gp = gpar(col = colour, fill = fill, lwd = size / 5)
  )
  # 圆形上半轮廓弧
  arc_grob <- linesGrob(
    x = x + cos(seq(0, pi, length.out = 100)) * size / 10,
    y = y + sin(seq(0, pi, length.out = 100)) * size / 10,
    gp = gpar(col = colour, lwd = size / 5)
  )
  # 组合所有图形元素
  grobTree(poly_grob, arc_grob)
}

# 右半填充圆形
half_filled_right <- function(x, y, size, colour = "black", fill = "red") {
  poly_grob <- polygonGrob(
    x = x + c(0, 0.5, 0.5, 0) * size / 5,
    y = y + c(-0.5, -0.5, 0.5, 0.5) * size / 5,
    gp = gpar(col = colour, fill = fill, lwd = size / 5)
  )
  arc_grob <- linesGrob(
    x = x + cos(seq(pi, 2*pi, length.out = 100)) * size / 10,
    y = y + sin(seq(pi, 2*pi, length.out = 100)) * size / 10,
    gp = gpar(col = colour, lwd = size / 5)
  )
  grobTree(poly_grob, arc_grob)
}
  1. 分图层添加不同形状的点并配置图例
# 基础图层
p <- newdata_small %>%
  ggplot(aes(x = as.numeric(F6_GR), y = emmean)) +
  geom_errorbar(aes(ymin = emmean - SE, ymax = emmean + SE), 
                width = .2, position = pd) +
  geom_line(position = pd) +
  theme_classic() +
  ggtitle("Small Populations \n")

# 添加各类型点
p <- p + 
  # 空心圆(shape=0)
  geom_point(data = filter(newdata_small, shape == 0), 
             position = pd, size = 5, shape = 1, color = "black") +
  # 左半填充圆(shape=1)
  geom_custom(data = filter(newdata_small, shape == 1),
              aes(x = as.numeric(F6_GR), y = emmean),
              grob_fun = half_filled_left, size = 5,
              position = pd) +
  # 右半填充圆(shape=2)
  geom_custom(data = filter(newdata_small, shape == 2),
              aes(x = as.numeric(F6_GR), y = emmean),
              grob_fun = half_filled_right, size = 5,
              position = pd) +
  # 完全填充圆(shape=3)
  geom_point(data = filter(newdata_small, shape == 3), 
             position = pd, size = 5, shape = 16, color = "black")

# 手动配置图例
p <- p + scale_color_manual(
  name = "Heat Waves",
  labels = c("No heat waves", "Initial heat wave only",
             "Final heat wave only ", "Initial & final heat wave"),
  values = rep("black", 4)
) +
  guides(color = guide_legend(override.aes = list(
    shape = c(1, NA, NA, 16),
    fill = c(NA, "yellow", "red", NA),
    grob = list(NULL, half_filled_left(0,0,5), half_filled_right(0,0,5), NULL)
  )))

print(p)

方法二:使用ggsymbol包快速实现(更简便)

ggsymbol包内置了半填充圆形等特殊形状,无需自定义grob:

  1. 加载依赖包
library(ggplot2)
library(ggsymbol)
library(dplyr)
  1. 直接调用geom_symbol()绘图
newdata_small %>%
  ggplot(aes(x = as.numeric(F6_GR), y = emmean, symbol = factor(shape))) +
  geom_errorbar(aes(ymin = emmean - SE, ymax = emmean + SE), 
                width = .2, position = pd) +
  geom_line(position = pd) +
  geom_symbol(position = pd, size = 5, 
              aes(fill = factor(shape)), color = "black") +
  theme_classic() +
  ggtitle("Small Populations \n") +
  scale_symbol_manual(
    name = "Heat Waves",
    labels = c("No heat waves", "Initial heat wave only",
               "Final heat wave only ", "Initial & final heat wave"),
    values = c("circle-open", "circle-half-left", "circle-half-right", "circle-filled")
  ) +
  scale_fill_manual(
    name = "Heat Waves",
    labels = c("No heat waves", "Initial heat wave only",
               "Final heat wave only ", "Initial & final heat wave"),
    values = c(NA, "yellow", "red", "black")
  )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 00:24:55