6.3 图形、子图和坐标

6.3.1 图形Figure

Matplotlib中的"figure"表示用户界面中的整个窗口,一个figure对象是标题为"Figure#"的GUI窗口,Figure命名是以1开始,与以0开始索引的常规Python方式截然不同。这显然是Matlab风格。以下有几个参数确定figure对象的外观,如下表所示:

参数默认值描述
num1图形的数量
figsizefigure.figsize图形对象的宽度和高度(单位:英寸)
dpifigure.dpi像素分辨率
facecolorfigure.facecolor背景颜色
edgecolorfigure.edgecolor边界颜色
frameonTure是否绘制框架

默认值可以在源文件中指定,并且在大多数时间都会使用,只有图形的编号经常改变。

6.3.2 子图Axes

一个绘图对象(figure)可以包含多个子图(Axes),在Matplotlib中用Axes对象表示一个绘图区域。在前面的例子中,Figure对象只包括一个子图。可以使用subplot()函数快速绘制多个子图的图表。它的调用形式如下:

subplot(numRows, numCols, plotNum)

subplot将整个绘图区域等分为numRows行 * numCols列个子区域,然后按照从左到右,从上到下的顺序对每个子区域进行编号,左上的子区域的编号为1。plotNum参数指定所创建Axes对象的区域。如果numRows,numCols和plotNum这三个数都小于10的话,可以把它们缩写为一个整数,例如subplot(323)和subplot(3,2,3)是相同的。如果新创建的子图和之前创建的子图重叠,之前的子图将被删除。
下面的程序创建3行2列共6个子图,通过axisbg参数给每个轴设置不同的背景颜色。示例代码:

for idx, color in enumerate("rgbyck"):
    plt.subplot(320+idx+1, axisbg=color)
plt.show()

显示结果:


图6.3-1

通过创建figure对象,利用add_subplot()方法也可以创建若干子图,其参数与subplot()函数一致。拟构造了两个子图,按列并排显示,示例代码:

import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(2,1,1)
ax2 = fig.add_subplot(2,1,2)
plt.show()

显示结果:


生成两个子图


此外,可以根据标号显示指定图像,示例代码:

import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(3,2,1)
ax2 = fig.add_subplot(3,2,2)
ax6 = fig.add_subplot(3,2,6)
plt.show()

根据要求显示了三个图像,如图所示:


生成三个子图


可以绘制子图的不同图像,示例代码:

import numpy as np
fig = plt.figure()
#fig = plt.figure(figsize=(3, 3))
ax1 = fig.add_subplot(2,1,1)
ax2 = fig.add_subplot(2,1,2)
ax1.plot(np.random.randint(1,5,5), np.arange(5))
ax2.plot(np.arange(10)*3, np.arange(10))
plt.show()

显示结果:


绘制不同子图

除了绘制不同的子图,在同一个子图中也可以绘制多个图表,示例代码:

import pandas as pd
import matplotlib.pyplot as plt
unrate = pd.read_csv("unrate.csv")
unrate['DATE'] = pd.to_datetime(unrate['DATE'])
unrate['MONTH'] = unrate['DATE'].dt.month
fig = plt.figure(figsize=(10, 6))
ax1 = fig.add_subplot(1,1,1)
colors = ['r', 'b', 'g', 'y', 'k']
for i in range(5):
    start_index = i*12
    end_index = (i+1)*12
    subset = unrate[start_index:end_index]
    label = str(1948+i)
    ax1.plot(subset["MONTH"], subset["VALUE"], c=colors[i], label=label)
ax1.legend(loc="upper left")
plt.xlabel("Month, Integer")
plt.ylabel("Unemployment Rate, Percent")
plt.title("Monthly Unemployment Trends, 1948-1952")
plt.show()

显示结果:


同一子图多图表显示

6.3.3 坐标Axis容器

Axis容器包括坐标轴上的刻度线、刻度文本、坐标网格以及坐标轴标题等内容。每个刻度线都是一个XTick或YTick对象,它包括实际的刻度线和刻度文本。
下面先创建一个子图并获得其X轴对象axis:

import matplotlib.pyplot as plt
fig, ax = plt.subplots()
axis = ax.xaxis

下面获得axis对象的刻度位置的列表:

axis.get_ticklocs()

运行结果:

array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ])

下面获得axis对象的刻度标签以及标签中的文字:

print(axis.get_ticklabels())    # 获得刻度标签的列表
print([x.get_text() for x in axis.get_ticklabels()])    # 获得刻度的文本字符串

运行结果:

<a list of 6 Text major ticklabel objects>

下面获得轴上表示主刻度线的列表,可以看到X轴上共有12条刻度线,它们是子图的上下两个X轴上的所有刻度线:

axis.get_ticklines()
<a list of 12 Line2D ticklines objects>

由于图中没有副刻度线,因此副刻度线列表的长度为0:

axis.get_ticklines(minor=True)    # 获得副刻度线列表
<a list of 0 Line2D ticklines objects>

获得刻度线或刻度标签之后,可以设置其各种属性,下面设置刻度线为绿色粗线,文本为红色并且旋转45°。示例代码:

for label in axis.get_ticklabels():
    label.set_color("red")
    label.set_rotation(45)
    label.set_fontsize(16)
for line in axis.get_ticklines():
    line.set_color("green")
    line.set_markersize(25)     # 设置刻度线长度
    line.set_markeredgewidth(3)    # 设置刻度线宽度
fig

显示结果
使用pyplot模块中的xticks()能够快速的完成X轴上的刻度文本的配置。不过,xticks()只能设置刻度文本的属性,不能设置刻度线的属性。示例代码:

plt.xticks(fontsize=16, color="red", rotation=45)
import pandas as pd import numpy as np from sklearn.cluster import KMeans from sklearn.preprocessing import LabelEncoder from sklearn.metrics import adjusted_rand_score, silhouette_score import matplotlib.pyplot as plt from io import StringIO import warnings # 忽略Matplotlib的特定警告 warnings.filterwarnings("ignore", category=UserWarning, module="matplotlib") # --------------------- 1. 数据加载与处理 --------------------- # 鸢尾花数据集 iris_data = """ Sepal.Length,Sepal.Width,Petal.Length,Petal.Width,Species 5.1,3.5,1.4,0.2,setosa 4.9,3.0,1.4,0.2,setosa 4.7,3.2,1.3,0.2,setosa 4.6,3.1,1.5,0.2,setosa 5.0,3.6,1.4,0.2,setosa 5.4,3.9,1.7,0.4,setosa 4.6,3.4,1.4,0.3,setosa 5.0,3.4,1.5,0.2,setosa 4.4,2.9,1.4,0.2,setosa 4.9,3.1,1.5,0.1,setosa 5.4,3.7,1.5,0.2,setosa 4.8,3.4,1.6,0.2,setosa 4.8,3.0,1.4,0.1,setosa 4.3,3.0,1.1,0.1,setosa 5.8,4.0,1.2,0.2,setosa 5.7,4.4,1.5,0.4,setosa 5.4,3.9,1.3,0.4,setosa 5.1,3.5,1.4,0.3,setosa 5.7,3.8,1.7,0.3,setosa 5.1,3.8,1.5,0.3,setosa 5.4,3.4,1.7,0.2,setosa 5.1,3.7,1.5,0.4,setosa 4.6,3.6,1.0,0.2,setosa 5.1,3.3,1.7,0.5,setosa 4.8,3.4,1.9,0.2,setosa 5.0,3.0,1.6,0.2,setosa 5.0,3.4,1.6,0.4,setosa 5.2,3.5,1.5,0.2,setosa 5.2,3.4,1.4,0.2,setosa 4.7,3.2,1.6,0.2,setosa 4.8,3.1,1.6,0.2,setosa 5.4,3.4,1.5,0.4,setosa 5.2,4.1,1.5,0.1,setosa 5.5,4.2,1.4,0.2,setosa 4.9,3.1,1.5,0.2,setosa 5.0,3.2,1.2,0.2,setosa 5.5,3.5,1.3,0.2,setosa 4.9,3.6,1.4,0.1,setosa 4.4,3.0,1.3,0.2,setosa 5.1,3.4,1.5,0.2,setosa 5.0,3.5,1.3,0.3,setosa 4.5,2.3,1.3,0.3,setosa 4.4,3.2,1.3,0.2,setosa 5.0,3.5,1.6,0.6,setosa 5.1,3.8,1.9,0.4,setosa 4.8,3.0,1.4,0.3,setosa 5.1,3.8,1.6,0.2,setosa 4.6,3.2,1.4,0.2,setosa 5.3,3.7,1.5,0.2,setosa 5.0,3.3,1.4,0.2,setosa 7.0,3.2,4.7,1.4,versicolor 6.4,3.2,4.5,1.5,versicolor 6.9,3.1,4.9,1.5,versicolor 5.5,2.3,4.0,1.3,versicolor 6.5,2.8,4.6,1.5,versicolor 5.7,2.8,4.5,1.3,versicolor 6.3,3.3,4.7,1.6,versicolor 4.9,2.4,3.3,1.0,versicolor 6.6,2.9,4.6,1.3,versicolor 5.2,2.7,3.9,1.4,versicolor 5.0,2.0,3.5,1.0,versicolor 5.9,3.0,4.2,1.5,versicolor 6.0,2.2,4.0,1.0,versicolor 6.1,2.9,4.7,1.4,versicolor 5.6,2.9,3.6,1.3,versicolor 6.7,3.1,4.4,1.4,versicolor 5.6,3.0,4.5,1.5,versicolor 5.8,2.7,4.1,1.0,versicolor 6.2,2.2,4.5,1.5,versicolor 5.6,2.5,3.9,1.1,versicolor 5.9,3.2,4.8,1.8,versicolor 6.1,2.8,4.0,1.3,versicolor 6.3,2.5,4.9,1.5,versicolor 6.1,2.8,4.7,1.2,versicolor 6.4,2.9,4.3,1.3,versicolor 6.6,3.0,4.4,1.4,versicolor 6.8,2.8,4.8,1.4,versicolor 6.7,3.0,5.0,1.7,versicolor 6.0,2.9,4.5,1.5,versicolor 5.7,2.6,3.5,1.0,versicolor 5.5,2.4,3.8,1.1,versicolor 5.5,2.4,3.7,1.0,versicolor 5.8,2.7,3.9,1.2,versicolor 6.0,2.7,5.1,1.6,versicolor 5.4,3.0,4.5,1.5,versicolor 6.0,3.4,4.5,1.6,versicolor 6.7,3.1,4.7,1.5,versicolor 6.3,2.3,4.4,1.3,versicolor 5.6,3.0,4.1,1.3,versicolor 5.5,2.5,4.0,1.3,versicolor 5.5,2.6,4.4,1.2,versicolor 6.1,3.0,4.6,1.4,versicolor 5.8,2.6,4.0,1.2,versicolor 5.0,2.3,3.3,1.0,versicolor 5.6,2.7,4.2,1.3,versicolor 5.7,3.0,4.2,1.2,versicolor 5.7,2.9,4.2,1.3,versicolor 6.2,2.9,4.3,1.3,versicolor 5.1,2.5,3.0,1.1,versicolor 5.7,2.8,4.1,1.3,versicolor 6.3,3.3,6.0,2.5,virginica 5.8,2.7,5.1,1.9,virginica 7.1,3.0,5.9,2.1,virginica 6.3,2.9,5.6,1.8,virginica 6.5,3.0,5.8,2.2,virginica 7.6,3.0,6.6,2.1,virginica 4.9,2.5,4.5,1.7,virginica 7.3,2.9,6.3,1.8,virginica 6.7,2.5,5.8,1.8,virginica 7.2,3.6,6.1,2.5,virginica 6.5,3.2,5.1,2.0,virginica 6.4,2.7,5.3,1.9,virginica 6.8,3.0,5.5,2.1,virginica 5.7,2.5,5.0,2.0,virginica 5.8,2.8,5.1,2.4,virginica 6.4,3.2,5.3,2.3,virginica 6.5,3.0,5.5,1.8,virginica 7.7,3.8,6.7,2.2,virginica 7.7,2.6,6.9,2.3,virginica 6.0,2.2,5.0,1.5,virginica 6.9,3.2,5.7,2.3,virginica 5.6,2.8,4.9,2.0,virginica 7.7,2.8,6.7,2.0,virginica 6.3,2.7,4.9,1.8,virginica 6.7,3.3,5.7,2.1,virginica 7.2,3.2,6.0,1.8,virginica 6.2,2.8,4.8,1.8,virginica 6.1,3.0,4.9,1.8,virginica 6.4,2.8,5.6,2.1,virginica 7.2,3.0,5.8,1.6,virginica 7.4,2.8,6.1,1.9,virginica 7.9,3.8,6.4,2.0,virginica 6.4,2.8,5.6,2.2,virginica 6.3,2.8,5.1,1.5,virginica 6.1,2.6,5.6,1.4,virginica 7.7,3.0,6.1,2.3,virginica 6.3,3.4,5.6,2.4,virginica 6.4,3.1,5.5,1.8,virginica 6.0,3.0,4.8,1.8,virginica 6.9,3.1,5.4,2.1,virginica 6.7,3.1,5.6,2.4,virginica 6.9,3.1,5.1,2.3,virginica 5.8,2.7,5.1,1.9,virginica 6.8,3.2,5.9,2.3,virginica 6.7,3.3,5.7,2.5,virginica 6.7,3.0,5.2,2.3,virginica 6.3,2.5,5.0,1.9,virginica 6.5,3.0,5.2,2.0,virginica 6.2,3.4,5.4,2.3,virginica 5.9,3.0,5.1,1.8,virginica """ # 读取数据 df = pd.read_csv(StringIO(iris_data)) print(f"数据集形状: {df.shape}") print("前5行数据:") print(df.head()) # --------------------- 2. 数据预处理 --------------------- # 提取特征 X = df[["Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"]].values # 标签编码 le = LabelEncoder() y_true = le.fit_transform(df["Species"]) species_names = le.classes_ print("\n物种编码映射:") for i, name in enumerate(species_names): print(f"{name} → {i}") # --------------------- 3. K-Means聚类 --------------------- # 创建K-Means模型 kmeans = KMeans( n_clusters=3, # 聚类数量 init=&#39;k-means++&#39;, # 智能初始化方法 n_init=10, # 多次初始化以避免局部最优 max_iter=300, # 最大迭代次数 random_state=42 # 随机种 ) # 训练模型 kmeans.fit(X) # 获取结果 y_pred = kmeans.labels_ # 聚类标签 centroids = kmeans.cluster_centers_ # 聚类中心 inertia = kmeans.inertia_ # 样本到最近聚类中心的平方 print("\n聚类完成!") print(f"样本到最近聚类中心的平方: {inertia:.2f}") # --------------------- 4. 聚类结果评估 --------------------- # 评估指标 ari = adjusted_rand_score(y_true, y_pred) # 调整兰德指数 silhouette = silhouette_score(X, y_pred) # 轮廓系数 print("\n聚类评估:") print(f"调整兰德指数(ARI): {ari:.4f} (1.0表示完美匹配)") print(f"轮廓系数: {silhouette:.4f} (越高表示聚类效果越好)") # 聚类中心分析 print("\n聚类中心坐标:") for i, center in enumerate(centroids): print(f"Cluster {i}:") print(f" 萼片长度: {center[0]:.2f} cm, 萼片宽度: {center[1]:.2f} cm") print(f" 花瓣长度: {center[2]:.2f} cm, 花瓣宽度: {center[3]:.2f} cm") # 聚类与物种对应关系 cluster_species = {} print("\n聚类物种分布:") for cluster in range(3): species_in_cluster = df.loc[y_pred == cluster, &#39;Species&#39;].value_counts() dominant_species = species_in_cluster.idxmax() cluster_species[cluster] = dominant_species print(f"Cluster {cluster} 主要包含: {dominant_species} ({species_in_cluster[dominant_species]}个样本)") # --------------------- 5. 可视化 --------------------- plt.figure(figsize=(15, 10)) # 1. 花瓣特征散点 ax1 = plt.subplot(2, 2, 1) # 为每个创建新的轴对象 scatter1 = ax1.scatter( X[:, 2], X[:, 3], c=y_pred, cmap=&#39;viridis&#39;, s=50, alpha=0.7, edgecolor=&#39;k&#39; ) centroids1 = ax1.scatter( centroids[:, 2], centroids[:, 3], marker=&#39;X&#39;, s=200, c=&#39;red&#39;, label=&#39;聚类中心&#39; ) ax1.set_title(&#39;花瓣长度 vs 花瓣宽度&#39;) ax1.set_xlabel(&#39;花瓣长度 (cm)&#39;) ax1.set_ylabel(&#39;花瓣宽度 (cm)&#39;) ax1.legend() ax1.grid(alpha=0.3) # 2. 萼片特征散点 ax2 = plt.subplot(2, 2, 2) scatter2 = ax2.scatter( X[:, 0], X[:, 1], c=y_pred, cmap=&#39;viridis&#39;, s=50, alpha=0.7, edgecolor=&#39;k&#39; ) centroids2 = ax2.scatter( centroids[:, 0], centroids[:, 1], marker=&#39;X&#39;, s=200, c=&#39;red&#39; ) ax2.set_title(&#39;萼片长度 vs 萼片宽度&#39;) ax2.set_xlabel(&#39;萼片长度 (cm)&#39;) ax2.set_ylabel(&#39;萼片宽度 (cm)&#39;) ax2.grid(alpha=0.3) # 3. 混合特征散点 ax3 = plt.subplot(2, 2, 3) scatter3 = ax3.scatter( X[:, 0], X[:, 2], c=y_pred, cmap=&#39;viridis&#39;, s=50, alpha=0.7, edgecolor=&#39;k&#39; ) centroids3 = ax3.scatter( centroids[:, 0], centroids[:, 2], marker=&#39;X&#39;, s=200, c=&#39;red&#39; ) ax3.set_title(&#39;萼片长度 vs 花瓣长度&#39;) ax3.set_xlabel(&#39;萼片长度 (cm)&#39;) ax3.set_ylabel(&#39;花瓣长度 (cm)&#39;) ax3.grid(alpha=0.3) # 4. 聚类物种分布饼 ax4 = plt.subplot(2, 2, 4) # 准备数据:每个聚类中每个物种的数量 cluster_counts = [] for cluster in range(3): species_in_cluster = df.loc[y_pred == cluster, &#39;Species&#39;].value_counts() # 保证顺序与species_names一致 counts = [species_in_cluster.get(s, 0) for s in species_names] cluster_counts.append(counts) # 转换为数组,形状为(3,3) cluster_counts = np.array(cluster_counts) # 设置条形位置 bar_width = 0.6 x = np.arange(3) # 绘制堆叠条形 bottom = np.zeros(3) colors = [&#39;#ff9999&#39;,&#39;#66b3ff&#39;,&#39;#99ff99&#39;] for i, species in enumerate(species_names): ax4.bar( x, cluster_counts[:, i], bottom=bottom, width=bar_width, label=species, color=colors[i], alpha=0.7 ) bottom += cluster_counts[:, i] ax4.set_title(&#39;每个聚类中的物种分布&#39;) ax4.set_xlabel(&#39;聚类&#39;) ax4.set_ylabel(&#39;样本数量&#39;) ax4.set_xticks(x) ax4.set_xticklabels([&#39;Cluster 0&#39;, &#39;Cluster 1&#39;, &#39;Cluster 2&#39;]) ax4.legend(loc=&#39;upper right&#39;) ax4.grid(axis=&#39;y&#39;, alpha=0.3) plt.tight_layout() plt.savefig(&#39;iris_clustering_results.png&#39;, dpi=300, bbox_inches=&#39;tight&#39;) plt.show() # --------------------- 6. 肘部法确定最佳K值 --------------------- plt.figure(figsize=(10, 6)) inertias = [] k_range = range(1, 10) for k in k_range: kmeans = KMeans(n_clusters=k, random_state=42, n_init=10) kmeans.fit(X) inertias.append(kmeans.inertia_) plt.plot(k_range, inertias, &#39;bo-&#39;) plt.xlabel(&#39;聚类数量 (K)&#39;) plt.ylabel(&#39;样本到最近中心的平方&#39;) plt.title(&#39;肘部法确定最佳K值&#39;) plt.xticks(k_range) plt.grid(True) plt.savefig(&#39;elbow_method.png&#39;, dpi=300, bbox_inches=&#39;tight&#39;) plt.show() # --------------------- 7. 聚类边界可视化 --------------------- # 选择两个特征进行可视化 plt.figure(figsize=(12, 8)) # 选择花瓣长度宽度进行可视化 x_min, x_max = X[:, 2].min() - 0.5, X[:, 2].max() + 0.5 y_min, y_max = X[:, 3].min() - 0.5, X[:, 3].max() + 0.5 # 创建网格点 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02)) # 使用花瓣特征训练新模型 X_subset = X[:, 2:4] kmeans_subset = KMeans(n_clusters=3, random_state=42, n_init=10) kmeans_subset.fit(X_subset) # 预测网格点 Z = kmeans_subset.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) # 绘制决策边界 plt.contourf(xx, yy, Z, alpha=0.4, cmap=&#39;viridis&#39;) plt.scatter( X_subset[:, 0], X_subset[:, 1], c=y_pred, cmap=&#39;viridis&#39;, s=50, alpha=0.8, edgecolor=&#39;k&#39; ) plt.scatter( centroids[:, 2], centroids[:, 3], marker=&#39;X&#39;, s=200, c=&#39;red&#39;, label=&#39;聚类中心&#39; ) plt.title(&#39;花瓣特征的聚类边界&#39;) plt.xlabel(&#39;花瓣长度 (cm)&#39;) plt.ylabel(&#39;花瓣宽度 (cm)&#39;) plt.legend() plt.grid(alpha=0.3) plt.savefig(&#39;cluster_boundaries.png&#39;, dpi=300, bbox_inches=&#39;tight&#39;) plt.show()表明横纵坐标
最新发布
11-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值