Matplotlib三元图报错:'AxesSubplot'对象无'colorbar'属性
错误原因与修复方案:AttributeError: 'AxesSubplot' object has no attribute 'colorbar'
错误根源
你的代码中创建画布对象时出现了关键错误:
fig = plt.subplot() ax = plt.subplot()
plt.subplot()返回的是坐标轴对象(AxesSubplot),而非Matplotlib的画布对象(Figure)。而colorbar是Figure对象独有的方法,当你把这个错误的"fig"传入plot2方法调用fig.colorbar()时,自然会触发AttributeError。
修复步骤
1. 正确创建Figure和Axes对象
将创建画布和坐标轴的代码替换为:
fig, ax = plt.subplots(figsize=(10, 10)) # figsize可根据需求调整,适配三元图比例
这行代码会同时返回正确的Figure对象(fig)和对应的坐标轴对象(ax)。
2. 可选优化(提升图表效果)
- 修复数据追加逻辑:
append_data方法开头的清空语句会导致多次添加数据时丢失之前的内容,建议移除:# 移除append_data方法中的这三行 self.weights = [] self.colors = [] self.labels = [] - 调整坐标轴范围:三元图是等边三角形,实际高度为√3/2≈0.866,修改
plot_frame中的坐标轴范围,减少顶部空白:# 替换原ax.axis(...) ax.axis([-0.1, 1.1, -0.025, 0.9])
完整修正后的代码
import matplotlib.pyplot as plt from matplotlib.colors import LogNorm import matplotlib.cm as cm import numpy as np import matplotlib as mpl import pandas as pd from math import sqrt from matplotlib.ticker import LogFormatter from mpl_toolkits.axes_grid1 import make_axes_locatable dataset = pd.read_excel('/content/Sequecia BC74 teste v2.xlsx') class Ternary: font_size = 12 plot_size = 12 def __init__(self, label_A: str = "A", label_B: str = "B", label_C: str = "C", min_ternary: float = 0): self.label_A = label_A self.label_B = label_B self.label_C = label_C self.min_ternary = min_ternary self.weights = [] self.colors = [] self.labels = [] self.X = [] self.Y = [] self.Z = [] def append_data(self, A, B, C, weights=None, colors=None, tick_label: list=[]): # 移除原清空语句,支持多次追加数据 if len(A) != len(B) or len(B) != len(C): print("ERROR in append_data, table length are different") else: for i in range(len(A)): if A[i] + B[i] + C[i] >= self.min_ternary: self.X.append(0.5 * (2 * C[i] + B[i]) / (A[i] + B[i] + C[i])) self.Y.append(sqrt(3) * 0.5 * B[i] / (A[i] + B[i] + C[i])) if weights is not None: self.weights.append(weights[i]) else: self.weights.append(1) if colors is not None: self.colors.append(colors[i]) else: self.colors.append(1) if len(tick_label) > 0: self.labels.append(tick_label[i]) def plot2(self, ax, fig, cmap, norm, bounds, scale_factor: int = 1, weight_label: str = None, color_label: str = None, label: str = "Ter", tet_marks: bool = False, graduation_step: float = 10, show_scale: bool = True, show_legend: bool = True): self.plot_frame(ax=ax, graduation_step=graduation_step, tetrahedron_marks=tet_marks) # Label label_points = label + " - " + str(len(self.X)) + " inclusions" if weight_label is not None: label_mean = "Mean " + weight_label + ": " + str(np.round(np.mean(np.asarray(self.weights)), 2)) else: label_mean = "Mean" if color_label is not None: label_mean += " / color coding: " + color_label # Plot data if len(self.labels) > 0: if len(np.unique(np.asarray(self.labels))) > 10: cmap = cm.tab20 else: cmap = cm.tab10 unique, index, inverse = np.unique(self.colors, return_index=True, return_inverse=True) self.colors = inverse bounds = range(len(np.unique(np.asarray(self.labels)[index]))) dat = ax.scatter(self.X, self.Y, s=[x * scale_factor for x in self.weights], label=label_points, c=self.colors, cmap=cmap, norm=norm, edgecolors="k", linewidth=0.25) divider = make_axes_locatable(ax) cax = divider.append_axes('right', size='5%', pad=0.05) cbar = fig.colorbar(dat, cax=cax, format='%.2f', ticks=bounds) cbar.ax.tick_params(labelsize=12) if len(self.labels) > 0: cbar.ax.set_yticklabels(np.asarray(self.labels)[index]) # Plot Mean ax.scatter(np.mean(np.asarray(self.X)), np.mean(np.asarray(self.Y)), s=scale_factor * np.mean(self.weights), label=label_mean, edgecolors="k", linewidth=0.25, color="black") ax.legend(fontsize="large", loc="upper right") return dat def plot_frame(self, ax, graduation_step: float = 10, tetrahedron_marks: bool = False): T1 = [0, 0.5] TT1 = [x * sqrt(3) for x in T1] T2 = [0.5, 1] TT2 = [(-x * (sqrt(3))) + sqrt(3) for x in T2] T3 = [0, 1] TT3 = [0 * x for x in T3] ax.plot(T1, TT1, c='black', lw=0.5) ax.plot(T2, TT2, c='black', lw=0.5) ax.plot(T3, TT3, c='black', lw=0.5) for x in np.linspace(graduation_step, 100 - graduation_step, int((100 / graduation_step) - 1)): x = x/100 T = [x, x + 0.5 * (1 - x)] TT = [sqrt(3) * (y - x) for y in T] ax.plot(T, TT, c='grey', lw=0.2) T = [0.5 * x, 1 - 0.5 * x] TT = [sqrt(3) * 0.5 * x for y in T] ax.plot(T, TT, c='grey', lw=0.2) T = [(1 - x) * 0.5, 1 - x] TT = [-sqrt(3) * y + sqrt(3) * (1 - x) for y in T] ax.plot(T, TT, c='grey', lw=0.2) # 调整坐标轴范围,适配等边三角形高度 ax.axis([-0.1, 1.1, -0.025, 0.9]) ax.text(-0.05, 0, self.label_A, fontsize=self.font_size) ax.text(0.5, (0.5 * sqrt(3)) * (1 + 0.02), self.label_B, fontsize=self.font_size) ax.text(1 + 0.02, 0, self.label_C, fontsize=self.font_size) if tetrahedron_marks: T1 = [0, 0.5] TT1 = [x * 2 * sqrt(1 / 12) for x in T1] T2 = [0.5, 1] TT2 = [(-x * 2 * sqrt(1 / 12) + 2 * sqrt(1 / 12)) for x in T2] T3 = [0.5, 0.5] TT3 = [sqrt(1 / 12), sqrt(3) / 2] ax.plot(T1, TT1, c='black', lw=0.5) ax.plot(T2, TT2, c='black', lw=0.5) ax.plot(T3, TT3, c='black', lw=0.5) ax.set_aspect(aspect="equal") ax.axis("off") ter = Ternary() ter.append_data(dataset['CaOMnOMgO'], dataset['SiO2'], dataset['Al2O3'],dataset['Tamanho'],dataset['O2']) # 正确创建Figure和Axes对象 fig, ax = plt.subplots(figsize=(10,10)) cmap = mpl.cm.coolwarm bounds = [1, 2, 3, 4, 5, 10] norm = mpl.colors.BoundaryNorm(bounds, cmap.N) ter.plot2(ax, fig, cmap, norm, bounds) plt.show() # 添加这行确保图表显示
内容的提问来源于stack exchange,提问作者Kleverton Junio
相关产品推荐
相关产品推荐

