如何用ggplot2创建可嵌入Shiny的渐变色彩温度计图表?
用ggplot2实现可嵌入Shiny的温度计图表
核心实现思路
温度计可拆解为几个核心元素:带圆角的矩形主体、底部水银球、渐变填充的水银区域、刻度标签,以及可选的图标装饰。需用到这些包:ggplot2(基础绘图)、ggforce(圆角图形)、scales(颜色渐变处理)、ggtext(渲染图标/富文本)。
基础温度计代码(单图版)
以下代码实现包含圆角、渐变、图标功能的静态温度计:
library(ggplot2) library(ggforce) library(scales) library(ggtext) # 自定义渐变函数:基于主色生成浅→深的渐变,保持渐变逻辑一致 create_gradient <- function(main_color) { colorRampPalette(c(alpha(main_color, 0.3), main_color))(100) } # 模拟数据:填充高度对应75%刻度(0-100区间) temp_data <- data.frame(fill_height = 75) # 绘制温度计 ggplot(temp_data) + # 1. 温度计外框:圆角矩形+底部圆形 geom_rounded_rect(aes(xmin = 0.4, xmax = 0.6, ymin = 0, ymax = 100), radius = unit(5, "pt"), color = "gray50", fill = "white") + geom_circle(aes(x0 = 0.5, y0 = 0, r = 0.1), color = "gray50", fill = "white") + # 2. 渐变填充的水银区域 geom_rounded_rect(aes(xmin = 0.42, xmax = 0.58, ymin = 0, ymax = fill_height), radius = unit(3, "pt"), fill = gradient_n_pal(create_gradient("#2196F3"))(seq(0,1,length.out=100))) + geom_circle(aes(x0 = 0.5, y0 = 0, r = 0.09), fill = gradient_n_pal(create_gradient("#2196F3"))(1)) + # 3. 刻度线与标签 geom_segment(aes(x = 0.62, xend = 0.65, y = seq(0,100,20), yend = seq(0,100,20)), color = "gray50") + geom_text(aes(x = 0.7, y = seq(0,100,20), label = seq(0,100,20)), color = "gray50", size = 3) + # 4. 添加Font Awesome温度计图标 geom_richtext(aes(x = 0.5, y = 110, label = "<i style='color:#2196F3;'></i>"), size = 8, fill = NA, label.color = NA) + # 5. 调整坐标与主题 coord_cartesian(xlim = c(0, 1), ylim = c(-5, 115), expand = FALSE) + theme_void() + theme(plot.margin = margin(10, 10, 10, 10))
关键细节说明
- 圆角边缘:用
ggforce::geom_rounded_rect实现矩形圆角,geom_circle绘制底部水银球,通过radius参数控制圆角/圆形大小。 - 渐变色彩:
create_gradient函数基于输入主色生成浅到深的渐变,确保无论用户选择什么颜色,渐变方向和逻辑保持一致。 - 图标搭配:通过
ggtext::geom_richtext渲染Font Awesome图标,若图标不显示,需确保系统安装对应字体,或替换为普通文本标签。
Shiny整合示例
以下是支持用户自定义颜色和温度值的Shiny应用:
library(shiny) library(ggplot2) library(ggforce) library(scales) library(ggtext) create_gradient <- function(main_color) { colorRampPalette(c(alpha(main_color, 0.3), main_color))(100) } ui <- fluidPage( titlePanel("温度计Shiny演示"), sidebarLayout( sidebarPanel( colorInput("temp_color", "选择温度计颜色", value = "#2196F3"), sliderInput("temp_value", "温度值", min = 0, max = 100, value = 75) ), mainPanel( plotOutput("thermometer_plot") ) ) ) server <- function(input, output) { output$thermometer_plot <- renderPlot({ temp_data <- data.frame(fill_height = input$temp_value) ggplot(temp_data) + geom_rounded_rect(aes(xmin = 0.4, xmax = 0.6, ymin = 0, ymax = 100), radius = unit(5, "pt"), color = "gray50", fill = "white") + geom_circle(aes(x0 = 0.5, y0 = 0, r = 0.1), color = "gray50", fill = "white") + geom_rounded_rect(aes(xmin = 0.42, xmax = 0.58, ymin = 0, ymax = fill_height), radius = unit(3, "pt"), fill = gradient_n_pal(create_gradient(input$temp_color))(seq(0,1,length.out=100))) + geom_circle(aes(x0 = 0.5, y0 = 0, r = 0.09), fill = gradient_n_pal(create_gradient(input$temp_color))(1)) + geom_segment(aes(x = 0.62, xend = 0.65, y = seq(0,100,20), yend = seq(0,100,20)), color = "gray50") + geom_text(aes(x = 0.7, y = seq(0,100,20), label = seq(0,100,20)), color = "gray50", size = 3) + geom_richtext(aes(x = 0.5, y = 110, label = paste0("<i style='color:", input$temp_color, ";'></i>")), size = 8, fill = NA, label.color = NA) + coord_cartesian(xlim = c(0, 1), ylim = c(-5, 115), expand = FALSE) + theme_void() + theme(plot.margin = margin(10, 10, 10, 10)) }, height = 400, width = 300) } shinyApp(ui, server)
内容的提问来源于stack exchange,提问作者Ainhoa
相关产品推荐
相关产品推荐

