# -*- coding: utf-8 -*- import matplotlib matplotlib.use("agg") import matplotlib.pyplot as plt import numpy as np import os from datetime import datetime from matplotlib.font_manager import FontProperties # # 数据 # data = { # "停电用户\n(万户)": {"昨天": 200.87, "今天": 132.59}, # "过载配变\n(台)": {"昨天": 126, "今天": 119}, # "95598供电类投诉\n(条)": {"昨天": 18, "今天": 12}, # "涉电力供应类舆情风险信息\n(条)": {"昨天": 79, "今天": 40} # } def plot_electricity_comparison(year, month, day, data): year = int(year) month = int(month) day = int(day) # # 设置中文字体 plt.rcParams["font.sans-serif"] = [ "Microsoft YaHei" ] # 字体设置,用来正常显示中文标签 plt.rcParams["axes.unicode_minus"] = False # 用来正常显示负号 # # 创建一个大图形,1行4列的子图布局 # fig, axs = plt.subplots(1, 4, figsize=(8, 4)) # 1行4列的子图布局 # 定义横轴标签 categories = ["昨天", "今天"] x = np.arange(len(categories)) # 计算变化百分比 def calculate_change_percentage(yesterday, today): return ((today - yesterday) / yesterday) * 100 # 检查数据完整性并过滤掉不完整的数据 valid_data = {} for title, values in data.items(): if "昨天" in values and "今天" in values: if values["昨天"] is not None and values["今天"] is not None: valid_data[title] = values # 如果没有有效的数据,返回 None 或其他指示 if not valid_data: return None # 没有有效的数据,不生成图片 # 根据有效数据的数量动态创建子图布局 num_valid_data = len(valid_data) fig, axs = plt.subplots( 1, num_valid_data, figsize=(2 * num_valid_data, 4) ) # 动态调整布局 # 如果只有一个子图,axs 是一个单个的 Axes 对象而不是数组,需要将其转换为列表 if num_valid_data == 1: axs = [axs] # 绘制每个子图 for i, (title, values) in enumerate(valid_data.items()): ax = axs[i] # 获取当前子图 y = list(values.values()) # 将蓝色柱子改为暗蓝色 bars = ax.bar(x, y, color=["#1E3A8A", "#FF8C00"], width=0.6) # 设置子图标题和坐标轴标签 ax.set_title( title, fontsize=12, fontweight="bold", color="#00008B" ) # 设置标题字体加粗深蓝色 # 设置坐标轴标签字体加粗深蓝色 ax.set_xticks(x) ax.set_xticklabels(categories, fontsize=10, fontweight="bold", color="#00008B") # 动态设置纵坐标范围 max_y = max(y) * 1.2 # 增加20%的范围 ax.set_ylim(0, max_y) # 隐藏纵轴刻度线 ax.tick_params(axis="y", length=0) ax.tick_params(axis="x", length=0) # 添加自定义的淡颜色细长分割线 for y_tick in ax.get_yticks(): ax.axhline(y=y_tick, color="#87CEEB", linestyle="--", alpha=0.3) # 设置刻度标签字体加粗深蓝色 ax.tick_params(axis="y", labelsize=12, labelcolor="#00008B") # 添加数据标签 for bar in bars: height = bar.get_height() # 根据柱子颜色设置数据标签颜色 if bar == bars[0]: color = "#1E3A8A" # 暗蓝色 else: color = "#FF8C00" # 暗橙色 ax.text( bar.get_x() + bar.get_width() / 2, height, f"{height}", ha="center", va="bottom", fontsize=10, fontweight="bold", color=color, ) # 添加变化百分比和箭头 change_percent = calculate_change_percentage(y[0], y[1]) # 根据变化百分比设置符号和颜色 if change_percent < 0: symbol = "\u25bc" # 倒三角 color = "#006400" # 深绿色 # 调整箭头起始点和终点位置:从柱子的边角开始指向边角 bar0_height = bars[0].get_height() bar1_height = bars[1].get_height() ax.annotate( "", xy=(x[1] - bars[1].get_width() / 2+0.1, bar1_height), #xy=(x[1], bar1_height), #xytext=((x[0] + bars[0].get_width() / 2) + 0.05, bar0_height * 0.95), xytext=((x[0] + bars[0].get_width() / 2), bar0_height), arrowprops=dict( arrowstyle="-|>", mutation_scale=20, # 箭头大小 connectionstyle="arc3,rad=-0.4", # 调整为负值,箭头凸起 color="#FFD580", linewidth=3, capstyle='round', joinstyle='round' ), ) # 浅橙色箭头,加粗 # 在子图中间显示变化百分比 ax.text( 0.5, 0.9, f"{symbol}{abs(change_percent):.2f}%", ha="center", va="center", transform=ax.transAxes, fontsize=12, fontweight="bold", color=color, ) elif change_percent > 0: symbol = "\u25b2" # 正三角 color = "#FF0000" # 红色 # 调整箭头起始点和终点位置:从柱子的边角开始指向边角 bar0_height = bars[0].get_height() bar1_height = bars[1].get_height() ax.annotate( "", #xy=(x[1] - bars[1].get_width() / 2, bar1_height), xy=(x[1] - bars[1].get_width() / 2, bar1_height), #xytext=((x[0] + bars[0].get_width() / 2) + 0.05, bar0_height), xytext=((x[0] + bars[0].get_width() / 2), bar0_height), arrowprops=dict( arrowstyle="-|>", mutation_scale=20, # 箭头大小 connectionstyle="arc3,rad=0.4", # 调整为负值,箭头凸起 color="#FFD580", linewidth=3, ), ) # 浅橙色箭头,加粗 # 在子图中间显示变化百分比 ax.text( 0.5, 0.9, f"{symbol}{abs(change_percent):.2f}%", ha="center", va="center", transform=ax.transAxes, fontsize=12, fontweight="bold", color=color, ) else: symbol = "" color = "#FFA500" # 橙色 # 调整箭头起始点和终点位置:从柱子的边角开始指向边角 bar0_height = bars[0].get_height() bar1_height = bars[1].get_height() ax.annotate( "", xy=(x[1] - bars[1].get_width() / 2+0.1, bar1_height), xytext=((x[0] + bars[0].get_width() / 2), bar0_height), arrowprops=dict( arrowstyle="-|>", mutation_scale=20, # 箭头大小 connectionstyle="arc3,rad=0", # 调整为负值,箭头凸起 color="#FFD580", linewidth=3, ), ) # 浅橙色箭头,加粗 # 在子图中间显示变化百分比 ax.text( 0.5, 0.9, f"持平", ha="center", va="center", transform=ax.transAxes, fontsize=12, fontweight="bold", color=color, ) # 调整子图间距 plt.subplots_adjust(wspace=0) # 进一步减小子图之间的水平间距 plt.tight_layout(rect=[0, 0, 1, 0.95]) # 调整整体布局 # 获取当前脚本的绝对路径 current_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.dirname(os.path.dirname(current_dir)) # 创建 temp_picture 目录 temp_picture_dir = os.path.join(project_root, "temp_picture") if not os.path.exists(temp_picture_dir): os.makedirs(temp_picture_dir) # 按年月创建子目录 month_dir = os.path.join(temp_picture_dir, f"{year}{month:02d}") if not os.path.exists(month_dir): os.makedirs(month_dir) # 保存图形到指定目录 file_name = f"电力供应数据变化对比{year}{month:02d}{day:02d}.png" file_path = os.path.join(month_dir, file_name) plt.savefig(file_path, dpi=1200, bbox_inches="tight") return file_path # # 显示图形 # plt.show() # plot_electricity_comparison(data)