Files
JITToolBox/utils/function.py
2025-05-20 18:30:00 +08:00

191 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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:
if hasattr(sys, '_MEIPASS'):
base_path = sys._MEIPASS
else:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)