Plotly气泡图制作教程
1. 环境准备和包加载
# 加载必要的包
library(plotly)
library(dplyr)
library(RColorBrewer)
library(scales)
library(htmlwidgets)
library(purrr)
# 设置中文字体(如果需要)
# Sys.setlocale("LC_ALL", "Chinese")
2. 数据生成
我们将创建多个数据集来演示不同类型的气泡图:
# 设置随机种子以确保结果可重现
set.seed(123)
# 数据集1: 国家经济发展数据
countries_data <- data.frame(
country = c("中国", "美国", "日本", "德国", "英国", "法国", "印度", "意大利",
"巴西", "加拿大", "俄罗斯", "韩国", "澳大利亚", "西班牙", "墨西哥",
"印度尼西亚", "荷兰", "沙特阿拉伯", "土耳其", "瑞士"),
gdp_per_capita = c(12556, 65298, 39048, 53259, 42330, 41464, 2099, 34260,
8897, 46195, 11289, 34980, 51812, 29565, 9946,
4256, 56383, 23139, 9127, 81867),
life_expectancy = c(76.9, 78.9, 84.6, 81.3, 81.3, 82.7, 69.7, 83.5,
75.9, 82.4, 72.6, 83.0, 83.4, 83.6, 75.0,
71.7, 82.3, 75.1, 77.7, 83.8),
population = c(1439323776, 331002651, 126476461, 83783942, 67886011, 65273511,
1380004385, 60461826, 212559417, 37742154, 145934462, 51269185,
25499884, 46754778, 128932753, 273523615, 17134872, 34813871,
84339067, 8654622),
continent = c("亚洲", "北美洲", "亚洲", "欧洲", "欧洲", "欧洲", "亚洲", "欧洲",
"南美洲", "北美洲", "欧洲", "亚洲", "大洋洲", "欧洲", "北美洲",
"亚洲", "欧洲", "亚洲", "欧洲", "欧洲"),
happiness_score = c(5.124, 6.951, 5.871, 7.076, 7.064, 6.592, 4.015, 6.387,
6.376, 7.278, 5.546, 5.838, 7.284, 6.491, 6.317,
5.240, 7.449, 6.406, 5.132, 7.560)
) %>%
mutate(
# 将人口转换为百万为单位,便于可视化
population_millions = population / 1000000,
# 创建GDP分类
gdp_category = case_when(
gdp_per_capita >= 50000 ~ "高收入",
gdp_per_capita >= 20000 ~ "中高收入",
gdp_per_capita >= 5000 ~ "中等收入",
TRUE ~ "低收入"
)
)
# 数据集2: 公司业绩数据
companies_data <- data.frame(
company = paste0("公司", LETTERS[1:25]),
revenue = rnorm(25, 500, 200),
profit_margin = rnorm(25, 15, 8),
employees = sample(100:5000, 25),
industry = sample(c("科技", "金融", "制造", "零售", "医疗"), 25, replace = TRUE),
market_cap = rnorm(25, 1000, 500),
risk_score = runif(25, 1, 10)
) %>%
mutate(
revenue = pmax(revenue, 50), # 确保收入为正
profit_margin = pmax(profit_margin, -5), # 利润率最低-5%
market_cap = pmax(market_cap, 100), # 确保市值为正
performance = case_when(
profit_margin >= 20 ~ "优秀",
profit_margin >= 10 ~ "良好",
profit_margin >= 0 ~ "一般",
TRUE ~ "较差"
)
)
# 数据集3: 产品销售数据
products_data <- data.frame(
product = paste0("产品", 1:30),
price = runif(30, 10, 500),
sales_volume = sample(100:10000, 30),
customer_rating = runif(30, 2, 5),
category = sample(c("电子产品", "服装", "家居", "食品", "运动"), 30, replace = TRUE)
) %>%
mutate(
revenue = price * sales_volume,
profit_per_unit = price * runif(30, 0.1, 0.4),
satisfaction_level = case_when(
customer_rating >= 4.5 ~ "非常满意",
customer_rating >= 4.0 ~ "满意",
customer_rating >= 3.5 ~ "一般",
TRUE ~ "不满意"
)
)
# 显示数据概览
head(countries_data)
## country gdp_per_capita life_expectancy population continent happiness_score
## 1 中国 12556 76.9 1439323776 亚洲 5.124
## 2 美国 65298 78.9 331002651 北美洲 6.951
## 3 日本 39048 84.6 126476461 亚洲 5.871
## 4 德国 53259 81.3 83783942 欧洲 7.076
## 5 英国 42330 81.3 67886011 欧洲 7.064
## 6 法国 41464 82.7 65273511 欧洲 6.592
## population_millions gdp_category
## 1 1439.32378 中等收入
## 2 331.00265 高收入
## 3 126.47646 中高收入
## 4 83.78394 高收入
## 5 67.88601 中高收入
## 6 65.27351 中高收入
3. 基础气泡图
3.1 简单气泡图
# 创建基础气泡图
basic_bubble <- plot_ly(
data = countries_data,
x = ~gdp_per_capita,
y = ~life_expectancy,
size = ~population_millions,
text = ~country,
type = 'scatter',
mode = 'markers',
hovertemplate = paste(
'<b>%{text}</b><br>',
'GDP per capita: $%{x:,.0f}<br>',
'Life expectancy: %{y:.1f} years<br>',
'Population: %{marker.size:.1f}M<br>',
'<extra></extra>'
)
) %>%
layout(
title = list(text = "世界各国GDP、预期寿命与人口关系", font = list(size = 16)),
xaxis = list(title = "人均GDP (美元)"),
yaxis = list(title = "预期寿命 (年)"),
showlegend = FALSE
)
basic_bubble
4. 高级气泡图 - 颜色控制
4.1 按分类变量着色
# 按大洲着色的气泡图
continent_bubble <- plot_ly(
data = countries_data,
x = ~gdp_per_capita,
y = ~life_expectancy,
size = ~population_millions,
color = ~continent,
colors = RColorBrewer::brewer.pal(6, "Set3"),
text = ~country,
type = 'scatter',
mode = 'markers',
marker = list(
sizemode = 'diameter',
sizeref = 2.0 * max(countries_data$population_millions) / (40^2),
line = list(width = 2, color = 'rgba(255, 255, 255, 0.8)')
),
hovertemplate = paste(
'<b>%{text}</b><br>',
'GDP per capita: $%{x:,.0f}<br>',
'Life expectancy: %{y:.1f} years<br>',
'Population: %{marker.size:.1f}M<br>',
'Continent: %{marker.color}<br>',
'<extra></extra>'
)
) %>%
layout(
title = list(text = "按大洲分类的气泡图", font = list(size = 16)),
xaxis = list(title = "人均GDP (美元)", type = "log"),
yaxis = list(title = "预期寿命 (年)"),
legend = list(title = list(text = "大洲"))
)
continent_bubble
4.2 按连续变量着色
# 按幸福指数着色的气泡图
happiness_bubble <- plot_ly(
data = countries_data,
x = ~gdp_per_capita,
y = ~life_expectancy,
size = ~population_millions,
color = ~happiness_score,
colors = colorRamp(c("red", "yellow", "green")),
text = ~country,
type = 'scatter',
mode = 'markers',
marker = list(
sizemode = 'diameter',
sizeref = 2.0 * max(countries_data$population_millions) / (40^2),
line = list(width = 1.5, color = 'rgba(0, 0, 0, 0.3)'),
colorbar = list(title = "幸福指数")
),
hovertemplate = paste(
'<b>%{text}</b><br>',
'GDP per capita: $%{x:,.0f}<br>',
'Life expectancy: %{y:.1f} years<br>',
'Population: %{marker.size:.1f}M<br>',
'Happiness Score: %{marker.color:.2f}<br>',
'<extra></extra>'
)
) %>%
layout(
title = list(text = "按幸福指数着色的气泡图", font = list(size = 16)),
xaxis = list(title = "人均GDP (美元)"),
yaxis = list(title = "预期寿命 (年)")
)
happiness_bubble
5. 大小控制和自定义
5.1 自定义气泡大小
# 公司数据的气泡图 - 自定义大小控制
company_bubble <- plot_ly(
data = companies_data,
x = ~revenue,
y = ~profit_margin,
size = ~employees,
color = ~industry,
colors = viridis::viridis(5),
text = ~company,
type = 'scatter',
mode = 'markers',
marker = list(
sizemode = 'diameter',
sizeref = 2.0 * max(companies_data$employees) / (50^2),
sizemin = 4,
line = list(width = 2, color = 'rgba(255, 255, 255, 0.9)'),
opacity = 0.8
),
hovertemplate = paste(
'<b>%{text}</b><br>',
'Revenue: $%{x:.1f}M<br>',
'Profit Margin: %{y:.1f}%<br>',
'Employees: %{marker.size:,.0f}<br>',
'Industry: %{marker.color}<br>',
'<extra></extra>'
)
) %>%
layout(
title = list(text = "公司收入、利润率与员工数量关系", font = list(size = 16)),
xaxis = list(title = "收入 (百万美元)"),
yaxis = list(title = "利润率 (%)"),
legend = list(title = list(text = "行业"))
)
company_bubble
5.2 多维度气泡图
# 产品数据的多维度气泡图
product_bubble <- plot_ly(
data = products_data,
x = ~price,
y = ~customer_rating,
size = ~sales_volume,
color = ~revenue,
colors = colorRamp(c("blue", "lightblue", "yellow", "orange", "red")),
text = ~paste("产品:", product, "<br>类别:", category),
type = 'scatter',
mode = 'markers',
marker = list(
sizemode = 'diameter',
sizeref = 2.0 * max(products_data$sales_volume) / (60^2),
sizemin = 3,
line = list(width = 1, color = 'rgba(0, 0, 0, 0.5)'),
opacity = 0.7,
colorbar = list(
title = "收入",
titleside = "right"
)
),
hovertemplate = paste(
'%{text}<br>',
'Price: $%{x:.2f}<br>',
'Rating: %{y:.2f}/5<br>',
'Sales Volume: %{marker.size:,.0f}<br>',
'Revenue: $%{marker.color:,.0f}<br>',
'<extra></extra>'
)
) %>%
layout(
title = list(text = "产品价格、评分、销量与收入关系", font = list(size = 16)),
xaxis = list(title = "价格 (美元)", type = "log"),
yaxis = list(title = "客户评分 (1-5分)")
)
product_bubble
6. 交互式功能增强
6.1 动画气泡图
# 创建时间序列数据用于动画
time_series_data <- expand.grid(
country = c("中国", "美国", "日本", "德国", "印度"),
year = 2015:2022
) %>%
mutate(
gdp_growth = rnorm(nrow(.), 3, 2),
investment = runif(nrow(.), 200, 1000),
innovation_index = runif(nrow(.), 30, 80),
gdp_growth = pmax(gdp_growth, -5) # 确保增长率不会太低
)
# 创建动画气泡图
animated_bubble <- time_series_data %>%
plot_ly(
x = ~investment,
y = ~gdp_growth,
size = ~innovation_index,
color = ~country,
frame = ~year,
text = ~country,
type = 'scatter',
mode = 'markers',
marker = list(
sizemode = 'diameter',
sizeref = 2.0 * max(time_series_data$innovation_index) / (40^2),
line = list(width = 2, color = 'rgba(255, 255, 255, 0.8)')
),
hovertemplate = paste(
'<b>%{text}</b><br>',
'Investment: $%{x:.0f}B<br>',
'GDP Growth: %{y:.1f}%<br>',
'Innovation Index: %{marker.size:.1f}<br>',
'<extra></extra>'
)
) %>%
layout(
title = list(text = "国家投资、GDP增长与创新指数 (2015-2022)", font = list(size = 16)),
xaxis = list(title = "投资 (十亿美元)"),
yaxis = list(title = "GDP增长率 (%)"),
legend = list(title = list(text = "国家"))
) %>%
animation_opts(
frame = 800,
transition = 400,
easing = "elastic",
redraw = FALSE
) %>%
animation_button(
x = 1, xanchor = 'right', y = 0, yanchor = 'bottom'
) %>%
animation_slider(
currentvalue = list(prefix = "年份: ")
)
animated_bubble
7. 高级自定义和样式
7.1 自定义主题气泡图
# 创建深色主题的气泡图
dark_theme_bubble <- plot_ly(
data = countries_data,
x = ~gdp_per_capita,
y = ~happiness_score,
size = ~population_millions,
color = ~continent,
colors = c("#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7", "#DDA0DD"),
text = ~country,
type = 'scatter',
mode = 'markers',
marker = list(
sizemode = 'diameter',
sizeref = 2.0 * max(countries_data$population_millions) / (50^2),
line = list(width = 2, color = 'rgba(255, 255, 255, 0.3)'),
opacity = 0.8
)
) %>%
layout(
title = list(
text = "GDP与幸福指数关系 - 深色主题",
font = list(color = "white", size = 18)
),
xaxis = list(
title = "人均GDP (美元)",
gridcolor = 'rgba(255,255,255,0.1)',
color = "white"
),
yaxis = list(
title = "幸福指数",
gridcolor = 'rgba(255,255,255,0.1)',
color = "white"
),
plot_bgcolor = 'rgba(0,0,0,0.9)',
paper_bgcolor = 'rgba(0,0,0,0.9)',
font = list(color = "white"),
legend = list(
font = list(color = "white"),
title = list(text = "大洲", font = list(color = "white"))
)
)
dark_theme_bubble
8. 数据洞察和总结
# 生成数据洞察
cat("=== 数据洞察总结 ===\n")
## === 数据洞察总结 ===
cat("国家数据分析:\n")
## 国家数据分析:
cat("- 最高人均GDP国家:", countries_data$country[which.max(countries_data$gdp_per_capita)], "\n")
## - 最高人均GDP国家: 瑞士
cat("- 预期寿命最长国家:", countries_data$country[which.max(countries_data$life_expectancy)], "\n")
## - 预期寿命最长国家: 日本
cat("- 人口最多国家:", countries_data$country[which.max(countries_data$population)], "\n")
## - 人口最多国家: 中国
cat("- 最幸福国家:", countries_data$country[which.max(countries_data$happiness_score)], "\n\n")
## - 最幸福国家: 瑞士
cat("公司数据分析:\n")
## 公司数据分析:
cat("- 收入最高公司:", companies_data$company[which.max(companies_data$revenue)], "\n")
## - 收入最高公司: 公司P
cat("- 利润率最高公司:", companies_data$company[which.max(companies_data$profit_margin)], "\n")
## - 利润率最高公司: 公司S
cat("- 员工最多公司:", companies_data$company[which.max(companies_data$employees)], "\n\n")
## - 员工最多公司: 公司H
# 相关性分析
cat("相关性分析:\n")
## 相关性分析:
cat("GDP与预期寿命相关系数:", round(cor(countries_data$gdp_per_capita, countries_data$life_expectancy), 3), "\n")
## GDP与预期寿命相关系数: 0.754
cat("GDP与幸福指数相关系数:", round(cor(countries_data$gdp_per_capita, countries_data$happiness_score), 3), "\n")
## GDP与幸福指数相关系数: 0.822
9. 最佳实践总结
www.rdaizuo.com
www.daixie.it.com
www.rcodedaixie.com
专业R语言辅导 | Python编程 | 数据分析 Data analysis | 统计分析 Statistics | 数据挖掘 Data mining | 机器学习 Machine learning | |统计分析 Statistics|STATS 202|STATS 203|STAT 110|STAT 104|STAT 705|STAT 707|STAT4203|STAT4204|STAT4205|STAT4206|STAT 133|STAT 134|STAT 101A|STAT 100A|STAT 581|STAT 520|STAT 521|STAT 4500|STAT 5805|STAT 5806|STAT 4600|STAT30001|STAT3001|STAT3002|STAT3003|STAT3004|STAT3005|STAT3006|STAT5001|STAT5002|STAT5003|STAT5004|
气泡图制作要点:
- 数据准备:确保数据质量,处理异常值
- 尺寸映射:合理设置sizeref参数控制气泡大小
- 颜色选择:使用对比明显的颜色方案
- 交互性:添加详细的hover信息
- 主题一致性:保持视觉风格统一
常用参数说明:
- size: 控制气泡大小的变量
- color: 控制气泡颜色的变量
- sizeref: 控制气泡大小的缩放比例
- sizemode: ‘diameter’ 或 ‘area’
- opacity: 透明度设置
- marker.line: 气泡边框设置
10. 保存和导出
# 保存为HTML文件
htmlwidgets::saveWidget(continent_bubble, "bubble_chart.html", selfcontained = TRUE)
# 保存为静态图片 (需要安装kaleido包)
# install.packages("reticulate")
# reticulate::py_install("kaleido")
# plotly::save_image(continent_bubble, "bubble_chart.png", width = 1200, height = 800)
这个完整的R Markdown教程包含了:
shiny 咨询
www.rshinyserver.com
主要特色:
- 完整的数据生成:三个不同领域的模拟数据集
- 基础到高级:从简单气泡图到复杂交互式图表
- 颜色控制:分类变量和连续变量的颜色映射
- 大小控制:详细的气泡大小参数设置
- 交互功能:动画、子图、hover效果
- 样式自定义:深色主题等视觉效果
- 实用技巧:最佳实践和参数说明
包含的图表类型:
- 基础气泡图
- 按分类着色的气泡图
- 按连续变量着色的气泡图
- 多维度气泡图
- 动画气泡图
- 子图组合
- 自定义主题气泡图