Загрузка данных


import pandas as pd
import numpy as np
import tkinter as tk
from tkinter import messagebox, ttk, Toplevel, Text
import os

class MeterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Анализ показаний счетчика 2026")
        self.df_raw = None
        self.df_melted = None
        self.file_path = 'data.xlsx'

        self.create_widgets()
        self.load_file(self.file_path)

    def create_widgets(self):
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        self.tree = ttk.Treeview(main_frame, show='headings')
        vsb = ttk.Scrollbar(main_frame, orient="vertical", command=self.tree.yview)
        hsb = ttk.Scrollbar(main_frame, orient="horizontal", command=self.tree.xview)
        self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)

        self.tree.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.E, tk.W))
        vsb.grid(row=0, column=1, sticky='ns')
        hsb.grid(row=1, column=0, sticky='ew')

        button_frame = ttk.Frame(main_frame, padding="10 0 0 0")
        button_frame.grid(row=2, column=0, columnspan=2, sticky=tk.W)

        buttons = [
            ("Максимум", lambda: self.show_extreme('max')),
            ("Минимум", lambda: self.show_extreme('min')),
            ("Сумма/Месяц", self.show_monthly_sums),
            ("Сумма/Число", self.show_daily_sums),
            ("Изменить данные", self.show_edit_popup),
            ("Среднее/Медиана", self.show_mean_median),
            ("Лучший день недели", self.show_best_weekday)
        ]

        for text, cmd in buttons:
            btn = tk.Button(button_frame, text=text, command=cmd, padx=8, pady=5)
            btn.pack(side=tk.LEFT, padx=2)

    def process_data(self):
        if self.df_raw is None: return
        df = self.df_raw.copy()
        df.columns = [str(col).strip().lower() for col in df.columns]
        day_col = df.columns[0]

        for col in df.columns[1:]:
            df[col] = pd.to_numeric(df[col], errors='coerce')

        self.df_melted = df.melt(id_vars=[day_col], var_name='Месяц', value_name='Значение').dropna()
        self.df_melted.columns = ['День', 'Месяц', 'Значение']

    def load_file(self, filepath):
        try:
            if os.path.exists(filepath):
                self.df_raw = pd.read_excel(filepath)
                self.process_data()
                self.update_table_display()
            else:
                messagebox.showwarning("Внимание", f"Файл {filepath} не найден.")
        except Exception as e:
            messagebox.showerror("Ошибка", f"Ошибка: {e}")

    def update_table_display(self):
        if self.df_raw is None: return
        self.tree.delete(*self.tree.get_children())
        cols = list(self.df_raw.columns)
        self.tree["columns"] = cols
        for col in cols:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=70, anchor="center")
        for idx, row in self.df_raw.iterrows():
            self.tree.insert("", tk.END, values=list(row))

    def show_extreme(self, mode):
        if self.df_melted is None: return
        val = self.df_melted['Значение'].max() if mode == 'max' else self.df_melted['Значение'].min()
        title = "Максимум" if mode == 'max' else "Минимум"
        dates = self.df_melted[self.df_melted['Значение'] == val]
        res = f"Значение: {val}\n\nДаты:\n"
        for _, r in dates.iterrows():
            res += f" - {int(r['День'])} {r['Месяц'].capitalize()}\n"
        self.display_text_popup(title, res)

    def show_monthly_sums(self):
        if self.df_melted is None: return
        res = self.df_melted.groupby('Месяц')['Значение'].sum().to_string()
        self.display_text_popup("Сумма по месяцам", res)

    def show_daily_sums(self):
        if self.df_melted is None: return
        res = self.df_melted.groupby('День')['Значение'].sum().to_string()
        self.display_text_popup("Сумма по числам", res)

    def show_edit_popup(self):
        popup = Toplevel(self.root)
        popup.title("Изменение")
        fields = ["День:", "Месяц:", "Значение:"]
        self.entries = []
        for i, f in enumerate(fields):
            tk.Label(popup, text=f).grid(row=i, column=0, padx=10, pady=5)
            e = tk.Entry(popup)
            e.grid(row=i, column=1, padx=10, pady=5)
            self.entries.append(e)
        tk.Button(popup, text="ОК", command=lambda: self.save_edit(popup)).grid(row=3, columnspan=2, pady=10)

    def save_edit(self, win):
        try:
            day = int(self.entries[0].get())
            month = self.entries[1].get().strip().lower()
            val = float(self.entries[2].get())
            col = next((c for c in self.df_raw.columns if str(c).lower() == month), None)
            if col:
                idx = self.df_raw[self.df_raw.iloc[:, 0] == day].index
                if not idx.empty:
                    self.df_raw.at[idx[0], col] = val
                    self.process_data()
                    self.update_table_display()
                    win.destroy()
                else: messagebox.showerror("Ошибка", "День не найден")
            else: messagebox.showerror("Ошибка", "Месяц не найден")
        except: messagebox.showerror("Ошибка", "Неверный ввод")

    def show_mean_median(self):
        if self.df_melted is None: return
        res = self.df_melted.groupby('Месяц')['Значение'].agg(['mean', 'median'])
        res.columns = ['Среднее', 'Медиана']
        self.display_text_popup("Статистика", res.to_string())

    def show_best_weekday(self):
        if self.df_melted is None: return
        m_map = {'январь': 1, 'февраль': 2, 'март': 3, 'апрель': 4, 'май': 5, 'июнь': 6,
                 'июль': 7, 'август': 8, 'сентябрь': 9, 'октябрь': 10, 'ноябрь': 11, 'декабрь': 12}
        temp = self.df_melted.copy()
        def get_wd(row):
            try:
                return pd.Timestamp(2026, m_map[str(row['Месяц']).lower().strip()], int(row['День'])).day_name()
            except: return None
        temp['WD'] = temp.apply(get_wd, axis=1)
        stats = temp.groupby('WD')['Значение'].sum()
        days_ru = {'Monday': 'Понедельник', 'Tuesday': 'Вторник', 'Wednesday': 'Среда',
                   'Thursday': 'Четверг', 'Friday': 'Пятница', 'Saturday': 'Суббота', 'Sunday': 'Воскресенье'}
        if not stats.empty:
            best = stats.idxmax()
            messagebox.showinfo("Результат", f"Лучший день: {days_ru[best]}\nСумма: {stats.max():.2f}")

    def display_text_popup(self, title, content):
        win = Toplevel(self.root)
        win.title(title)
        t = Text(win, height=15, width=45, padx=10, pady=10)
        t.pack()
        t.insert(tk.END, content)
        t.config(state=tk.DISABLED)

if __name__ == "__main__":
    root = tk.Tk()
    app = MeterApp(root)
    root.mainloop()