diff --git a/app.py b/app.py index 1d88f4d..6808d10 100644 --- a/app.py +++ b/app.py @@ -1,831 +1,839 @@ -from flask import Flask, render_template, request, send_from_directory, redirect, url_for -from werkzeug.utils import secure_filename -from math import * -import os -import pandas as pd -import plotly.express as px -import plotly.io as pio -import plotly.graph_objects as go -from plotly.subplots import make_subplots -import numpy as np -import shutil - -app = Flask(__name__, static_folder='static') -os.chdir(os.path.dirname(__file__)) -app.config['UPLOAD_FOLDER'] = 'uploads' -app.config['DOWNLOAD_FOLDER'] = 'downloads' -app.config['ALLOWED_EXTENSIONS'] = {'xlsm','xlsx'} - -VRP_MO=[4206.506,4290.2613,4644.635,5196.1364,5406.0765,6809.9511,7720.8426]#2016 2017 2018 2019 2020 2021 2022 - -def sankey(table): - year=table.iloc[0,10] - table = table.iloc[2:].reset_index(drop=True) - names = table.iloc[:,0].head(20).tail(18).tolist()+['Баланс'] - b= len(names) - 1 - v = table.iloc[:,11].head(20).tail(18).astype('str').str.replace('-','').tolist() - v[6]=str(round(table.iloc[8,9],2)) - v[7]=str(round(table.iloc[9,10],2)) - names[0]='Производство' - names[1]='Импорт' - names[4]='Потр. первичной энергии' - names[5]='Стат. расхождение' - names[7]='Производство ТЭ' - names[10]='Потери' - names[11]='Преобр. топлива' - names[17]='Конечное потр.' - names[-1]+=' ' + str(round((float(v[0])+float(v[1]))/1000,2)) - for i in range(len(names)-1): - names[i]+=' '+str(round(float(v[i])/1000,2)) - fig = go.Figure(data=[go.Sankey( - arrangement = "snap", - node = dict( - pad = 15, - thickness = 10, - line = dict(color = "black", width = 1), - label = names, - x = [0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.4], # 0 пэр 1 ввоз 2 вывоз 3 изм зап 4 ппэ 5 стат расх 6 произв ээ 7 произв тэ 8 преобр топ 9 соб нуж 10 потери 11 кп 12 бал - y = [0.8, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], - ), - link = dict( - source = [0, 1, b, b, b, 4, 4, 4,4,4,4,4], - target = [b, b, 2, 3, 4, 5, 6, 7,11,15,16,17], - value = [v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[11],v[15],v[16],v[17]] - ))]) - fig.update_layout( - title={ - 'text': "Структура первичного потребления ТЭР за "+year, - 'y':0.9, - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - font=dict( - family="Arial, sans-serif", - size=12 - ) - ) - return fig - -def sankey2(table): - names =['Производство', 'Импорт','Доступно из всех ист.','Прямой перенос','Трансф.','Транф. убытки','Доступно после трансф.','Транзит','Конечное потр.'] - year=table.iloc[0,10] - table = table.iloc[2:].reset_index(drop=True) - v = table[11].head(20).tail(18).astype('str').str.replace('-','').tolist() - v = [eval(i) for i in v] - vDop= [int(table[4][19]),int(table[5][19]),int(table[9][19]),int(table[10][19])] - val = [v[0], v[1], vDop[1]+v[2], v[6]+v[7]+v[11]+v[15]+v[16] + vDop[0]+vDop[2]+vDop[3], vDop[1]+v[2], v[6]+v[7]+v[11]+v[15]+v[16], vDop[0]+vDop[2]+vDop[3], v[2], v[17]] - names[0]+=' '+ str(round(float(val[0])/1000,2)) - names[1]+=' '+ str(round(float(val[1])/1000,2)) - names[2]+=' '+ str(round((float(val[0])+float(val[1]))/1000,2)) - names[3]+=' '+ str(round(float(val[4])/1000,2)) - names[4]+=' '+ str(round(float(val[3])/1000,2)) - names[5]+=' '+ str(round(float(val[5])/1000,2)) - names[6]+=' '+ str(round((float(val[3])+float(val[4])-float(val[5]))/1000,2)) - names[7]+=' '+ str(round(float(val[7])/1000,2)) - names[8]+=' '+ str(round(float(val[8])/1000,2)) - fig = go.Figure(data=[go.Sankey( - arrangement = "snap", - node = dict( - pad = 15, - thickness = 10, - line = dict(color = "black", width = 1), - label = names, - x = [0.2, 0.2, 0.3, 0.5, 0.5, 0.65, 0.65, 0.85, 0.85], - y = [0.1, 0.1, 0.1, 0.1, 0.4, 0.8, 0.1, 0.1, 0.45], - ), - link = dict( - source = [0, 1, 2, 2, 3, 4, 4, 6, 6], - target = [2, 2, 3, 4, 6, 5, 6, 7, 8], - value = val - ))]) - fig.update_layout( - title={ - 'text': "Пропорции ТЭБ "+year, - 'y':0.9, - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - font=dict( - family="Arial, sans-serif", - size=12 - ) - ) - return fig - -def piePPE(table): # потребление первичной энергии - year=table.iloc[0,10] - table = table.iloc[2:].reset_index(drop=True) - labels = table.iloc[0].to_list()[2:11] - values = table.iloc[6].values.tolist()[2:11] - fig = go.Figure(data=[go.Pie(labels=labels,values=values)]) - fig.update_layout( - title={ - 'text': "Потребление первичной энергии за "+year, - 'y':0.9, - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - font=dict( - family="Arial, sans-serif", - size=18 - )) - return fig - -def pieKP(table): # конечное потребление - year=table.iloc[0,10] - table = table.iloc[2:].reset_index(drop=True) - labels = table.iloc[0].to_list()[2:11] - values = table.iloc[19].values.tolist()[2:11] - fig = go.Figure(data=[go.Pie(labels=labels,values=values)]) - fig.update_layout( - title={ - 'text': "Конечное потребление за "+year, - 'y':0.9, - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - font=dict( - family="Arial, sans-serif", - size=18 - ) - ) - return fig - -def barChart(tables): - dataBal=[] - dataPPE=[] - dataKP=[] - for table in tables: - year=table.iloc[0,10] - table = table.iloc[2:].reset_index(drop=True) - dataBal.append([year[:4], int(table.iloc[:,11][2])+int(table.iloc[:,11][3])]) - dataPPE.append([year[:4], int(table.iloc[:,11][6])]) - dataKP.append([year[:4], int(table.iloc[:,11][19])]) - dfBal=pd.DataFrame(dataBal,columns=['Год','Баланс']) - dfPPE=pd.DataFrame(dataPPE,columns=['Год','Потребление первичной энергии']) - dfKP=pd.DataFrame(dataKP,columns=['Год','Конечное потребление']) - figBal =[ - px.bar(dfBal,x='Год',y='Баланс').update_layout( - title={ - 'text': 'Сравнение балансов', - 'y':0.95, - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - font=dict( - family="Arial, sans-serif", - size=18 - ) - ), - px.bar(dfPPE,x='Год',y='Потребление первичной энергии').update_layout( - title={ - 'text': 'Сравнение потребления первичной энергии', - 'y':0.95, - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - font=dict( - family="Arial, sans-serif", - size=18 - ) - ), - px.bar(dfKP,x='Год',y='Конечное потребление').update_layout( - title={ - 'text': 'Сравнение конечного потребления', - 'y':0.95, - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - font=dict( - family="Arial, sans-serif", - size=18 - ) - )] - return figBal - -def parcoordsChart(tables, tables2): - energy_sources = ["Уголь", "Сырая нефть", "Нефтепродукты", "Природный газ", "Твёрдое топливо", "Гидроэнергия", "Атомная энергия", "Электро энергия", "Тепловая энергия"] - energy_sources2 = ["Уголь", 'Дизель', 'Мазут', 'СУГ', 'Природный газ'] - sectors_sources = ['Сельское хозяйство', 'Промышленность', 'Строительство', 'Транспорт', 'Сфера услуг', 'Население'] - - ranges_ppe = [[1, 2500], [0, 3000], [1000, 12000], [20000, 26000], [1, 1100], [100, 300], [0, 300], [3000, 5000], [1000, 1600]] - ranges_ppe2 = [[500,2000], [1000,4100], [0,500], [0,150], [20000,25000]] - ranges_kp = [[0, 3000], [0, 3000], [1000, 10000], [4000, 8000], [0, 1000], [0, 1000], [0, 1000], [4000, 5500], [8000, 11000]] - ranges_ee = [[0, 500], [1500, 2000], [100, 200], [400, 800], [400, 1000],[1000, 1500]] - # Инициализация данных - ppe_data = {source: [] for source in energy_sources} - ppe_data2 = {source: [] for source in energy_sources2} - kp_data = {source: [] for source in energy_sources} - ee_data = {source: [] for source in sectors_sources} - years = [] - colors = [[0, 'red'], [0.5, 'yellow'], [1, 'blue']] - - # Обработка таблиц - for table in tables: - year = table.iloc[0, 10] - years.append(int(year[:4])) - table = table.iloc[2:].reset_index(drop=True) - - for idx, source in enumerate(energy_sources, start=2): - ppe_value = table.iloc[6,idx] if pd.notna(table.iloc[6,idx]) else 0 - kp_value = table.iloc[19,idx] if pd.notna(table.iloc[19,idx]) else 0 - - ppe_data[source].append(int(ppe_value)) - kp_data[source].append(int(kp_value)) - - for i in range(len(sectors_sources)): - if i==0: - ee_data[sectors_sources[i]].append(int(table.iloc[20][9])) - elif i==1: - ee_data[sectors_sources[i]].append(int(table.iloc[21][9])) - elif i==2: - ee_data[sectors_sources[i]].append(int(table.iloc[27][9])) - elif i==3: - ee_data[sectors_sources[i]].append(int(table.iloc[28][9])) - elif i==4: - ee_data[sectors_sources[i]].append(int(table.iloc[33][9])) - elif i==5: - ee_data[sectors_sources[i]].append(int(table.iloc[34][9])) - - for table in tables2: - for i in range(len(energy_sources2)): - if i==0: - ppe_data2[energy_sources2[i]].append(int(table['Уголь'].iloc[6,1])) - elif i==1: - ppe_data2[energy_sources2[i]].append(int(table['Дизель'].iloc[6,1])) - elif i==2: - ppe_data2[energy_sources2[i]].append(int(table['Мазут'].iloc[6,1])) - elif i==3: - ppe_data2[energy_sources2[i]].append(int(table['СУГ'].iloc[6,1])) - elif i==4: - ppe_data2[energy_sources2[i]].append(int(table['Пр-й газ'].iloc[6,1])) - - # Функция для создания графика - def create_figure(data, ranges, title): - dimensions = [dict(tickvals=years, label='Год', values=years)] + [ - dict(range=ranges[idx], - label=source, - values=values, - tickformat=".0f") - for idx, (source, values) in enumerate(data.items()) - ] - fig = go.Figure(data=go.Parcoords( - line=dict(color=years, colorscale=colors), - dimensions=dimensions, - unselected=dict(line=dict(color='green', opacity=1)) - )) - fig.update_layout( - title=dict(text=title, y=0.95, x=0.5, xanchor='center', yanchor='top'), - font=dict(family="Arial, sans-serif", size=18) - ) - return fig - - # Создание графиков - figParPPE = create_figure(ppe_data, ranges_ppe, "Динамика изменения потребления первичной энергии") - figParKP = create_figure(kp_data, ranges_kp, "Динамика изменения конечного потребления") - figParEE = create_figure(ee_data,ranges_ee,'Конечное потребление ЭЭ по секторам экономики') - figParPPE2 = create_figure(ppe_data2,ranges_ppe2, 'Выборочная динамика изменения потребления первичной энергии') - - return [figParPPE, figParPPE2, figParKP, figParEE] - -def heatMapsGeneral(tables): - resources = ['Уголь', 'Нефтепродукты', 'Природный газ', 'Электроэнергия', 'Тепловая энергия'] - years = [] - ppe_data = {resource: [] for resource in resources} - kp_data = {resource: [] for resource in resources} - - # Обработка данных из таблиц - for table in tables: - year = table.iloc[0, 10] - years.append(int(year[:4])) - table = table.iloc[3:].reset_index(drop=True) - # Индексы колонок соответствующих ресурсов - resource_indices = { - 'Уголь': 2, - 'Нефтепродукты': 4, - 'Природный газ': 5, - 'Электроэнергия': 9, - 'Тепловая энергия': 10 - } - for resource, col_idx in resource_indices.items(): - ppe_data[resource].append(round(table.iloc[5, col_idx], 2)) - kp_data[resource].append(round(table.iloc[18, col_idx], 2)) - - # Функция для создания тепловой карты - def create_heatmap(data, title): - values = [data[resource] for resource in resources] - fig = go.Figure(data=go.Heatmap( - z=values, - x=years, - y=resources, - text=values, - texttemplate="%{text}", - colorscale='YlGnBu', - colorbar=dict(title="Потребление") - )) - fig.update_layout( - xaxis_title='Годы', - yaxis_title='Ресурсы', - xaxis=dict(tickvals=years, ticktext=[str(year) for year in years]), - yaxis=dict(tickvals=list(range(len(resources))), ticktext=resources), - title=title - ) - return fig - - # Создание тепловых карт - figPPE = create_heatmap(ppe_data, "Тепловая карта потребления первичной энергии") - figKP = create_heatmap(kp_data, "Тепловая карта конечного потребления энергии") - return [figPPE, figKP] - -def heatMaps(tables): - sectors = ['Сельское хозяйство', 'Промышленность', 'Строительство', 'Транспорт и связь', 'Сфера услуг', 'Население', 'Неэнергетические нужды'][::-1] - resources = ['Уголь', 'Нефтепродукты', 'Природный газ', 'Электроэнергия', 'Тепловая энергия'] - res=[] - for d in tables: - year=d.iloc[0,10] - d = d.iloc[2:].reset_index(drop=True) - value = [ - [round(d.iloc[20, 2], 2), round(d.iloc[20, 4], 2), round(d.iloc[20, 5], 2), round(d.iloc[20, 9], 2), round(d.iloc[20, 10], 2)], - [round(d.iloc[21, 2], 2), round(d.iloc[21, 4], 2), round(d.iloc[21, 5], 2), round(d.iloc[21, 9], 2), round(d.iloc[21, 10], 2)], - [round(d.iloc[27, 2], 2), round(d.iloc[27, 4], 2), round(d.iloc[27, 5], 2), round(d.iloc[27, 9], 2), round(d.iloc[27, 10], 2)], - [round(d.iloc[28, 2], 2), round(d.iloc[28, 4], 2), round(d.iloc[28, 5], 2), round(d.iloc[28, 9], 2), round(d.iloc[28, 10], 2)], - [round(d.iloc[33, 2], 2), round(d.iloc[33, 4], 2), round(d.iloc[33, 5], 2), round(d.iloc[33, 9], 2), round(d.iloc[33, 10], 2)], - [round(d.iloc[34, 2], 2), round(d.iloc[34, 4], 2), round(d.iloc[34, 5], 2), round(d.iloc[34, 9], 2), round(d.iloc[34, 10], 2)], - [round(d.iloc[35, 2], 2), round(d.iloc[35, 4], 2), round(d.iloc[35, 5], 2), round(d.iloc[35, 9], 2), round(d.iloc[35, 10], 2)]][::-1] - value=np.array(value) - fig = go.Figure(data=go.Heatmap( - z=value, - x=resources, - y=sectors, - text=value, # Текстовые метки - texttemplate="%{text}", # Отображение значений в ячейках - colorscale='YlGnBu', - colorbar=dict(title="Потребление") - )) - fig.update_layout( - title={ - 'text':year, - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - xaxis_title='Источники энергии', - yaxis_title='Секторы экономики', - ) - res.append(fig) - return res - -def streamGraph(tables): - sources = ['Расход ТЭР на производство ЭЭ', 'Расход ТЭР на производство ТЭ', 'Расход на преобразование топлива', 'Потери ЭЭ в сетях', 'Потери ТЭ в сетях', 'Потери на СП', 'Первичное потребление'] - data = {source: [] for source in sources} - years=[] - for table in tables: - year=table.iloc[0,10] - years.append(int(year[:4])) - table = table.iloc[2:].reset_index(drop=True) - if isnan(table.iloc[8,11]): - data['Расход ТЭР на производство ЭЭ'].append(0) - else: - data['Расход ТЭР на производство ЭЭ'].append(abs(int(table.iloc[8,11]))) - if isnan(table.iloc[9,11]): - data['Расход ТЭР на производство ТЭ'].append(0) - else: - data['Расход ТЭР на производство ТЭ'].append(abs(int(table.iloc[9,11]))) - if isnan(table.iloc[13,11]): - data['Расход на преобразование топлива'].append(0) - else: - data['Расход на преобразование топлива'].append(abs(int(table.iloc[13,11]))) - if isnan(table.iloc[18,9]): - data['Потери ЭЭ в сетях'].append(0) - else: - data['Потери ЭЭ в сетях'].append(abs(int(table.iloc[18,9]))) - if isnan(table.iloc[18,10]): - data['Потери ТЭ в сетях'].append(0) - else: - data['Потери ТЭ в сетях'].append(abs(int(table.iloc[18,10]))) - if isnan(table.iloc[17,11]): - data['Потери на СП'].append(0) - else: - data['Потери на СП'].append(abs(int(table.iloc[17,11]))) - if isnan(table.iloc[6,11]): - data['Первичное потребление'].append(0) - else: - data['Первичное потребление'].append(abs(int(table.iloc[6,11]))) - - data={**{'Year': years},**data} - df=pd.DataFrame(data) - fig=go.Figure() - for source in sources: - fig.add_trace(go.Scatter( - x=df['Year'], - y=df[source], - mode='lines', - stackgroup='one', # Стек с накоплением - name=source - )) - - # Настройка графика - fig.update_layout( - title={ - 'text':'Динамика эффективности сектора трансформации ТЭК региона', - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - xaxis_title="Годы", - yaxis_title="Значения, т.у.т.", - legend_title="Категории", - template="plotly_white", - yaxis=dict( - tickformat="d" # Используем формат целого числа - ) - ) - return [fig] - -def radarDiagram(tables): - VRP_MO=[4206.506,4290.2613,4644.635,5196.1364,5406.0765,6809.9511,7720.8426]#2016 2017 2018 2019 2020 2021 2022 - years=[] - VRP=[] - P1=[] - P2=[] - P3=[] - P4=[] - P5=[] - P6=[] - for d in tables: - year=int(d.iloc[0,10][:4]) - years.append(year) - VRP.append(VRP_MO[year-2016]) - d = d.iloc[4:].reset_index(drop=True) - P1.append(1/abs(round(d.iloc[4,11]/VRP_MO[year-2016],3))) - P2.append(abs(round(d.iloc[17,11]/d.iloc[4,11],3))) - P3.append(abs(round( (d.iloc[6,9]+d.iloc[8,10])/(abs(d.iloc[6,2]+d.iloc[6,3]+d.iloc[6,4]+d.iloc[6,5]+d.iloc[6,6]+d.iloc[6,7]+d.iloc[6,8]+d.iloc[6,10])+abs(d.iloc[8,2]+d.iloc[8,3]+d.iloc[8,4]+d.iloc[8,5]+d.iloc[8,6]+d.iloc[8,7]+d.iloc[8,8]+d.iloc[8,9])),3))) - P4.append(abs(round(d.iloc[9,10]/abs(d.iloc[9,2]+d.iloc[9,3]+d.iloc[9,4]+d.iloc[9,5]+d.iloc[9,6]+d.iloc[9,7]+d.iloc[9,8]+d.iloc[9,9]),3))) - P5.append(1/abs(round(d.iloc[16,9]/d.iloc[17,9],3))) - P6.append(1/abs(round(d.iloc[16,10]/d.iloc[17,10],3))) - U1=[] - U2=[] - U3=[] - U4=[] - U5=[] - U6=[] - for i in range(1,len(years)): # За базовый берем первый год (2016г) - U1.append(round(P1[i]/P1[0],2)) - U2.append(round(P2[i]/P2[0],2)) - U3.append(round(P3[i]/P3[0],2)) - U4.append(round(P4[i]/P4[0],2)) - U5.append(round(P5[i]/P5[0],2)) - U6.append(round(P6[i]/P6[0],2)) - - years=[str(y) for y in years][1:] - parameters=['U1', 'U2', 'U3', 'U4', 'U5', 'U6'] - data= { - 'U1':U1, - 'U2':U2, - 'U3':U3, - 'U4':U4, - 'U5':U5, - 'U6':U6, - } - # Преобразуем данные в удобный формат - values_by_year = list(zip(*[data[param] for param in parameters])) - - # Создание фигуры - fig1 = go.Figure() - - # Добавляем данные для каждого года - for i, year in enumerate(years): - values = values_by_year[i] - fig1.add_trace(go.Scatterpolar( - r=list(values) + [values[0]], # Преобразуем кортеж в список и замыкаем круг - theta=parameters + [parameters[0]], # Замыкаем круг - name=year - )) - - # Настройка графика - fig1.update_layout( - polar=dict( - radialaxis=dict( - visible=True, - range=[0, max(max(values_by_year)) + 0.5] # Диапазон значений оси - ) - ), - title={ - 'text':'Радарная диаграмма параметров по годам, 2016 год базовый', - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - showlegend=True - ) - - # Создаем субплоты - fig2 = make_subplots( - rows=2, cols=3, # Сетка 2x3 - specs=[[{'type': 'polar'}] * 3, [{'type': 'polar'}] * 3], # Все графики полярные - subplot_titles=years # Названия графиков — годы - ) - - # Добавляем данные для каждого года - for i, year in enumerate(years): - values = values_by_year[i] - row = i // 3 + 1 # Рассчитываем строку (целая часть от деления) - col = i % 3 + 1 # Рассчитываем колонку (остаток от деления) - fig2.add_trace(go.Scatterpolar( - r=list(values) + [values[0]], # Замыкаем круг - theta=parameters + [parameters[0]], # Замыкаем круг - fill='toself', # Закрашиваем область - name=f"Year {year}", - showlegend=False - ), row=row, col=col) - - # Настройка графика - fig2.update_layout( - title={ - 'text':'Радарные диаграммы по годам, 2016 год базовый', - 'x':0.5, - 'xanchor': 'center', - 'yanchor': 'top' - }, - height=800, # Высота всего графика - ) - return[fig1,fig2] - -def energyEfficiency(baseTable,currentTable): - d=baseTable - baseYear=d.iloc[0,10] - baseYearInt=int(baseYear[:4]) - d = d.iloc[4:].reset_index(drop=True) - b_p=[ - abs(round(d.iloc[4,11]/VRP_MO[baseYearInt-2016],3)), - abs(round(d.iloc[17,11]/d.iloc[4,11],3)), - abs(round( (d.iloc[6,9]+d.iloc[8,10])/(abs(d.iloc[6,2]+d.iloc[6,3]+d.iloc[6,4]+d.iloc[6,5]+d.iloc[6,6]+d.iloc[6,7]+d.iloc[6,8]+d.iloc[6,10])+abs(d.iloc[8,2]+d.iloc[8,3]+d.iloc[8,4]+d.iloc[8,5]+d.iloc[8,6]+d.iloc[8,7]+d.iloc[8,8]+d.iloc[8,9])),3)), - abs(round(d.iloc[9,10]/abs(d.iloc[9,2]+d.iloc[9,3]+d.iloc[9,4]+d.iloc[9,5]+d.iloc[9,6]+d.iloc[9,7]+d.iloc[9,8]+d.iloc[9,9]),3)), - abs(round(d.iloc[16,9]/d.iloc[17,9],3)), - abs(round(d.iloc[16,10]/d.iloc[17,10],3)) - ] - d=currentTable - currentYear=d.iloc[0,10] - currentYearInt=int(currentYear[:4]) - d = d.iloc[4:].reset_index(drop=True) - p=[ - abs(round(d.iloc[4,11]/VRP_MO[currentYearInt-2016],3)), - abs(round(d.iloc[17,11]/d.iloc[4,11],3)), - abs(round( (d.iloc[6,9]+d.iloc[8,10])/(abs(d.iloc[6,2]+d.iloc[6,3]+d.iloc[6,4]+d.iloc[6,5]+d.iloc[6,6]+d.iloc[6,7]+d.iloc[6,8]+d.iloc[6,10])+abs(d.iloc[8,2]+d.iloc[8,3]+d.iloc[8,4]+d.iloc[8,5]+d.iloc[8,6]+d.iloc[8,7]+d.iloc[8,8]+d.iloc[8,9])),3)), - abs(round(d.iloc[9,10]/abs(d.iloc[9,2]+d.iloc[9,3]+d.iloc[9,4]+d.iloc[9,5]+d.iloc[9,6]+d.iloc[9,7]+d.iloc[9,8]+d.iloc[9,9]),3)), - abs(round(d.iloc[16,9]/d.iloc[17,9],3)), - abs(round(d.iloc[16,10]/d.iloc[17,10],3)) - ] - # Согласование «чем больше, тем лучше» - b_p[0]=round(1/b_p[0],3) - b_p[4]=round(1/b_p[4],3) - b_p[5]=round(1/b_p[5],3) - p[0]=round(1/p[0],3) - p[4]=round(1/p[4],3) - p[5]=round(1/p[5],3) - # Определение значения функции полезности - u=[] - for i in range(6): - u.append(round(p[i]/b_p[i], 2)) - # уровень значимости показателей - #r = [0.17, 0.17, 0.17, 0.17, 0.16, 0.16] - r = [0.2, 0.2, 0.1, 0.2, 0.1, 0.2] - # узловые точки в классификаторе - g = [0.1, 0.3, 0.5, 0.7, 0.9] - # Классификация отдельных значений - M = [[0.55, 0.65, 0.75], [0.65, 0.75, 0.85, 0.95], [0.85, 0.95, 1.05, 1.15], [1.05, 1.15, 1.25, 1.35], [1.25, 1.35, 1.45]] - # Классификация уровней показателей - lvlX = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] - for i in range(6): - b = [] # какие значения лингв переменной может принимать (0 - Плохо, 1 - Есть ухудшение, 2 - Не хуже, 3 - Есть улучшение, 4 - Хорошо) - w = [] # интервал значения показателя - for j in range(5): - for h in range(len(M[j]) - 1): - if M[j][h] <= u[i] <= M[j][h+1]: - w = [M[j][h], M[j][h+1]] - b.append(j) - break - if len(b) == 2: - if u[i]==w[0]: - lvlX[i][b[0]]=0.95 - lvlX[i][b[1]]=0.05 - elif u[i]==w[1]: - lvlX[i][b[0]]=0.05 - lvlX[i][b[1]]=0.95 - else: - lvlX[i][b[0]] = round(10*(w[1] - u[i]), 2) - lvlX[i][b[1]] = round(1 - lvlX[i][b[0]],2) - elif len(b) == 1: - lvlX[i][b[0]] = 1 - elif len(b) == 0: - lvlX[i][4] = 1 - # считаем Динамику изменения энергопотребления в регионе - D = 0 - for i in range(6): - s = 0 - for j in range(5): - s += g[j] * lvlX[i][j] - D += r[i] * s - MD = [[0, 0.15, 0.25], [0.15, 0.25, 0.35, 0.45], [0.35, 0.45, 0.55, 0.65], [0.55, 0.65, 0.75, 0.85], [0.75, 0.85, 1]] - lvlD = [0, 0, 0, 0, 0] - b = [] # какие значения лингв переменной может принимать (0 - Отрицателньая, 1 - Есть ухудшение, 2 - Без изменения, 3 - Есть улучшение, 4 - Положительная) - w = [] # интервал значения показателя - for j in range(5): - for h in range(len(M[j]) - 1): - if MD[j][h] <= D <= MD[j][h+1]: - w = [M[j][h],MD[j][h+1]] - b.append(j) - break - if len(b) == 2: - if D==w[0]: - lvlD[b[0]]=0.9 - lvlD[b[1]]=0.05 - elif D==w[1]: - lvlD[b[0]]=0.05 - lvlD[b[1]]=0.95 - else: - lvlD[b[0]] = round(10*(w[1] - D), 2) - lvlD[b[1]] = round(1 - lvlD[b[0]],2) - elif len(b) == 1: - lvlD[b[0]] = 1 - elif len(b) == 0 : - lvlD[4] = 1 - - return lvlD, D, lvlX - -def prepare_data_for_display(lvlD, D, lvlX): - # Логика генерации текста отчета - if lvlD[0] == 1 or (lvlD[0] == 0.5 and lvlD[1] == 0.5) or (lvlD[0] > 0 and lvlD[1] > 0 and lvlD[0] > lvlD[1]): - lpD = 'Отрицательная' - elif lvlD[1] == 1 or (lvlD[1] == 0.5 and lvlD[2] == 0.5) or (lvlD[1] > 0 and lvlD[2] > 0 and lvlD[1] > lvlD[2]) or (lvlD[0] > 0 and lvlD[1] > 0 and lvlD[0] < lvlD[1]): - lpD = 'Есть ухудшение' - elif lvlD[2] == 1 or (lvlD[2] == 0.5 and lvlD[3] == 0.5) or (lvlD[2] > 0 and lvlD[3] > 0 and lvlD[2] > lvlD[3]) or (lvlD[1] > 0 and lvlD[2] > 0 and lvlD[1] < lvlD[2]): - lpD = 'Без изменения' - elif lvlD[3] == 1 or (lvlD[3] == 0.5 and lvlD[4] == 0.5) or (lvlD[3] > 0 and lvlD[4] > 0 and lvlD[3] > lvlD[4]) or (lvlD[2] > 0 and lvlD[3] > 0 and lvlD[2] < lvlD[3]): - lpD = 'Есть улучшение' - elif (lvlD[3] > 0 and lvlD[4] > 0 and lvlD[4] > lvlD[3]) or lvlD[4] == 1: - lpD = 'Положительная' - - report_text = f""" -

Значение лингвистической переменной D: {D}

-

Динамика эффективности использования ТЭР в регионе: {lpD}

- """ - indicators = [ - "Энергоемкость ВРП (P1)", - "Коэффициент полезного использования ТЭР в конечном потр. (P2)", - "Коэффициент полезного использования ТЭР на электростанциях (P3)", - "Коэффициент полезного использования ТЭР котельными (P4)", - "Доля потерь в сетях в конечном потр. электрической энергии (P5)", - "Доля потерь в сетях в конечном потр. тепловой энергии (P6)" - ] - for i in range(6): - if lvlX[i][0] == 1 or (lvlX[i][0] == 0.5 and lvlX[i][1] == 0.5) or (lvlX[i][0] > 0 and lvlX[i][1] > 0 and lvlX[i][0] > lvlX[i][1]): - lpP = 'Плохо' - elif lvlX[i][1] == 1 or (lvlX[i][1] == 0.5 and lvlX[i][2] == 0.5) or (lvlX[i][1] > 0 and lvlX[i][2] > 0 and lvlX[i][1] > lvlX[i][2]) or (lvlX[i][0] > 0 and lvlX[i][1] > 0 and lvlX[i][0] < lvlX[i][1]): - lpP = 'Есть ухудшение' - elif lvlX[i][2] == 1 or (lvlX[i][2] == 0.5 and lvlX[i][3] == 0.5) or (lvlX[i][2] > 0 and lvlX[i][3] > 0 and lvlX[i][2] > lvlX[i][3]) or (lvlX[i][1] > 0 and lvlX[i][2] > 0 and lvlX[i][1] < lvlX[i][2]): - lpP = 'Не хуже' - elif lvlX[i][3] == 1 or (lvlX[i][3] == 0.5 and lvlX[i][4] == 0.5) or (lvlX[i][3] > 0 and lvlX[i][4] > 0 and lvlX[i][3] > lvlX[i][4]) or (lvlX[i][2] > 0 and lvlX[i][3] > 0 and lvlX[i][2] < lvlX[i][3]): - lpP = 'Есть улучшение' - elif (lvlX[i][3] > 0 and lvlX[i][4] > 0 and lvlX[i][4] > lvlX[i][3]) or lvlX[i][4] == 1: - lpP = 'Хорошо' - report_text += f"

Уровень полезности показателя {indicators[i]}: {lpP}

" - report_text += "

Лингвистическая переменная оценки уровня полезности показателей:

" - report_text += "" - for i in range(6): - report_text += f""" - - - - - - - - - """ - report_text += "
ИндикаторПлохоЕсть ухудшениеНе хужеЕсть улучшениеХорошо
P{i+1}{lvlX[i][0]}{lvlX[i][1]}{lvlX[i][2]}{lvlX[i][3]}{lvlX[i][4]}
" - return report_text - -def allowed_file(filename): - return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS'] - -@app.route('/') -def index(): - files = os.listdir(app.config['UPLOAD_FOLDER']) - return render_template('index.html', files=files) - -@app.route('/download-template') -def download_template(): - try: - return send_from_directory(app.config['DOWNLOAD_FOLDER'], 'template.xlsm', as_attachment=True) - except FileNotFoundError: - return "Шаблон не найден", 404 - -@app.route('/upload', methods=['POST']) -def upload_files(): - if 'files' not in request.files: - return redirect(request.url) - - files = request.files.getlist('files') - - if not files or any(f.filename == '' for f in files): - return redirect(request.url) - - for file in files: - if file and allowed_file(file.filename): - filename = secure_filename(file.filename) - filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) - file.save(filepath) - - return redirect(url_for('index')) - -@app.route('/display-report', methods=['POST']) -def display_report(): - try: - base_file = request.form.get('base_file') - current_file = request.form.get('current_file') - - if not base_file or not current_file: - return redirect(url_for('index')) - - base_filepath = os.path.join(app.config['UPLOAD_FOLDER'], base_file) - current_filepath = os.path.join(app.config['UPLOAD_FOLDER'], current_file) - - if not os.path.exists(base_filepath) or not os.path.exists(current_filepath): - return "Файл не найден", 404 - - fig_html = analyze_excel_files(base_filepath, current_filepath) - - return render_template('index.html', files=os.listdir(app.config['UPLOAD_FOLDER']), fig_html=fig_html) - except Exception as e: - app.logger.error(f"Error in /display-report: {str(e)}") - return "Internal Server Error", 500 -@app.route('/download-report', methods=['POST']) -def download_report(): - base_file = request.form.get('base_file') - current_file = request.form.get('current_file') - - if not base_file or not current_file: - return redirect(url_for('index')) - - base_filepath = os.path.join(app.config['UPLOAD_FOLDER'], base_file) - current_filepath = os.path.join(app.config['UPLOAD_FOLDER'], current_file) - - if not os.path.exists(base_filepath) or not os.path.exists(current_filepath): - return "Файл не найден", 404 - - pdf_path = os.path.join(app.config['DOWNLOAD_FOLDER'], 'report.pdf') - #doc.SaveToFile(pdf_path, FileFormat.PDF) - return send_from_directory(app.config['DOWNLOAD_FOLDER'], 'report.pdf', as_attachment=True) - -def analyze_excel_files(base_filepath, current_filepath): - files = os.listdir(app.config['UPLOAD_FOLDER']) - tables = [pd.read_excel(os.path.join(app.config['UPLOAD_FOLDER'], f),header=None) for f in files if allowed_file(f)] - tables2 = [pd.read_excel(os.path.join(app.config['UPLOAD_FOLDER'], f),header=None,sheet_name=None) for f in files if allowed_file(f)] - baseTable = pd.read_excel(base_filepath, header=None) - currentTable = pd.read_excel(current_filepath, header=None) - - figSankey = [sankey(t) for t in tables] - figSankey2 = [sankey2(t) for t in tables] - figPiePPE = [piePPE(t) for t in tables] - figPieKP = [pieKP(t) for t in tables] - figBar = barChart(tables) - figPar=parcoordsChart(tables, tables2) - figHeatMapsGeneral = heatMapsGeneral(tables) - figHeatMaps = heatMaps(tables) - figStream = streamGraph(tables) - figRadar = radarDiagram(tables) - lvlD, D, lvlX =energyEfficiency(baseTable, currentTable) - report_text = prepare_data_for_display(lvlD,D,lvlX) - figs = figSankey+figSankey2+figPar+figHeatMapsGeneral+figHeatMaps+figStream+figRadar+figPiePPE+figPieKP+figBar - fig_html = ''.join([pio.to_html(fig, full_html=False) for fig in figs]) - # Объединяем отчет и графики - full_content = f"
{report_text}
{fig_html}" - return full_content - -# Функция для очистки папки uploads -def clear_upload_folder(): - folder = app.config['UPLOAD_FOLDER'] - if os.path.exists(folder): - for filename in os.listdir(folder): - file_path = os.path.join(folder, filename) - try: - if os.path.isfile(file_path) or os.path.islink(file_path): - os.unlink(file_path) # Удаляем файл или ссылку - elif os.path.isdir(file_path): - shutil.rmtree(file_path) # Удаляем папку и её содержимое - except Exception as e: - print(f"Не удалось удалить {file_path}. Причина: {e}") - -if __name__ == '__main__': - clear_upload_folder() # Очистка папки перед запуском - from waitress import serve - serve(app, host="0.0.0.0", port=8080) - # app.run(debug=True) + +from flask import Flask, render_template, request, send_from_directory, redirect, url_for +from werkzeug.utils import secure_filename +from math import * +import os +import pandas as pd +import plotly.express as px +import plotly.io as pio +import plotly.graph_objects as go +from plotly.subplots import make_subplots +import numpy as np +import shutil + +app = Flask(__name__, static_folder='static') +os.chdir(os.path.dirname(__file__)) +app.config['UPLOAD_FOLDER'] = 'uploads' +app.config['DOWNLOAD_FOLDER'] = 'downloads' +app.config['ALLOWED_EXTENSIONS'] = {'xlsm','xlsx'} + +VRP_MO=[4206.506,4290.2613,4644.635,5196.1364,5406.0765,6809.9511,7720.8426]#2016 2017 2018 2019 2020 2021 2022 + +def sankey(table): + year=table.iloc[0,10] + table = table.iloc[2:].reset_index(drop=True) + names = table.iloc[:,0].head(20).tail(18).tolist()+['Баланс'] + b= len(names) - 1 + v = table.iloc[:,11].head(20).tail(18).astype('str').str.replace('-','').tolist() + v[6]=str(round(table.iloc[8,9],2)) + v[7]=str(round(table.iloc[9,10],2)) + names[0]='Производство' + names[1]='Импорт' + names[4]='Потр. первичной энергии' + names[5]='Стат. расхождение' + names[7]='Производство ТЭ' + names[10]='Потери' + names[11]='Преобр. топлива' + names[17]='Конечное потр.' + names[-1]+=' ' + str(round((float(v[0])+float(v[1]))/1000,2)) + for i in range(len(names)-1): + names[i]+=' '+str(round(float(v[i])/1000,2)) + fig = go.Figure(data=[go.Sankey( + arrangement = "snap", + node = dict( + pad = 15, + thickness = 10, + line = dict(color = "black", width = 1), + label = names, + x = [0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.4], # 0 пэр 1 ввоз 2 вывоз 3 изм зап 4 ппэ 5 стат расх 6 произв ээ 7 произв тэ 8 преобр топ 9 соб нуж 10 потери 11 кп 12 бал + y = [0.8, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], + ), + link = dict( + source = [0, 1, b, b, b, 4, 4, 4,4,4,4,4], + target = [b, b, 2, 3, 4, 5, 6, 7,11,15,16,17], + value = [v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[11],v[15],v[16],v[17]] + ))]) + fig.update_layout( + title={ + 'text': "Структура первичного потребления ТЭР за "+year, + 'y':0.9, + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + font=dict( + family="Arial, sans-serif", + size=12 + ) + ) + return fig + +def sankey2(table): + names =['Производство', 'Импорт','Доступно из всех ист.','Прямой перенос','Трансф.','Транф. убытки','Доступно после трансф.','Транзит','Конечное потр.'] + year=table.iloc[0,10] + table = table.iloc[2:].reset_index(drop=True) + v = table[11].head(20).tail(18).astype('str').str.replace('-','').tolist() + v = [eval(i) for i in v] + vDop= [int(table[4][19]),int(table[5][19]),int(table[9][19]),int(table[10][19])] + val = [v[0], v[1], vDop[1]+v[2], v[6]+v[7]+v[11]+v[15]+v[16] + vDop[0]+vDop[2]+vDop[3], vDop[1]+v[2], v[6]+v[7]+v[11]+v[15]+v[16], vDop[0]+vDop[2]+vDop[3], v[2], v[17]] + names[0]+=' '+ str(round(float(val[0])/1000,2)) + names[1]+=' '+ str(round(float(val[1])/1000,2)) + names[2]+=' '+ str(round((float(val[0])+float(val[1]))/1000,2)) + names[3]+=' '+ str(round(float(val[4])/1000,2)) + names[4]+=' '+ str(round(float(val[3])/1000,2)) + names[5]+=' '+ str(round(float(val[5])/1000,2)) + names[6]+=' '+ str(round((float(val[3])+float(val[4])-float(val[5]))/1000,2)) + names[7]+=' '+ str(round(float(val[7])/1000,2)) + names[8]+=' '+ str(round(float(val[8])/1000,2)) + fig = go.Figure(data=[go.Sankey( + arrangement = "snap", + node = dict( + pad = 15, + thickness = 10, + line = dict(color = "black", width = 1), + label = names, + x = [0.2, 0.2, 0.3, 0.5, 0.5, 0.65, 0.65, 0.85, 0.85], + y = [0.1, 0.1, 0.1, 0.1, 0.4, 0.8, 0.1, 0.1, 0.45], + ), + link = dict( + source = [0, 1, 2, 2, 3, 4, 4, 6, 6], + target = [2, 2, 3, 4, 6, 5, 6, 7, 8], + value = val + ))]) + fig.update_layout( + title={ + 'text': "Пропорции ТЭБ "+year, + 'y':0.9, + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + font=dict( + family="Arial, sans-serif", + size=12 + ) + ) + return fig + +def piePPE(table): # потребление первичной энергии + year=table.iloc[0,10] + table = table.iloc[2:].reset_index(drop=True) + labels = table.iloc[0].to_list()[2:11] + values = table.iloc[6].values.tolist()[2:11] + fig = go.Figure(data=[go.Pie(labels=labels,values=values)]) + fig.update_layout( + title={ + 'text': "Потребление первичной энергии за "+year, + 'y':0.9, + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + font=dict( + family="Arial, sans-serif", + size=18 + )) + return fig + +def pieKP(table): # конечное потребление + year=table.iloc[0,10] + table = table.iloc[2:].reset_index(drop=True) + labels = table.iloc[0].to_list()[2:11] + values = table.iloc[19].values.tolist()[2:11] + fig = go.Figure(data=[go.Pie(labels=labels,values=values)]) + fig.update_layout( + title={ + 'text': "Конечное потребление за "+year, + 'y':0.9, + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + font=dict( + family="Arial, sans-serif", + size=18 + ) + ) + return fig + +def barChart(tables): + dataBal=[] + dataPPE=[] + dataKP=[] + for table in tables: + year=table.iloc[0,10] + table = table.iloc[2:].reset_index(drop=True) + dataBal.append([year[:4], int(table.iloc[:,11][2])+int(table.iloc[:,11][3])]) + dataPPE.append([year[:4], int(table.iloc[:,11][6])]) + dataKP.append([year[:4], int(table.iloc[:,11][19])]) + dfBal=pd.DataFrame(dataBal,columns=['Год','Баланс']) + dfPPE=pd.DataFrame(dataPPE,columns=['Год','Потребление первичной энергии']) + dfKP=pd.DataFrame(dataKP,columns=['Год','Конечное потребление']) + figBal =[ + px.bar(dfBal,x='Год',y='Баланс').update_layout( + title={ + 'text': 'Сравнение балансов', + 'y':0.95, + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + font=dict( + family="Arial, sans-serif", + size=18 + ) + ), + px.bar(dfPPE,x='Год',y='Потребление первичной энергии').update_layout( + title={ + 'text': 'Сравнение потребления первичной энергии', + 'y':0.95, + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + font=dict( + family="Arial, sans-serif", + size=18 + ) + ), + px.bar(dfKP,x='Год',y='Конечное потребление').update_layout( + title={ + 'text': 'Сравнение конечного потребления', + 'y':0.95, + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + font=dict( + family="Arial, sans-serif", + size=18 + ) + )] + return figBal + +def parcoordsChart(tables, tables2): + energy_sources = ["Уголь", "Сырая нефть", "Нефтепродукты", "Природный газ", "Твёрдое топливо", "Гидроэнергия", "Атомная энергия", "Электро энергия", "Тепловая энергия"] + energy_sources2 = ["Уголь", 'Дизель', 'Мазут', 'СУГ', 'Природный газ'] + sectors_sources = ['Сельское хозяйство', 'Промышленность', 'Строительство', 'Транспорт', 'Сфера услуг', 'Население'] + + ranges_ppe = [[1, 2500], [0, 3000], [1000, 12000], [20000, 26000], [1, 1100], [100, 300], [0, 300], [3000, 5000], [1000, 1600]] + ranges_ppe2 = [[500,2000], [1000,4100], [0,500], [0,150], [20000,25000]] + ranges_kp = [[0, 3000], [0, 3000], [1000, 10000], [4000, 8000], [0, 1000], [0, 1000], [0, 1000], [4000, 5500], [8000, 11000]] + ranges_ee = [[0, 500], [1500, 2000], [100, 200], [400, 800], [400, 1000],[1000, 1500]] + # Инициализация данных + ppe_data = {source: [] for source in energy_sources} + ppe_data2 = {source: [] for source in energy_sources2} + kp_data = {source: [] for source in energy_sources} + ee_data = {source: [] for source in sectors_sources} + years = [] + colors = [[0, 'red'], [0.5, 'yellow'], [1, 'blue']] + + # Обработка таблиц + for table in tables: + year = table.iloc[0, 10] + years.append(int(year[:4])) + table = table.iloc[2:].reset_index(drop=True) + + for idx, source in enumerate(energy_sources, start=2): + ppe_value = table.iloc[6,idx] if pd.notna(table.iloc[6,idx]) else 0 + kp_value = table.iloc[19,idx] if pd.notna(table.iloc[19,idx]) else 0 + + ppe_data[source].append(int(ppe_value)) + kp_data[source].append(int(kp_value)) + + for i in range(len(sectors_sources)): + if i==0: + ee_data[sectors_sources[i]].append(int(table.iloc[20][9])) + elif i==1: + ee_data[sectors_sources[i]].append(int(table.iloc[21][9])) + elif i==2: + ee_data[sectors_sources[i]].append(int(table.iloc[27][9])) + elif i==3: + ee_data[sectors_sources[i]].append(int(table.iloc[28][9])) + elif i==4: + ee_data[sectors_sources[i]].append(int(table.iloc[33][9])) + elif i==5: + ee_data[sectors_sources[i]].append(int(table.iloc[34][9])) + + for table in tables2: + for i in range(len(energy_sources2)): + if i==0: + ppe_data2[energy_sources2[i]].append(int(table['Уголь'].iloc[6,1])) + elif i==1: + ppe_data2[energy_sources2[i]].append(int(table['Дизель'].iloc[6,1])) + elif i==2: + ppe_data2[energy_sources2[i]].append(int(table['Мазут'].iloc[6,1])) + elif i==3: + ppe_data2[energy_sources2[i]].append(int(table['СУГ'].iloc[6,1])) + elif i==4: + ppe_data2[energy_sources2[i]].append(int(table['Пр-й газ'].iloc[6,1])) + + # Функция для создания графика + def create_figure(data, ranges, title): + dimensions = [dict(tickvals=years, label='Год', values=years)] + [ + dict(range=ranges[idx], + label=source, + values=values, + tickformat=".0f") + for idx, (source, values) in enumerate(data.items()) + ] + fig = go.Figure(data=go.Parcoords( + line=dict(color=years, colorscale=colors), + dimensions=dimensions, + unselected=dict(line=dict(color='green', opacity=1)) + )) + fig.update_layout( + title=dict(text=title, y=0.95, x=0.5, xanchor='center', yanchor='top'), + font=dict(family="Arial, sans-serif", size=18) + ) + return fig + + # Создание графиков + figParPPE = create_figure(ppe_data, ranges_ppe, "Динамика изменения потребления первичной энергии") + figParKP = create_figure(kp_data, ranges_kp, "Динамика изменения конечного потребления") + figParEE = create_figure(ee_data,ranges_ee,'Конечное потребление ЭЭ по секторам экономики') + figParPPE2 = create_figure(ppe_data2,ranges_ppe2, 'Выборочная динамика изменения потребления первичной энергии') + + return [figParPPE, figParPPE2, figParKP, figParEE] + +def heatMapsGeneral(tables): + resources = ['Уголь', 'Нефтепродукты', 'Природный газ', 'Электроэнергия', 'Тепловая энергия'] + years = [] + ppe_data = {resource: [] for resource in resources} + kp_data = {resource: [] for resource in resources} + + # Обработка данных из таблиц + for table in tables: + year = table.iloc[0, 10] + years.append(int(year[:4])) + table = table.iloc[3:].reset_index(drop=True) + # Индексы колонок соответствующих ресурсов + resource_indices = { + 'Уголь': 2, + 'Нефтепродукты': 4, + 'Природный газ': 5, + 'Электроэнергия': 9, + 'Тепловая энергия': 10 + } + for resource, col_idx in resource_indices.items(): + ppe_data[resource].append(round(table.iloc[5, col_idx], 2)) + kp_data[resource].append(round(table.iloc[18, col_idx], 2)) + + # Функция для создания тепловой карты + def create_heatmap(data, title): + values = [data[resource] for resource in resources] + fig = go.Figure(data=go.Heatmap( + z=values, + x=years, + y=resources, + text=values, + texttemplate="%{text}", + colorscale='YlGnBu', + colorbar=dict(title="Потребление") + )) + fig.update_layout( + xaxis_title='Годы', + yaxis_title='Ресурсы', + xaxis=dict(tickvals=years, ticktext=[str(year) for year in years]), + yaxis=dict(tickvals=list(range(len(resources))), ticktext=resources), + title=title + ) + return fig + + # Создание тепловых карт + figPPE = create_heatmap(ppe_data, "Тепловая карта потребления первичной энергии") + figKP = create_heatmap(kp_data, "Тепловая карта конечного потребления энергии") + return [figPPE, figKP] + +def heatMaps(tables): + sectors = ['Сельское хозяйство', 'Промышленность', 'Строительство', 'Транспорт и связь', 'Сфера услуг', 'Население', 'Неэнергетические нужды'][::-1] + resources = ['Уголь', 'Нефтепродукты', 'Природный газ', 'Электроэнергия', 'Тепловая энергия'] + res=[] + for d in tables: + year=d.iloc[0,10] + d = d.iloc[2:].reset_index(drop=True) + value = [ + [round(d.iloc[20, 2], 2), round(d.iloc[20, 4], 2), round(d.iloc[20, 5], 2), round(d.iloc[20, 9], 2), round(d.iloc[20, 10], 2)], + [round(d.iloc[21, 2], 2), round(d.iloc[21, 4], 2), round(d.iloc[21, 5], 2), round(d.iloc[21, 9], 2), round(d.iloc[21, 10], 2)], + [round(d.iloc[27, 2], 2), round(d.iloc[27, 4], 2), round(d.iloc[27, 5], 2), round(d.iloc[27, 9], 2), round(d.iloc[27, 10], 2)], + [round(d.iloc[28, 2], 2), round(d.iloc[28, 4], 2), round(d.iloc[28, 5], 2), round(d.iloc[28, 9], 2), round(d.iloc[28, 10], 2)], + [round(d.iloc[33, 2], 2), round(d.iloc[33, 4], 2), round(d.iloc[33, 5], 2), round(d.iloc[33, 9], 2), round(d.iloc[33, 10], 2)], + [round(d.iloc[34, 2], 2), round(d.iloc[34, 4], 2), round(d.iloc[34, 5], 2), round(d.iloc[34, 9], 2), round(d.iloc[34, 10], 2)], + [round(d.iloc[35, 2], 2), round(d.iloc[35, 4], 2), round(d.iloc[35, 5], 2), round(d.iloc[35, 9], 2), round(d.iloc[35, 10], 2)]][::-1] + value=np.array(value) + fig = go.Figure(data=go.Heatmap( + z=value, + x=resources, + y=sectors, + text=value, # Текстовые метки + texttemplate="%{text}", # Отображение значений в ячейках + colorscale='YlGnBu', + colorbar=dict(title="Потребление") + )) + fig.update_layout( + title={ + 'text':year, + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + xaxis_title='Источники энергии', + yaxis_title='Секторы экономики', + ) + res.append(fig) + return res + +def streamGraph(tables): + sources = ['Расход ТЭР на производство ЭЭ', 'Расход ТЭР на производство ТЭ', 'Расход на преобразование топлива', 'Потери ЭЭ в сетях', 'Потери ТЭ в сетях', 'Потери на СП', 'Первичное потребление'] + data = {source: [] for source in sources} + years=[] + for table in tables: + year=table.iloc[0,10] + years.append(int(year[:4])) + table = table.iloc[2:].reset_index(drop=True) + if isnan(table.iloc[8,11]): + data['Расход ТЭР на производство ЭЭ'].append(0) + else: + data['Расход ТЭР на производство ЭЭ'].append(abs(int(table.iloc[8,11]))) + if isnan(table.iloc[9,11]): + data['Расход ТЭР на производство ТЭ'].append(0) + else: + data['Расход ТЭР на производство ТЭ'].append(abs(int(table.iloc[9,11]))) + if isnan(table.iloc[13,11]): + data['Расход на преобразование топлива'].append(0) + else: + data['Расход на преобразование топлива'].append(abs(int(table.iloc[13,11]))) + if isnan(table.iloc[18,9]): + data['Потери ЭЭ в сетях'].append(0) + else: + data['Потери ЭЭ в сетях'].append(abs(int(table.iloc[18,9]))) + if isnan(table.iloc[18,10]): + data['Потери ТЭ в сетях'].append(0) + else: + data['Потери ТЭ в сетях'].append(abs(int(table.iloc[18,10]))) + if isnan(table.iloc[17,11]): + data['Потери на СП'].append(0) + else: + data['Потери на СП'].append(abs(int(table.iloc[17,11]))) + if isnan(table.iloc[6,11]): + data['Первичное потребление'].append(0) + else: + data['Первичное потребление'].append(abs(int(table.iloc[6,11]))) + + data={**{'Year': years},**data} + df=pd.DataFrame(data) + fig=go.Figure() + for source in sources: + fig.add_trace(go.Scatter( + x=df['Year'], + y=df[source], + mode='lines', + stackgroup='one', # Стек с накоплением + name=source + )) + + # Настройка графика + fig.update_layout( + title={ + 'text':'Динамика эффективности сектора трансформации ТЭК региона', + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + xaxis_title="Годы", + yaxis_title="Значения, т.у.т.", + legend_title="Категории", + template="plotly_white", + yaxis=dict( + tickformat="d" # Используем формат целого числа + ) + ) + return [fig] + +def radarDiagram(tables): + VRP_MO=[4206.506,4290.2613,4644.635,5196.1364,5406.0765,6809.9511,7720.8426]#2016 2017 2018 2019 2020 2021 2022 + years=[] + VRP=[] + P1=[] + P2=[] + P3=[] + P4=[] + P5=[] + P6=[] + for d in tables: + year=int(d.iloc[0,10][:4]) + years.append(year) + VRP.append(VRP_MO[year-2016]) + d = d.iloc[4:].reset_index(drop=True) + P1.append(1/abs(round(d.iloc[4,11]/VRP_MO[year-2016],3))) + P2.append(abs(round(d.iloc[17,11]/d.iloc[4,11],3))) + P3.append(abs(round( (d.iloc[6,9]+d.iloc[8,10])/(abs(d.iloc[6,2]+d.iloc[6,3]+d.iloc[6,4]+d.iloc[6,5]+d.iloc[6,6]+d.iloc[6,7]+d.iloc[6,8]+d.iloc[6,10])+abs(d.iloc[8,2]+d.iloc[8,3]+d.iloc[8,4]+d.iloc[8,5]+d.iloc[8,6]+d.iloc[8,7]+d.iloc[8,8]+d.iloc[8,9])),3))) + P4.append(abs(round(d.iloc[9,10]/abs(d.iloc[9,2]+d.iloc[9,3]+d.iloc[9,4]+d.iloc[9,5]+d.iloc[9,6]+d.iloc[9,7]+d.iloc[9,8]+d.iloc[9,9]),3))) + P5.append(1/abs(round(d.iloc[16,9]/d.iloc[17,9],3))) + P6.append(1/abs(round(d.iloc[16,10]/d.iloc[17,10],3))) + U1=[] + U2=[] + U3=[] + U4=[] + U5=[] + U6=[] + for i in range(1,len(years)): # За базовый берем первый год (2016г) + U1.append(round(P1[i]/P1[0],2)) + U2.append(round(P2[i]/P2[0],2)) + U3.append(round(P3[i]/P3[0],2)) + U4.append(round(P4[i]/P4[0],2)) + U5.append(round(P5[i]/P5[0],2)) + U6.append(round(P6[i]/P6[0],2)) + + years=[str(y) for y in years][1:] + parameters=['U1', 'U2', 'U3', 'U4', 'U5', 'U6'] + data= { + 'U1':U1, + 'U2':U2, + 'U3':U3, + 'U4':U4, + 'U5':U5, + 'U6':U6, + } + # Преобразуем данные в удобный формат + values_by_year = list(zip(*[data[param] for param in parameters])) + + # Создание фигуры + fig1 = go.Figure() + + # Добавляем данные для каждого года + for i, year in enumerate(years): + values = values_by_year[i] + fig1.add_trace(go.Scatterpolar( + r=list(values) + [values[0]], # Преобразуем кортеж в список и замыкаем круг + theta=parameters + [parameters[0]], # Замыкаем круг + name=year + )) + + # Настройка графика + fig1.update_layout( + polar=dict( + radialaxis=dict( + visible=True, + range=[0, max(max(values_by_year)) + 0.5] # Диапазон значений оси + ) + ), + title={ + 'text':'Радарная диаграмма параметров по годам, 2016 год базовый', + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + showlegend=True + ) + + # Создаем субплоты + fig2 = make_subplots( + rows=2, cols=3, # Сетка 2x3 + specs=[[{'type': 'polar'}] * 3, [{'type': 'polar'}] * 3], # Все графики полярные + subplot_titles=years # Названия графиков — годы + ) + + # Добавляем данные для каждого года + for i, year in enumerate(years): + values = values_by_year[i] + row = i // 3 + 1 # Рассчитываем строку (целая часть от деления) + col = i % 3 + 1 # Рассчитываем колонку (остаток от деления) + fig2.add_trace(go.Scatterpolar( + r=list(values) + [values[0]], # Замыкаем круг + theta=parameters + [parameters[0]], # Замыкаем круг + fill='toself', # Закрашиваем область + name=f"Year {year}", + showlegend=False + ), row=row, col=col) + + # Настройка графика + fig2.update_layout( + title={ + 'text':'Радарные диаграммы по годам, 2016 год базовый', + 'x':0.5, + 'xanchor': 'center', + 'yanchor': 'top' + }, + height=800, # Высота всего графика + ) + return[fig1,fig2] + +def energyEfficiency(baseTable,currentTable): + d=baseTable + baseYear=d.iloc[0,10] + baseYearInt=int(baseYear[:4]) + d = d.iloc[4:].reset_index(drop=True) + b_p=[ + abs(round(d.iloc[4,11]/VRP_MO[baseYearInt-2016],3)), + abs(round(d.iloc[17,11]/d.iloc[4,11],3)), + abs(round( (d.iloc[6,9]+d.iloc[8,10])/(abs(d.iloc[6,2]+d.iloc[6,3]+d.iloc[6,4]+d.iloc[6,5]+d.iloc[6,6]+d.iloc[6,7]+d.iloc[6,8]+d.iloc[6,10])+abs(d.iloc[8,2]+d.iloc[8,3]+d.iloc[8,4]+d.iloc[8,5]+d.iloc[8,6]+d.iloc[8,7]+d.iloc[8,8]+d.iloc[8,9])),3)), + abs(round(d.iloc[9,10]/abs(d.iloc[9,2]+d.iloc[9,3]+d.iloc[9,4]+d.iloc[9,5]+d.iloc[9,6]+d.iloc[9,7]+d.iloc[9,8]+d.iloc[9,9]),3)), + abs(round(d.iloc[16,9]/d.iloc[17,9],3)), + abs(round(d.iloc[16,10]/d.iloc[17,10],3)) + ] + d=currentTable + currentYear=d.iloc[0,10] + currentYearInt=int(currentYear[:4]) + d = d.iloc[4:].reset_index(drop=True) + p=[ + abs(round(d.iloc[4,11]/VRP_MO[currentYearInt-2016],3)), + abs(round(d.iloc[17,11]/d.iloc[4,11],3)), + abs(round( (d.iloc[6,9]+d.iloc[8,10])/(abs(d.iloc[6,2]+d.iloc[6,3]+d.iloc[6,4]+d.iloc[6,5]+d.iloc[6,6]+d.iloc[6,7]+d.iloc[6,8]+d.iloc[6,10])+abs(d.iloc[8,2]+d.iloc[8,3]+d.iloc[8,4]+d.iloc[8,5]+d.iloc[8,6]+d.iloc[8,7]+d.iloc[8,8]+d.iloc[8,9])),3)), + abs(round(d.iloc[9,10]/abs(d.iloc[9,2]+d.iloc[9,3]+d.iloc[9,4]+d.iloc[9,5]+d.iloc[9,6]+d.iloc[9,7]+d.iloc[9,8]+d.iloc[9,9]),3)), + abs(round(d.iloc[16,9]/d.iloc[17,9],3)), + abs(round(d.iloc[16,10]/d.iloc[17,10],3)) + ] + # Согласование «чем больше, тем лучше» + b_p[0]=round(1/b_p[0],3) + b_p[4]=round(1/b_p[4],3) + b_p[5]=round(1/b_p[5],3) + p[0]=round(1/p[0],3) + p[4]=round(1/p[4],3) + p[5]=round(1/p[5],3) + # Определение значения функции полезности + u=[] + for i in range(6): + u.append(round(p[i]/b_p[i], 2)) + # уровень значимости показателей + #r = [0.17, 0.17, 0.17, 0.17, 0.16, 0.16] + r = [0.2, 0.2, 0.1, 0.2, 0.1, 0.2] + # узловые точки в классификаторе + g = [0.1, 0.3, 0.5, 0.7, 0.9] + # Классификация отдельных значений + M = [[0.55, 0.65, 0.75], [0.65, 0.75, 0.85, 0.95], [0.85, 0.95, 1.05, 1.15], [1.05, 1.15, 1.25, 1.35], [1.25, 1.35, 1.45]] + # Классификация уровней показателей + lvlX = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] + for i in range(6): + b = [] # какие значения лингв переменной может принимать (0 - Плохо, 1 - Есть ухудшение, 2 - Не хуже, 3 - Есть улучшение, 4 - Хорошо) + w = [] # интервал значения показателя + for j in range(5): + for h in range(len(M[j]) - 1): + if M[j][h] <= u[i] <= M[j][h+1]: + w = [M[j][h], M[j][h+1]] + b.append(j) + break + if len(b) == 2: + if u[i]==w[0]: + lvlX[i][b[0]]=0.95 + lvlX[i][b[1]]=0.05 + elif u[i]==w[1]: + lvlX[i][b[0]]=0.05 + lvlX[i][b[1]]=0.95 + else: + lvlX[i][b[0]] = round(10*(w[1] - u[i]), 2) + lvlX[i][b[1]] = round(1 - lvlX[i][b[0]],2) + elif len(b) == 1: + lvlX[i][b[0]] = 1 + elif len(b) == 0: + lvlX[i][4] = 1 + # считаем Динамику изменения энергопотребления в регионе + D = 0 + for i in range(6): + s = 0 + for j in range(5): + s += g[j] * lvlX[i][j] + D += r[i] * s + MD = [[0, 0.15, 0.25], [0.15, 0.25, 0.35, 0.45], [0.35, 0.45, 0.55, 0.65], [0.55, 0.65, 0.75, 0.85], [0.75, 0.85, 1]] + lvlD = [0, 0, 0, 0, 0] + b = [] # какие значения лингв переменной может принимать (0 - Отрицателньая, 1 - Есть ухудшение, 2 - Без изменения, 3 - Есть улучшение, 4 - Положительная) + w = [] # интервал значения показателя + for j in range(5): + for h in range(len(M[j]) - 1): + if MD[j][h] <= D <= MD[j][h+1]: + w = [M[j][h],MD[j][h+1]] + b.append(j) + break + if len(b) == 2: + if D==w[0]: + lvlD[b[0]]=0.9 + lvlD[b[1]]=0.05 + elif D==w[1]: + lvlD[b[0]]=0.05 + lvlD[b[1]]=0.95 + else: + lvlD[b[0]] = round(10*(w[1] - D), 2) + lvlD[b[1]] = round(1 - lvlD[b[0]],2) + elif len(b) == 1: + lvlD[b[0]] = 1 + elif len(b) == 0 : + lvlD[4] = 1 + + return lvlD, D, lvlX + +def prepare_data_for_display(lvlD, D, lvlX): + # Логика генерации текста отчета + if lvlD[0] == 1 or (lvlD[0] == 0.5 and lvlD[1] == 0.5) or (lvlD[0] > 0 and lvlD[1] > 0 and lvlD[0] > lvlD[1]): + lpD = 'Отрицательная' + elif lvlD[1] == 1 or (lvlD[1] == 0.5 and lvlD[2] == 0.5) or (lvlD[1] > 0 and lvlD[2] > 0 and lvlD[1] > lvlD[2]) or (lvlD[0] > 0 and lvlD[1] > 0 and lvlD[0] < lvlD[1]): + lpD = 'Есть ухудшение' + elif lvlD[2] == 1 or (lvlD[2] == 0.5 and lvlD[3] == 0.5) or (lvlD[2] > 0 and lvlD[3] > 0 and lvlD[2] > lvlD[3]) or (lvlD[1] > 0 and lvlD[2] > 0 and lvlD[1] < lvlD[2]): + lpD = 'Без изменения' + elif lvlD[3] == 1 or (lvlD[3] == 0.5 and lvlD[4] == 0.5) or (lvlD[3] > 0 and lvlD[4] > 0 and lvlD[3] > lvlD[4]) or (lvlD[2] > 0 and lvlD[3] > 0 and lvlD[2] < lvlD[3]): + lpD = 'Есть улучшение' + elif (lvlD[3] > 0 and lvlD[4] > 0 and lvlD[4] > lvlD[3]) or lvlD[4] == 1: + lpD = 'Положительная' + + report_text = f""" +

Значение лингвистической переменной D: {D}

+

Динамика эффективности использования ТЭР в регионе: {lpD}

+ """ + indicators = [ + "Энергоемкость ВРП (P1)", + "Коэффициент полезного использования ТЭР в конечном потр. (P2)", + "Коэффициент полезного использования ТЭР на электростанциях (P3)", + "Коэффициент полезного использования ТЭР котельными (P4)", + "Доля потерь в сетях в конечном потр. электрической энергии (P5)", + "Доля потерь в сетях в конечном потр. тепловой энергии (P6)" + ] + for i in range(6): + if lvlX[i][0] == 1 or (lvlX[i][0] == 0.5 and lvlX[i][1] == 0.5) or (lvlX[i][0] > 0 and lvlX[i][1] > 0 and lvlX[i][0] > lvlX[i][1]): + lpP = 'Плохо' + elif lvlX[i][1] == 1 or (lvlX[i][1] == 0.5 and lvlX[i][2] == 0.5) or (lvlX[i][1] > 0 and lvlX[i][2] > 0 and lvlX[i][1] > lvlX[i][2]) or (lvlX[i][0] > 0 and lvlX[i][1] > 0 and lvlX[i][0] < lvlX[i][1]): + lpP = 'Есть ухудшение' + elif lvlX[i][2] == 1 or (lvlX[i][2] == 0.5 and lvlX[i][3] == 0.5) or (lvlX[i][2] > 0 and lvlX[i][3] > 0 and lvlX[i][2] > lvlX[i][3]) or (lvlX[i][1] > 0 and lvlX[i][2] > 0 and lvlX[i][1] < lvlX[i][2]): + lpP = 'Не хуже' + elif lvlX[i][3] == 1 or (lvlX[i][3] == 0.5 and lvlX[i][4] == 0.5) or (lvlX[i][3] > 0 and lvlX[i][4] > 0 and lvlX[i][3] > lvlX[i][4]) or (lvlX[i][2] > 0 and lvlX[i][3] > 0 and lvlX[i][2] < lvlX[i][3]): + lpP = 'Есть улучшение' + elif (lvlX[i][3] > 0 and lvlX[i][4] > 0 and lvlX[i][4] > lvlX[i][3]) or lvlX[i][4] == 1: + lpP = 'Хорошо' + report_text += f"

Уровень полезности показателя {indicators[i]}: {lpP}

" + report_text += "

Лингвистическая переменная оценки уровня полезности показателей:

" + report_text += "" + for i in range(6): + report_text += f""" + + + + + + + + + """ + report_text += "
ИндикаторПлохоЕсть ухудшениеНе хужеЕсть улучшениеХорошо
P{i+1}{lvlX[i][0]}{lvlX[i][1]}{lvlX[i][2]}{lvlX[i][3]}{lvlX[i][4]}
" + return report_text + +def allowed_file(filename): + return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS'] + +@app.route('/') +def index(): + files = os.listdir(app.config['UPLOAD_FOLDER']) + return render_template('index.html', files=files) + +@app.route('/download-template') +def download_template(): + try: + return send_from_directory(app.config['DOWNLOAD_FOLDER'], 'template.xlsm', as_attachment=True) + except FileNotFoundError: + return "Шаблон не найден", 404 + +@app.route('/upload', methods=['POST']) +def upload_files(): + if 'files' not in request.files: + return redirect(request.url) + + files = request.files.getlist('files') + + if not files or any(f.filename == '' for f in files): + return redirect(request.url) + + for file in files: + if file and allowed_file(file.filename): + filename = secure_filename(file.filename) + filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) + file.save(filepath) + + return redirect(url_for('index')) + +@app.route('/delete_files') +def delete_files(): + clear_upload_folder() + return redirect(url_for('index')) + +@app.route('/display-report', methods=['POST']) +def display_report(): + try: + base_file = request.form.get('base_file') + current_file = request.form.get('current_file') + + if not base_file or not current_file: + return redirect(url_for('index')) + + base_filepath = os.path.join(app.config['UPLOAD_FOLDER'], base_file) + current_filepath = os.path.join(app.config['UPLOAD_FOLDER'], current_file) + + if not os.path.exists(base_filepath) or not os.path.exists(current_filepath): + return "Файл не найден", 404 + + fig_html = analyze_excel_files(base_filepath, current_filepath) + + return render_template('index.html', files=os.listdir(app.config['UPLOAD_FOLDER']), fig_html=fig_html) + except Exception as e: + app.logger.error(f"Error in /display-report: {str(e)}") + return "Internal Server Error", 500 + + +@app.route('/download-report', methods=['POST']) +def download_report(): + base_file = request.form.get('base_file') + current_file = request.form.get('current_file') + + if not base_file or not current_file: + return redirect(url_for('index')) + + base_filepath = os.path.join(app.config['UPLOAD_FOLDER'], base_file) + current_filepath = os.path.join(app.config['UPLOAD_FOLDER'], current_file) + + if not os.path.exists(base_filepath) or not os.path.exists(current_filepath): + return "Файл не найден", 404 + + pdf_path = os.path.join(app.config['DOWNLOAD_FOLDER'], 'report.pdf') + #doc.SaveToFile(pdf_path, FileFormat.PDF) + return send_from_directory(app.config['DOWNLOAD_FOLDER'], 'report.pdf', as_attachment=True) + +def analyze_excel_files(base_filepath, current_filepath): + files = os.listdir(app.config['UPLOAD_FOLDER']) + tables = [pd.read_excel(os.path.join(app.config['UPLOAD_FOLDER'], f),header=None) for f in files if allowed_file(f)] + tables2 = [pd.read_excel(os.path.join(app.config['UPLOAD_FOLDER'], f),header=None,sheet_name=None) for f in files if allowed_file(f)] + baseTable = pd.read_excel(base_filepath, header=None) + currentTable = pd.read_excel(current_filepath, header=None) + + figSankey = [sankey(t) for t in tables] + figSankey2 = [sankey2(t) for t in tables] + figPiePPE = [piePPE(t) for t in tables] + figPieKP = [pieKP(t) for t in tables] + figBar = barChart(tables) + figPar=parcoordsChart(tables, tables2) + figHeatMapsGeneral = heatMapsGeneral(tables) + figHeatMaps = heatMaps(tables) + figStream = streamGraph(tables) + figRadar = radarDiagram(tables) + lvlD, D, lvlX =energyEfficiency(baseTable, currentTable) + report_text = prepare_data_for_display(lvlD,D,lvlX) + figs = figSankey+figSankey2+figPar+figHeatMapsGeneral+figHeatMaps+figStream+figRadar+figPiePPE+figPieKP+figBar + fig_html = ''.join([pio.to_html(fig, full_html=False) for fig in figs]) + # Объединяем отчет и графики + full_content = f"
{report_text}
{fig_html}" + return full_content + +# Функция для очистки папки uploads +def clear_upload_folder(): + folder = app.config['UPLOAD_FOLDER'] + if os.path.exists(folder): + for filename in os.listdir(folder): + file_path = os.path.join(folder, filename) + try: + if os.path.isfile(file_path) or os.path.islink(file_path): + os.unlink(file_path) # Удаляем файл или ссылку + elif os.path.isdir(file_path): + shutil.rmtree(file_path) # Удаляем папку и её содержимое + except Exception as e: + print(f"Не удалось удалить {file_path}. Причина: {e}") + +if __name__ == '__main__': + clear_upload_folder() # Очистка папки перед запуском + from waitress import serve + serve(app, host="0.0.0.0", port=8080) + # app.run(debug=True) diff --git a/static/css/style.css b/static/css/style.css index 6b56f5b..e652846 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -1,49 +1,49 @@ -body { - font-family: Arial, sans-serif; - background-color: #f0f4f8; /* Светло-серый фон */ - color: #333; /* Темный текст */ - margin: 0; - padding: 0; -} - -h1, h2 { - color: #2c3e50; /* Темно-синий */ -} - -a { - color: #2980b9; /* Ярко-синий */ - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -form, select, input, button { - margin: 10px 0; - padding: 10px; - border: 1px solid #bdc3c7; /* Светло-серый */ - border-radius: 5px; - background-color: #ecf0f1; /* Очень светло-серый */ -} - -form button { - background-color: #3498db; /* Ярко-синий */ - color: white; - border: none; - cursor: pointer; -} - -form button:hover { - background-color: #2980b9; -} - -ul { - list-style-type: none; - padding: 0; -} - -ul li { - padding: 5px; - border-bottom: 1px solid #bdc3c7; -} +body { + font-family: Arial, sans-serif; + background-color: #f0f4f8; /* Светло-серый фон */ + color: #333; /* Темный текст */ + margin: 0; + padding: 0; +} + +h1, h2 { + color: #2c3e50; /* Темно-синий */ +} + +a { + color: #2980b9; /* Ярко-синий */ + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +form, select, input, button { + margin: 10px 0; + padding: 10px; + border: 1px solid #bdc3c7; /* Светло-серый */ + border-radius: 5px; + background-color: #ecf0f1; /* Очень светло-серый */ +} + +form button { + background-color: #3498db; /* Ярко-синий */ + color: white; + border: none; + cursor: pointer; +} + +form button:hover { + background-color: #2980b9; +} + +ul { + list-style-type: none; + padding: 0; +} + +ul li { + padding: 5px; + border-bottom: 1px solid #bdc3c7; +} diff --git a/templates/index.html b/templates/index.html index 7d86630..97c0079 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,49 +1,52 @@ - - - - - - Сервис оценки энергоэффективности - - - - -

Сервис оценки энергоэффективности на основе топливно-энергетических балансов региона

-

Скачать шаблон Excel файла

-
- -
- -
- - {% if files %} -

Загруженные файлы

- -
- -
- -
- - -
- {% endif %} - -
- {% if fig_html %} -
{{ fig_html|safe }}
- {% endif %} - + + + + + + Сервис оценки энергоэффективности + + + + +

Сервис оценки энергоэффективности на основе топливно-энергетических балансов региона

+

Скачать шаблон Excel файла

+
+ +
+ +
+ + {% if files %} +

Загруженные файлы

+ +
+ +
+ +
+ + +
+ {% endif %} + +
+ {% if fig_html %} +
{{ fig_html|safe }}
+ {% endif %} + \ No newline at end of file