合并达成度功能

This commit is contained in:
2025-05-20 18:30:00 +08:00
parent 8d063fd08a
commit 0a9bd74d8e
20 changed files with 14934 additions and 47 deletions

View File

@@ -1,5 +1,185 @@
import os
import sys
import io
import matplotlib
from matplotlib import pyplot as plt
import re
def format_ranges(nums):
"""格式化区间,支持特殊标记"""
if not nums:
return ""
def parse_value(val):
"""解析值,返回主数值和次要标记"""
if isinstance(val, int):
return val, ""
match = re.match(r"(\d+)[(](.*?)[)]", str(val))
if match:
return int(match.group(1)), match.group(2)
return int(val), ""
# 排序规则:主数值优先,次要标记其次
sorted_nums = sorted(nums, key=lambda x: parse_value(x))
result = []
start = sorted_nums[0]
end = sorted_nums[0]
def is_continuous(val1, val2):
"""判断两个值是否连续"""
main1, sub1 = parse_value(val1)
main2, sub2 = parse_value(val2)
# 主数值连续,且次要标记为空(特殊标记视为不连续)
return main2 == main1 + 1 and not sub2
for i in range(1, len(sorted_nums)):
if is_continuous(end, sorted_nums[i]):
end = sorted_nums[i]
else:
# 处理一个区间
if parse_value(start)[0] == parse_value(end)[0]: # 单值或特殊标记
result.append(str(start))
elif parse_value(end)[0] - parse_value(start)[0] >= 2: # 连续区间
result.append(f"{parse_value(start)[0]}~{parse_value(end)[0]}")
else: # 非连续的单值
result.extend(map(str, [start, end]))
start = end = sorted_nums[i]
# 添加最后一段区间
if parse_value(start)[0] == parse_value(end)[0]: # 单值或特殊标记
result.append(str(start))
elif parse_value(end)[0] - parse_value(start)[0] >= 2: # 连续区间
result.append(f"{parse_value(start)[0]}~{parse_value(end)[0]}")
else: # 非连续的单值
result.extend(map(str, [start, end]))
return "".join(result)
def support_version_str(lst: list[str]) -> str:
"""支持的版本字符串"""
if len(lst) == 1:
return lst[0]
elif len(lst) == 2:
return f"{lst[0]}{lst[1]}"
else:
return f"{lst[0]}~{lst[-1]}"
def get_rank(score: int | float) -> str:
"""根据分数获取等级"""
if score >= 0.9:
return "优秀"
elif score >= 0.8:
return "良好"
elif score >= 0.7:
return "中等"
elif score >= 0.6:
return "及格"
else:
return "不及格"
def min_score_people_name(data: list, kpi_number: int, start_index: int, end_index: int) -> list[tuple[str]]:
"""获取最低分人名"""
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13
# 20060510XX 覃XX 40.5 45 49 0.738 16 17 0 0.330 24.5 15 14 0.695
remove_indices = [5, 9, 13, 17, 21]
# 更新后的数据
# 0 1 2 3 4 5 6 7 8 9 10
# 20060510XX 覃XX 40.5 45 49 16 17 0 24.5 15 14
index = 2 + kpi_number * 3
updated_data = [[item for j, item in enumerate(row) if j not in remove_indices] for row in data]
result = [(), (), ()]
min_scores = [min(updated_data[start_index:end_index],
key=lambda x: x[index + i] if x[index + i] is not None else 0)[index + i] for i in range(3)]
for row in updated_data[start_index:end_index]:
for i in range(3):
if row[index + i] == min_scores[i]:
result[i] += (row[1],)
return result
def get_class_index_range(lst: list[int], num: int):
"""获取班级的索引范围"""
if num < 0 or num > len(lst):
raise ValueError("OutOfRange")
# 计算前num-1项和加一
first_value = sum(lst[:num])
# 计算前num项和加一
second_value = sum(lst[:num + 1]) if num < len(lst) else "OutOfRange"
return (first_value, second_value)
def check_version(version, compatible_versions):
# 将版本字符串转换为数字列表以便比较
version_nums = [int(v) for v in version.split('.')]
min_version_nums = [int(v) for v in compatible_versions[0].split('.')]
max_version_nums = [int(v) for v in compatible_versions[-1].split('.')]
# 比较版本
if version_nums < min_version_nums:
return False, "不支持低于{}的版本,如需尝试生成请勾选‘关闭兼容性检查’".format(compatible_versions[0])
elif version_nums > max_version_nums:
return True, "版本过高可能会导致兼容性问题"
else:
return True, ""
def gen_picture(data: list[list[str]], kpi_number: int, start_index: int, end_index: int):
# 设置全局字体
matplotlib.rcParams['font.family'] = ['Times New Roman', 'KaiTi']
matplotlib.rcParams['font.size'] = 10
# 将厘米转换为英寸
width_in_inches = 8 * 0.393701
height_in_inches = 6 * 0.393701
# 创建一个图形和三个子图
fig, axs = plt.subplots(1, kpi_number, figsize=(width_in_inches * kpi_number, height_in_inches))
# 遍历每个指定的索引来生成散点图
for ax, index in zip(axs, range(kpi_number)):
# 处理数据
data_indices = [5, 9, 13, 17, 21]
update_data = [[float(item) for j, item in enumerate(row) if j in data_indices] for row in data]
x = [i for i in range(end_index - start_index)]
y = [row[index] for row in update_data[start_index:end_index]]
# 绘制散点图
ax.scatter(x, y, label=f'目标{index + 1}达成值', s=10)
# 添加期望值直线
ax.axhline(y=0.65, color='r', linestyle='-', label='期望值')
# 设置轴标签
ax.set_xlabel('学生学号')
ax.set_ylabel('达成值')
# 设置y轴范围和刻度
ax.set_ylim(0, 1)
ax.set_yticks([i * 0.2 for i in range(6)])
# 设置图例
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.35), ncol=2, frameon=False)
# 设置坐标原点为(0, 0)
ax.set_xlim(x.index(x[0]), None)
# 调整子图间距
plt.tight_layout()
# 创建一个内存中的文件对象
buf = io.BytesIO()
# 保存图形
plt.savefig(buf, format='png', dpi=300, bbox_inches='tight')
# 将文件对象转换为字节对象
res = buf.getvalue()
buf.close()
return res
if __name__ == '__main__':
nums = [1, 2, 3, '4(1)', '42']
formatted_ranges = format_ranges(nums)
print(formatted_ranges)
def resource_path(relative_path: str) -> str: