如何在R中为轮廓图的不同簇设置差异化纹理?
解决轮廓图分簇设置不同纹理的问题
嘿,这个坑我之前踩过!直接用plot函数全局设置density和angle确实会让所有簇的纹理同步变化,要实现分簇差异化纹理,核心思路是逐个绘制每个簇的轮廓条,这样就能给每个簇单独指定纹理参数了。下面分Python和R两种常用场景给你具体方案:
Python(Matplotlib)实现
假设你用的是sklearn计算轮廓系数,结合matplotlib绘图:
import matplotlib.pyplot as plt from sklearn.cluster import KMeans from sklearn.metrics import silhouette_samples, silhouette_score import numpy as np # 1. 准备数据和聚类结果(替换成你的真实数据即可) X = np.random.rand(150, 2) # 示例:150个样本,2个特征 kmeans = KMeans(n_clusters=3, random_state=42) labels = kmeans.fit_predict(X) # 2. 计算轮廓系数 silhouette_vals = silhouette_samples(X, labels) sil_avg = silhouette_score(X, labels) # 平均轮廓系数 # 3. 定义每个簇的专属参数(颜色、纹理密度、角度) cluster_params = [ {"color": "#1f77b4", "density": 5, "angle": 0}, {"color": "#ff7f0e", "density": 10, "angle": 45}, {"color": "#2ca02c", "density": 15, "angle": 90} ] # 4. 逐个绘制每个簇的轮廓条 fig, ax = plt.subplots(figsize=(8, 6)) y_lower = 10 # 初始y轴位置 for cluster_idx in range(3): # 提取当前簇的轮廓系数并排序 cluster_sil = silhouette_vals[labels == cluster_idx] cluster_sil.sort() cluster_size = cluster_sil.shape[0] y_upper = y_lower + cluster_size # 绘制带纹理的填充区域 ax.fill_betweenx( np.arange(y_lower, y_upper), 0, cluster_sil, facecolor=cluster_params[cluster_idx]["color"], edgecolor=cluster_params[cluster_idx]["color"], density=cluster_params[cluster_idx]["density"], angle=cluster_params[cluster_idx]["angle"] ) # 添加簇编号标签 ax.text(-0.05, y_lower + cluster_size/2, str(cluster_idx + 1)) y_lower = y_upper + 10 # 簇之间留空白间距 # 添加平均轮廓线 ax.axvline(x=sil_avg, color="red", linestyle="--", label="Average Silhouette Score") ax.set_title("Silhouette Plot with Cluster-specific Hatching") ax.set_xlabel("Silhouette Coefficient Value") ax.set_ylabel("Cluster") ax.legend() plt.show()
R(ggplot2 + ggpattern)实现
如果用R语言,推荐结合ggpattern包实现自定义纹理:
library(cluster) library(ggplot2) library(ggpattern) # 1. 准备数据和聚类结果(示例用iris数据集) data(iris) X <- iris[, 1:4] km_model <- kmeans(X, 3) sil_results <- silhouette(km_model$cluster, dist(X)) sil_df <- as.data.frame(sil_results) # 2. 定义每个簇的纹理参数 cluster_patterns <- list( cluster1 = list(pattern = "stripe", density = 0.1, angle = 0), cluster2 = list(pattern = "crosshatch", density = 0.2, angle = 45), cluster3 = list(pattern = "dot", density = 0.3, angle = 90) ) # 3. 绘制分簇纹理的轮廓图 ggplot(sil_df, aes(x = sil_width, y = reorder(cluster, sil_width))) + geom_pattern_area( aes(pattern = factor(cluster), fill = factor(cluster)), pattern_density = c(cluster_patterns$cluster1$density, cluster_patterns$cluster2$density, cluster_patterns$cluster3$density), pattern_angle = c(cluster_patterns$cluster1$angle, cluster_patterns$cluster2$angle, cluster_patterns$cluster3$angle), pattern_fill = "black" ) + scale_pattern_manual(values = c("stripe", "crosshatch", "dot")) + geom_vline(xintercept = mean(sil_df$sil_width), linetype = "dashed", color = "red") + labs( title = "Silhouette Plot with Cluster-specific Textures", x = "Silhouette Width", y = "Cluster", fill = "Cluster", pattern = "Texture Pattern" ) + theme_minimal()
核心原理
原来的plot函数会把density和angle作为全局参数应用到所有元素上,而通过循环拆分每个簇单独绘制,我们可以为每个簇的填充区域传递独立的纹理参数,从而实现分簇纹理差异化。
内容的提问来源于stack exchange,提问作者K.-T. Chen
相关产品推荐
相关产品推荐

