python pic3:折线柱状
折线柱状
import matplotlib.pyplot as plt import numpy as np import pandas as pd from mpl_toolkits.mplot3d import Axes3D # ===== 强制中文字体设置 ===== plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS'] plt.rcParams['axes.unicode_minus'] = False # ========== 1. 读取Excel数据 ========== file_path = r"D:/趋势图.xlsx" df = pd.read_excel(file_path, engine='openpyxl') def extract_interval_value(text): try: parts = str(text).split('-') for p in reversed(parts): if p != '': return float(p) return np.nan except: return np.nan interval_raw = df["区间"].values area_before = df["作业前面积"].values area_after = df["作业后面积"].values pct_before = df["作业前面积占比"].values pct_after = df["作业后面积占比"].values intervals = np.array([extract_interval_value(v) for v in interval_raw]) valid_mask = ~(np.isnan(intervals) | np.isnan(area_before) | np.isnan(area_after) | np.isnan(pct_before) | np.isnan(pct_after)) intervals = intervals[valid_mask] area_before = area_before[valid_mask] area_after = area_after[valid_mask] pct_before = pct_before[valid_mask] pct_after = pct_after[valid_mask] print("有效数据行数:", len(intervals)) # ========== 2. 3D画布(白底)========== fig = plt.figure(figsize=(18, 12), dpi=150) ax = fig.add_subplot(111, projection='3d') ax.set_facecolor('white') fig.patch.set_facecolor('white') n = len(intervals) x_pos = np.arange(n) width = 0.5 depth = 0.3 max_area = 50 max_pct = max(pct_before.max(), pct_after.max()) scale_factor = 0.85 pct_height_before = max_area * (pct_before / 100) * scale_factor pct_height_after = max_area * (pct_after / 100) * scale_factor # ===== 3. 柱状图 ===== bar_y_pos = 0.6 bars1 = ax.bar3d(x_pos - width/2, bar_y_pos, 0, width, depth, area_before, color='#B8A9C9', alpha=0.5, edgecolor='none') bars2 = ax.bar3d(x_pos - width/2, bar_y_pos + depth, 0, width, depth, area_after, color='#00aaff', alpha=0.6, edgecolor='none') # ===== 4. 占比折线 ===== line_y_pos = -0.3 ax.plot(x_pos, [line_y_pos]*n, pct_height_before, color='#B8A9C9', linewidth=2, marker='o', markersize=2, markerfacecolor='#B8A9C9', markeredgewidth=2, markeredgecolor='#B8A9C9', linestyle='--', label='作业前占比') ax.plot(x_pos, [line_y_pos]*n, pct_height_after, color='#00aaff', linewidth=2, marker='o', markersize=2, markerfacecolor='white', markeredgewidth=2, markeredgecolor='#00aaff', linestyle='-.', label='作业后占比') # ===== 5. 占比数值标签 ===== # step_label = max(1, n // 8) # for i in range(0, n, step_label): # ax.text(x_pos[i], line_y_pos, pct_height_before[i] + max_area*0.015, # f'{pct_before[i]:.1f}%', color='#00aaff', fontsize=8, ha='center', va='bottom') # ax.text(x_pos[i], line_y_pos, pct_height_after[i] + max_area*0.015, # f'{pct_after[i]:.1f}%', color='#ff44aa', fontsize=8, ha='center', va='bottom') # ===== 6. 从折线到地面的垂直虚线 ===== step_line = max(1, n // 15) for i in range(0, n, step_line): ax.plot([x_pos[i], x_pos[i]], [line_y_pos, line_y_pos], [0, pct_height_before[i]], color='#00aaff', linewidth=0.5, alpha=0.2, linestyle=':') ax.plot([x_pos[i], x_pos[i]], [line_y_pos, line_y_pos], [0, pct_height_after[i]], color='#ff44aa', linewidth=0.5, alpha=0.2, linestyle=':') # ===== 7. Y轴标签 ===== ax.text(-1.2, bar_y_pos + depth/2, max_area*0.05, '面积', color='black', fontsize=13, fontweight='bold', ha='right') ax.text(-1.2, line_y_pos, max_area*0.05, '占比', color='black', fontsize=13, fontweight='bold', ha='right') # ===== 8. Z轴刻度 ===== ax.set_zlim(0, max_area * 1.2) # 面积刻度(黑色,步长5,从0到50) z_ticks_area = np.arange(0, 51, 5) ax.set_zticks(z_ticks_area) ax.set_zticklabels([f'{int(v)}' for v in z_ticks_area], color='black', fontsize=9) # 占比刻度(粉色):10%, 20%, 30%, 40%, 50% pct_ticks = np.arange(10, 51, 10) # 10, 20, 30, 40, 50 pct_z_positions = max_area * (pct_ticks / 100) * scale_factor for pct_val, z_pos in zip(pct_ticks, pct_z_positions): ax.plot([-0.3, 0], [line_y_pos, line_y_pos], [z_pos, z_pos], color='black', linewidth=1.5, alpha=0.7) ax.text(-0.5, line_y_pos, z_pos, f'{pct_val:.0f}%', color='black', fontsize=8, ha='right', va='center') # ===== 9. X轴美化 ===== tick_step = max(1, n // 20) ax.set_xticks(x_pos[::tick_step]) ax.set_xticklabels([f'{intervals[i]:.1f}' for i in range(0, n, tick_step)], rotation=45, color='black', fontsize=9) ax.set_xlabel('NDVI', fontsize=14, color='black', fontweight='bold', labelpad=10) # Y轴隐藏 ax.set_ylabel('') ax.set_yticks([]) ax.spines['left'].set_visible(False) # ===== 关键修改:Z轴标签字体大小为0 ===== ax.set_zlabel('', fontsize=0) # 字体大小为0,彻底看不见 ax.tick_params(colors='black', labelsize=10) ax.xaxis.label.set_color('black') ax.spines['bottom'].set_color('#aaaaaa') ax.spines['right'].set_color('#aaaaaa') # ===== 关掉所有网格,然后手动加 X 和 Y 方向的网格线 ===== ax.grid(False) # X方向网格线(竖直线,在底部z=0平面上) for x in x_pos[::tick_step]: ax.plot([x, x], [-0.5, 1.0], [0, 0], color='#cccccc', linewidth=0.3, alpha=0.5, linestyle='--') # Y方向网格线(水平线,在底部z=0平面上) for y in [-0.3, 0.6]: ax.plot([0, n-1], [y, y], [0, 0], color='#cccccc', linewidth=0.3, alpha=0.5, linestyle='--') # ===== 10. 视角 ===== ax.view_init(elev=30, azim=-55) # # ===== 11. 标题和图例 ===== # ax.set_title('作业前后面积与占比 3D立体对比图谱', fontsize=22, fontweight='bold', # color='black', pad=30) from matplotlib.patches import Patch legend_elements = [ Patch(facecolor='#B8A9C9', alpha=0.5, label='作业前面积'), Patch(facecolor='#00aaff', alpha=0.6, label='作业后面积'), Patch(facecolor='#B8A9C9', alpha=0.8, label='作业前占比'), Patch(facecolor='#00aaff', alpha=0.8, label='作业后占比') ] ax.legend(handles=legend_elements, loc='upper left', fontsize=11, facecolor='white', edgecolor='black', labelcolor='black', framealpha=0.9) plt.show()


浙公网安备 33010602011771号