/
obuxxxov
/
CodeForge
Обзор
Документация
Войти
/
obuxxxov
/
CodeForge
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
comb
visual/excel_radar_plot.py
136 строк
5 KB
ObliInSe
сборка прошла, теперь тютора делаю
18 авг 2025, 00:54
18 авг 2025, 00:54
dde10a9
Код
Авторство
О чём код?
import os import json import pandas as pd import plotly.graph_objects as go def load_and_aggregate(excel_path: str) -> pd.DataFrame: df = pd.read_excel(excel_path) required_cols = [ 'Блок', 'Компетенция', 'Оценка', 'Оценка Тимлида', 'Оценка AI', ] for col in required_cols: if col not in df.columns: raise ValueError(f"Отсутствует обязательная колонка: {col}") # Приводим числовые колонки for col in ['Оценка', 'Оценка Тимлида', 'Оценка AI']: df[col] = pd.to_numeric(df[col], errors='coerce') # Метрики по блокам agg = df.groupby('Блок').agg( Сумма_Оценка=('Оценка', 'sum'), Сумма_Оценка_Тимлида=('Оценка Тимлида', 'sum'), Сумма_Оценка_AI=('Оценка AI', 'sum'), ).reset_index() # Калиброванная оценка блока: (сумма Оценка + сумма Оценка Тимлида + сумма Оценка AI) / 3 agg['Среднее_калиброванное'] = ( agg['Сумма_Оценка'] + agg['Сумма_Оценка_Тимлида'] + agg['Сумма_Оценка_AI'] ) / 3 # Порядок осей радара agg = agg.sort_values('Блок') return agg def build_radar(agg: pd.DataFrame, html_out: str, png_out: str | None = None) -> None: categories = agg['Блок'].tolist() # Для замкнутого радара добавим первую категорию в конец для каждого трейса def closed(values): return values + values[:1] cat_closed = categories + categories[:1] fig = go.Figure() fig.add_trace(go.Scatterpolar( r=closed(agg['Сумма_Оценка'].tolist()), theta=cat_closed, fill='toself', name='Сумма: Оценка', opacity=0.25 )) fig.add_trace(go.Scatterpolar( r=closed(agg['Сумма_Оценка_Тимлида'].tolist()), theta=cat_closed, fill='toself', name='Сумма: Оценка Тимлида', opacity=0.25 )) fig.add_trace(go.Scatterpolar( r=closed(agg['Сумма_Оценка_AI'].tolist()), theta=cat_closed, fill='toself', name='Сумма: Оценка AI', opacity=0.25 )) fig.add_trace(go.Scatterpolar( r=closed(agg['Среднее_калиброванное'].tolist()), theta=cat_closed, name='Средняя калиброванная', line=dict(width=3) )) # Подписи, сетка и видимость max_r = max( agg['Сумма_Оценка'].max(), agg['Сумма_Оценка_Тимлида'].max(), agg['Сумма_Оценка_AI'].max(), agg['Среднее_калиброванное'].max(), ) fig.update_layout( title='Профиль компетенций по блокам', polar=dict( radialaxis=dict(visible=True, range=[0, max_r * 1.1]), angularaxis=dict(direction='clockwise') ), legend=dict(orientation='h', yanchor='bottom', y=-0.15, xanchor='center', x=0.5), margin=dict(l=40, r=40, t=60, b=80), template='plotly_white' ) fig.write_html(html_out, include_plotlyjs='cdn') if png_out: try: fig.write_image(png_out, scale=2) except Exception as exc: print(f"Не удалось сохранить PNG через kaleido: {exc}") def export_json_for_frontend(agg: pd.DataFrame, json_out_path: str) -> None: data = { "blocks": agg['Блок'].tolist(), "metrics": { "sum_score": agg['Сумма_Оценка'].tolist(), "sum_lead": agg['Сумма_Оценка_Тимлида'].tolist(), "sum_ai": agg['Сумма_Оценка_AI'].tolist(), "calibrated_avg": agg['Среднее_калиброванное'].tolist(), }, } with open(json_out_path, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) def main(): excel_path = os.path.join( os.path.dirname(os.getcwd()), 'analyzer', 'graph_matrix.xlsx', ) agg = load_and_aggregate(excel_path) build_radar(agg, html_out='radar_plot.html', png_out='radar_plot.png') # Экспорт для фронтенда public_dir = os.path.join(os.getcwd(), 'public') os.makedirs(public_dir, exist_ok=True) json_out = os.path.join(public_dir, 'competency_agg.json') export_json_for_frontend(agg, json_out) print('Готово: radar_plot.html, radar_plot.png и public/competency_agg.json') if __name__ == '__main__': main()