Merge commit '47296980495f8bbfc9493e93de85dd62de6fa6b9' as 'paste-framework'

This commit is contained in:
zwf
2026-06-02 19:09:22 +08:00
107 changed files with 21484 additions and 0 deletions
@@ -0,0 +1,153 @@
import numpy as np
import os
import traceback
from paste.chart.bar import (
gen_vertical_bars,
gen_horizontal_stacked_bars,
gen_percent_stacked_bars
)
class ChartBarExample:
"""
图表测试管理器:封装对 paste.chart.bar 中三个函数的调用。
不修改任何参数结构,仅提供清晰的调用封装与输出管理。
"""
def __init__(self, output_directory="./charts"):
"""
初始化测试器,定义所有测试数据。
数据结构完全匹配原始函数调用方式。
"""
self.output_directory = output_directory
os.makedirs(self.output_directory, exist_ok=True)
# 纵向堆叠柱形图数据(直接对应 gen_vertical_bars 参数)
self.primary_vals = [10, 20, 15, 25, 18]
self.nested_vals = [5, 8, 3, 10, 6]
self.x_labels_vert = ['产品1', '产品2', '产品3', '产品4', '产品5']
self.group_labels_vert = ['销售量', '退货量']
# 横向堆叠柱形图数据(直接对应 gen_horizontal_stacked_bars 参数)
self.data_matrix = np.array([
[10, 20, 15],
[15, 12, 18],
[8, 16, 10],
[12, 14, 13]
])
self.x_labels_hori = ['线上销售', '门店销售', '批发销售']
self.y_labels_hori = ['北京', '上海', '广州', '深圳']
self.y_data_unit_hori = '万元'
self.title_hori = '销售构成'
# 百分比堆叠柱形图数据(直接对应 gen_percent_stacked_bars 参数)
self.data_percent = {
'A组': [10, 20, 15, 18],
'B组': [5, 10, 5, 8],
'C组': [3, 7, 10, 4]
}
self.x_labels_percent = ['Q1', 'Q2', 'Q3', 'Q4']
self.title_percent = '季度占比'
def generate_vertical_bars(self) -> str:
"""调用 gen_vertical_bars,参数完全一致"""
try:
return gen_vertical_bars(
self.primary_vals,
self.nested_vals,
self.x_labels_vert,
self.group_labels_vert
)
except Exception as e:
print(f"纵向堆叠柱形图生成失败: {e}")
traceback.print_exc()
raise
def generate_horizontal_stacked_bars(self) -> str:
"""调用 gen_horizontal_stacked_bars,参数完全一致"""
try:
return gen_horizontal_stacked_bars(
self.data_matrix,
self.x_labels_hori,
self.y_labels_hori,
self.y_data_unit_hori,
self.title_hori
)
except Exception as e:
print(f"横向堆叠柱形图生成失败: {e}")
traceback.print_exc()
raise
def generate_percent_stacked_bars(self) -> str:
"""调用 gen_percent_stacked_bars,参数完全一致"""
try:
return gen_percent_stacked_bars(
self.data_percent,
self.x_labels_percent,
self.title_percent
)
except Exception as e:
print(f"百分比堆叠柱形图生成失败: {e}")
traceback.print_exc()
raise
def save_svg(self, svg_data: str, filename: str) -> None:
"""
将 SVG 的 base64 Data URL 写入文件(保留原始 SVG 格式)。
注意:svg_data 是 "data:image/svg+xml;base64,...",需提取真实 SVG 内容。
"""
if not svg_data or not isinstance(svg_data, str):
print(f"生成的 SVG 数据无效(为空或非字符串): {filename}")
return
# 提取 base64 编码部分(去除 data URL 前缀)
if svg_data.startswith("data:image/svg+xml;base64,"):
base64_content = svg_data[len("data:image/svg+xml;base64,"):]
try:
# 解码 base64 得到原始 SVG 字符串
import base64
svg_content = base64.b64decode(base64_content).decode('utf-8')
except Exception as e:
print(f"解码 base64 失败: {e}")
svg_content = svg_data # 退化为直接写入
else:
# 如果不是标准格式,直接写入(兼容调试)
svg_content = svg_data
filepath = os.path.join(self.output_directory, filename)
with open(filepath, 'w', encoding='utf-8') as f:
f.write(svg_content)
print(f"已保存: {filepath}")
def run(self) -> None:
"""按顺序执行所有图表生成与保存"""
print("开始生成图表...")
try:
print("生成纵向堆叠柱形图...")
svg1 = self.generate_vertical_bars()
self.save_svg(svg1, "vertical_bars.svg")
print("生成横向堆叠柱形图...")
svg2 = self.generate_horizontal_stacked_bars()
self.save_svg(svg2, "horizontal_stacked_bars.svg")
print("生成百分比堆叠柱形图...")
svg3 = self.generate_percent_stacked_bars()
self.save_svg(svg3, "percent_stacked_bars.svg")
print("\n所有图表已成功生成。")
print(f"输出目录: {self.output_directory}")
print("文件列表:")
print(" - vertical_bars.svg")
print(" - horizontal_stacked_bars.svg")
print(" - percent_stacked_bars.svg")
except Exception as e:
print(f"\n测试失败: {e}")
traceback.print_exc()
# 程序入口
if __name__ == "__main__":
tester = ChartBarExample()
tester.run()
@@ -0,0 +1,110 @@
import os
import traceback
from paste.chart.pie import gen_pie
class ChartPieExample:
"""
环形图测试管理器:封装对 paste.chart.pie.gen_pie 的调用。
数据结构严格匹配函数参数要求,支持扩展更多测试用例。
"""
def __init__(self, output_directory="./charts"):
"""
初始化测试器,定义所有测试数据。
数据结构完全匹配 gen_pie 函数的参数要求。
"""
self.output_directory = output_directory
os.makedirs(self.output_directory, exist_ok=True)
# 构造符合 gen_pie 要求的 DataFrame 数据(模拟真实业务场景)
# 假设业务场景:网络设备统计(服务器、交换机、路由器等)
import pandas as pd
self.data_df = pd.DataFrame({
'device_count': [35, 28, 22, 15, 10], # value_column
'percentage': ['35.2%', '28.1%', '22.0%', '15.0%', '9.7%'], # percentage_column
'device_type': ['服务器', '交换机', '路由器', '防火墙', 'AP'] # legend_labels
})
# 测试参数
self.value_column = 'device_count'
self.percentage_column = 'percentage'
self.legend_labels = 'device_type'
self.color_palette = 'BuPu' # 可尝试 'viridis', 'Set3', 'plasma'
self.dpi = 128
# 输出文件名
self.filename = "pie_chart.svg"
def generate_pie_chart(self) -> str:
"""
调用 gen_pie 函数,参数完全一致。
注意:gen_pie 接收的是 pandas.DataFrame,不是列表。
"""
try:
svg_data = gen_pie(
data_df=self.data_df,
value_column=self.value_column,
percentage_column=self.percentage_column,
legend_labels=self.legend_labels,
color_palette=self.color_palette,
dpi=self.dpi
)
if not svg_data or not isinstance(svg_data, str):
raise ValueError("gen_pie 返回的 SVG 数据为空或类型错误")
return svg_data
except Exception as e:
print(f"环形图生成失败: {e}")
traceback.print_exc()
raise
def save_svg(self, svg_data: str, filename: str) -> None:
"""
将 SVG 的 base64 Data URL 写入文件(保留原始 SVG 格式)。
注意:svg_data 是 "data:image/svg+xml;base64,...",需提取真实 SVG 内容。
"""
if not svg_data or not isinstance(svg_data, str):
print(f"生成的 SVG 数据无效(为空或非字符串): {filename}")
return
# 提取 base64 编码部分(去除 data URL 前缀)
if svg_data.startswith("data:image/svg+xml;base64,"):
base64_content = svg_data[len("data:image/svg+xml;base64,"):]
try:
# 解码 base64 得到原始 SVG 字符串
import base64
svg_content = base64.b64decode(base64_content).decode('utf-8')
except Exception as e:
print(f"解码 base64 失败: {e}")
svg_content = svg_data # 退化为直接写入
else:
# 如果不是标准格式,直接写入(兼容调试)
svg_content = svg_data
filepath = os.path.join(self.output_directory, filename)
with open(filepath, 'w', encoding='utf-8') as f:
f.write(svg_content)
print(f"已保存: {filepath}")
def run(self) -> None:
"""按顺序执行图表生成与保存"""
print("开始生成环形图...")
try:
print("正在生成环形图...")
svg_data = self.generate_pie_chart()
self.save_svg(svg_data, self.filename)
print(f"\n环形图已成功生成。")
print(f"输出目录: {self.output_directory}")
print(f"文件列表:")
print(f" - {self.filename}")
except Exception as e:
print(f"\n测试失败: {e}")
traceback.print_exc()
# 程序入口
if __name__ == "__main__":
tester = ChartPieExample()
tester.run()
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Charts</title>
</head>
<body>
<img src="./horizontal_stacked_bars.svg" alt="">
<img src="./lines.svg" alt="">
<img src="./percent_stacked_bars.svg" alt="">
<img src="./pie_chart.svg" alt="">
<img src="./splines.svg" alt="">
<img src="./vertical_bars.svg" alt="">
</body>
</html>
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 50 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 37 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 30 KiB

@@ -0,0 +1,124 @@
import pandas as pd
import os
from paste.chart.line import gen_lines, gen_splines
class LineChartExample:
"""
折线图与平滑曲线测试管理器。
封装 gen_lines 和 gen_splines 的调用,统一输出管理。
"""
def __init__(self, output_directory="./charts"):
"""
初始化测试器,定义所有测试数据。
使用 'ME' 替代 'M' 以兼容 pandas >=2.0。
"""
self.output_directory = output_directory
os.makedirs(self.output_directory, exist_ok=True)
# =========================
# gen_lines 测试数据(使用 'ME' 替代废弃的 'M'
# =========================
# 时间序列数据:3个年份,每月最后一个交易日(12个月)
dates_2022 = pd.date_range('2022-01-01', periods=12, freq='ME')
dates_2023 = pd.date_range('2023-01-01', periods=12, freq='ME')
dates_2024 = pd.date_range('2024-01-01', periods=12, freq='ME')
self.data_dict_lines = {
'2022': pd.Series([100 + i * 2 for i in range(12)], index=dates_2022),
'2023': pd.Series([110 + i * 1.5 for i in range(12)], index=dates_2023),
'2024': pd.Series([120 + i * 1 for i in range(12)], index=dates_2024),
}
self.color_palette_lines = 'BuPu'
self.dpi_lines = 128
# =========================
# gen_splines 测试数据(数值索引,无频率问题)
# =========================
self.data_dict_splines = {
'A组': pd.Series([10, 15, 12, 18, 16], index=[0, 1, 2, 3, 4]),
'B组': pd.Series([12, 14, 13, 17, 15], index=[0, 1, 2, 3, 4]),
'C组': pd.Series([8, 20, 10, 22, 11], index=[0, 1, 2, 3, 4]),
}
self.total_splines = pd.Series({
'A组': 71,
'B组': 71,
'C组': 71
})
self.color_palette_splines = 'viridis'
self.dpi_splines = 128
self.smooth_points = 100
self.spline_k = 3
self.markevery = 30
def generate_lines(self) -> str:
"""调用 gen_lines,参数顺序完全匹配原始函数"""
return gen_lines(
self.data_dict_lines,
self.color_palette_lines,
self.dpi_lines
)
def generate_splines(self) -> str:
"""调用 gen_splines,参数顺序完全匹配原始函数"""
return gen_splines(
self.data_dict_splines,
self.total_splines,
None,
self.color_palette_splines,
self.dpi_splines
)
def save_svg(self, svg_data: str, filename: str) -> None:
"""
将 SVG 的 base64 Data URL 写入文件(保留原始 SVG 格式)。
注意:svg_data 是 "data:image/svg+xml;base64,...",需提取真实 SVG 内容。
"""
if not svg_data or not isinstance(svg_data, str):
print(f"生成的 SVG 数据无效(为空或非字符串): {filename}")
return
# 提取 base64 编码部分(去除 data URL 前缀)
if svg_data.startswith("data:image/svg+xml;base64,"):
base64_content = svg_data[len("data:image/svg+xml;base64,"):]
try:
# 解码 base64 得到原始 SVG 字符串
import base64
svg_content = base64.b64decode(base64_content).decode('utf-8')
except Exception as e:
print(f"解码 base64 失败: {e}")
svg_content = svg_data # 退化为直接写入
else:
# 如果不是标准格式,直接写入(兼容调试)
svg_content = svg_data
filepath = os.path.join(self.output_directory, filename)
with open(filepath, 'w', encoding='utf-8') as f:
f.write(svg_content)
print(f"已保存: {filepath}")
def run(self) -> None:
"""按顺序生成并保存所有图表"""
print("生成折线图...")
svg1 = self.generate_lines()
self.save_svg(svg1, "lines.svg")
print("生成平滑曲线图...")
svg2 = self.generate_splines()
self.save_svg(svg2, "splines.svg")
print("\n所有图表已生成。")
print(f"输出目录: {self.output_directory}")
print("文件列表:")
print(" - lines.svg")
print(" - splines.svg")
# 程序入口
if __name__ == "__main__":
tester = LineChartExample()
tester.run()