电表及销售统计Python应用及win程序2

news2024/11/16 16:32:08

接着上一篇给代码添加了表格功能,方便更好的处理数据。

import json
import os
from datetime import datetime
from tkinter import *
from tkinter import messagebox
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import pandas as pd

def update_data(filename, data_name, value):
    """更新数据文件中的数据"""
    with open(filename, 'r') as file:
        data = json.load(file)
    if data_name not in data:
        data[data_name] = []
    current_time = datetime.now().isoformat()
    if data[data_name]:
        prev_value = data[data_name][-1]['value']
        difference = value - prev_value
    else:
        difference = None
    data[data_name].append({"time": current_time, "value": value, "difference": difference})
    with open(filename, 'w') as file:
        json.dump(data, file)

def read_data(filename):
    """从数据文件中读取数据"""
    if os.path.exists(filename):
        with open(filename, 'r') as file:
            return json.load(file)
    return {}

class DataApp:
    def __init__(self, master):
        self.master = master
        self.master.title("数据记录器")
        self.filename = 'data_records.json'
        self.init_data_file()  # 调用初始化数据文件的方法
        # 创建输入框和按钮
        Label(master, text="数据名称:").grid(row=0)
        self.data_name_entry = Entry(master)
        self.data_name_entry.grid(row=0, column=1)

        Label(master, text="数据值:").grid(row=1)
        self.data_value_entry = Entry(master)
        self.data_value_entry.grid(row=1, column=1)

        self.update_button = Button(master, text="更新数据", command=self.update_data_gui)
        self.update_button.grid(row=2, column=1)

        self.analyze_button = Button(master, text="分析数据", command=self.analyze_data)
        self.analyze_button.grid(row=3, column=1)

        self.clear_button = Button(master, text="清空数据库", command=self.clear_data)
        self.clear_button.grid(row=4, column=1)

        self.quit_button = Button(master, text="退出", command=master.quit)
        self.quit_button.grid(row=5, column=1)

        # 图表区域
        self.figure = Figure(figsize=(6, 4), dpi=100)
        self.ax = self.figure.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.figure, master=master)
        self.canvas.get_tk_widget().grid(row=0, column=2, rowspan=6)

        # 初始化数据文件(如果文件不存在,则创建空字典)

    def init_data_file(self):
        if not os.path.exists(self.filename):
            with open(self.filename, 'w') as file:
                json.dump({}, file)

                # 数据清空功能

    def clear_data(self):
        confirm = messagebox.askyesno("警告", "您确定要清空所有数据吗?此操作不可逆!")
        if confirm:
            with open(self.filename, 'w') as file:
                json.dump({}, file)
            messagebox.showinfo("成功", "数据已清空。")
            self.analyze_data()  # 可选:清空后重新分析数据
        else:
            messagebox.showinfo("取消", "数据清空操作已取消。")
    # GUI版本的更新数据函数
    def update_data_gui(self):
        data_name = self.data_name_entry.get()
        try:
            new_value = float(self.data_value_entry.get())
            update_data(self.filename, data_name, new_value)
            messagebox.showinfo("成功", f"数据 {data_name} 已更新,并记录了差值和时间。")
        except ValueError:
            messagebox.showerror("错误", "请输入有效的数字!")

    # 数据分析图表函数
    def analyze_data(self):
        data_name = self.data_name_entry.get()
        data = read_data(self.filename)

        if data_name in data:
            times = [record["time"] for record in data[data_name]]
            values = [record["value"] for record in data[data_name]]
            differences = [record["difference"] for record in data[data_name]]

            self.ax.clear()
            self.ax.plot(times, values, label='Values', marker='o')
            self.ax.plot(times, differences, label='Differences', marker='x')

            # 在每个点旁边添加数值标签
            for i, (val, diff) in enumerate(zip(values, differences)):
                self.ax.text(times[i], val, f'{val:.2f}', ha='center', va='bottom')
                self.ax.text(times[i], diff, f'{diff:.2f}', ha='center', va='top')

            self.ax.legend()
            self.ax.set_title(f"{data_name} Analysis")
            self.canvas.draw()

            # 添加Excel导出按钮
            self.export_button = Button(self.master, text="导出至Excel", command=lambda: self.export_to_excel(data_name))
            self.export_button.grid(row=6, column=1)
        else:
            messagebox.showerror("错误", f"数据名称 {data_name} 未找到!")

    # Excel导出功能
    def export_to_excel(self, data_name):
        data = read_data(self.filename)

        if data_name in data:
            records = data[data_name]
            df = pd.DataFrame(records)
            df['Time'] = pd.to_datetime(df['time'], format='ISO8601')  # 明确指定格式
            df.rename(columns={'time': 'Time'}, inplace=True)

            # 使用ExcelWriter,并设置if_sheet_exists为'replace'来覆盖已存在的工作表
            with pd.ExcelWriter('data_records.xlsx', engine='openpyxl', mode='a', if_sheet_exists='replace') as writer:
                df.to_excel(writer, sheet_name=data_name, index=False)

            messagebox.showinfo("成功", f"数据 {data_name} 已导出到Excel文件。")
        else:
            messagebox.showerror("错误", f"数据名称 {data_name} 未找到!无法导出。")


# 主程序入口
if __name__ == "__main__":
    root = Tk()
    app = DataApp(root)
    root.mainloop()

效果如下

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1924306.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA设计模式>>结构型>>适配器模式

本文介绍23种设计模式中结构型模式的适配器模式 目录 1. 适配器模式 1.1 基本介绍 1.2 工作原理 1.3 适配器模式的注意事项和细节 1.4 类适配器模式 1.4.1 类适配器模式介绍 1.4.2 应用实例 1.4.3 注意事项和细节 1.5 对象适配器模式 1.5.1 基本介绍 1.5.2 …

visual studio 2019版下载以及与UE4虚幻引擎配置(过程记录)(官网无法下载visual studio 2019安装包)

一、概述 由于需要使用到UE4虚幻引擎,我使用的版本是4.27版本的,其官方默认的visual studio版本是2019版本的,相应的版本对应关系可以通过下面的官方网站对应关系查询。https://docs.unrealengine.com/4.27/zh-CN/ProductionPipelines/Develo…

java实现资产管理系统图形化用户界面

创建一个💕资产管理系统的GUI(图形用户界面)❤️画面通常需要使用Java的Swing或者JavaFX库。下面我将提供一个简单的资产管理系统GUI的示例代码,使用Java Swing库来实现。这个示例将包括一个主窗口,一个表格来显示资产…

捷配笔记-如何设计PCB板布线满足生产标准?

PCB板布线是铺设连接各种设备与通电信号的路径的过程。PCB板布线是铺设连接各种设备与通电信号的路径的过程。 在PCB设计中,布线是完成产品设计的重要步骤。可以说,之前的准备工作已经为它做好了。在整个PCB设计中,布线设计过程具有最高的极限…

Web浏览器通过串口读取RFID卡号js JavaScript

本示例使用的读卡器&#xff1a;USB转RS232COM虚拟串口RFID读卡器主动读卡Web浏览器Andro、Linux-淘宝网 (taobao.com) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"…

翁恺-C语言程序设计-05-3. 求a的连续和

05-3. 求a的连续和 输入两个整数a和n&#xff0c;a的范围是[0,9]&#xff0c;n的范围是[1,8]&#xff0c;求数列之和S aaaaaa…aaa…a&#xff08;n个a&#xff09;。如a为2、n为8时输出的是222222…22222222的和。 输入格式&#xff1a; 输入在一行中给出两个整数&#xf…

深入了解 MySQL 的 EXPLAIN 命令

一、什么是 EXPLAIN 命令&#xff1f; EXPLAIN 命令用于显示 MySQL 如何执行某个 SQL 语句&#xff0c;尤其是 SELECT 语句。通过 EXPLAIN 命令&#xff0c;可以看到查询在实际执行前的执行计划&#xff0c;这对于优化查询性能至关重要。 二、EXPLAIN 的基本用法 要使用 EXP…

【算法篇】KMP算法,一种高效的字符串匹配算法

我们今天了解一个字符串匹配算法-KMP算法&#xff0c;内容难度相对来说较高&#xff0c;建议先收藏再细品&#xff01;&#xff01;&#xff01; KMP算法的基本概念 KMP算法是一种高效的字符串匹配算法&#xff0c;由D.E.Knuth&#xff0c;J.H.Morris和V.R.Pratt提出的&#…

Cxx Primer-CP-2

开篇第一句话足见作者的高屋建瓴&#xff1a;类型决定程序中数据和操作的意义。随后列举了简单语句i i j;的意义取决于i和j的类型。若它们都是整形&#xff0c;则为通常的算术意义。若它们都为字符串型&#xff0c;则为进行拼接操作。若为用户自定义的class类型&#xff0c;则…

《Linux系统编程篇》Visual Studio Code配置下载,中文配置,连接远程ssh ——基础篇

引言 vscode绝对值得推荐&#xff0c;非常好用&#xff0c;如果你能体会其中的奥妙的话。 工欲善其事&#xff0c;必先利其器 ——孔子 文章目录 引言下载VS Code配置VS Code中文扩展连接服务器 连接服务器测试确定服务器的IP地址VS code 配置ssh信息选择连接到主机选择这个添…

K8s学习笔记1-搭建k8s集群

本次使用kubeadm方式&#xff0c;部署1.23.17版本 安装包百度云盘地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1UrIotP253DoyDIYB7G1C0Q 提取码&#xff1a;8q6a 集群所需虚拟机环境 主机名称IP资源harbor10.0.0.2301c2gmaster10.0.0.2312c4gworker110.0.0…

全新UI自助图文打印系统源码(含前端小程序源码 PHP后端 数据库)

最新自助图文打印系统和证件照云打印小程序源码PHP后端&#xff0c;为用户用户自助打印的服务&#xff0c;包括但不限于文档、图片、表格等多种格式的文件。此外&#xff0c;它们还提供了诸如美颜、换装、文档打印等功能&#xff0c;以及后台管理系统&#xff0c;方便管理员对打…

7.13 专题训练DP

P1255 数楼梯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) ac代码 #include<bits/stdc.h> using namespace std; typedef long long ll; #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) const ll mod 1e97;int main() {IOS;int n;cin>>n;int a[…

面向对象与C++进阶—并发与多线程篇

文章目录 18. 并发与多线程篇说在前面(1).线程和进程(2).并发和并行(3).thread(C11)#1.thread库与thread类#2.join和detach方法#3.id类和get_id方法#4.this_thread和系列操作 (4).原子操作#1.为什么是原子?#2.为什么需要原子操作&#xff1f;#3.atomic库 (5).竞态条件(6).线程…

7-1、2、3 IPFS介绍使用及浏览器交互(react+区块链实战)

7-1、2、3 IPFS介绍使用及浏览器交互&#xff08;react区块链实战&#xff09; 7-1 ipfs介绍7-2 IPFS-desktop使用7-3 reactipfs-api浏览器和ipfs交互 7-1 ipfs介绍 IPFS区块链上的文件系统 https://ipfs.io/ 这个网站本身是需要科学上网的 Ipfs是点对点的分布式系统 无限…

TEB局部路径规划算法代码及原理解读

TEB(Timed Elastic Band) 是一个基于图优化的局部路径规划算法&#xff0c;具有较好的动态避障能力&#xff0c;在ROS1/ROS2的导航框架中均被采用。该图优化以g2o优化框架实现&#xff0c;以机器人在各个离散时刻的位姿和离散时刻之间的时间间隔为顶点&#xff0c;约束其中的加…

IEEE(常用)参考文献引用格式详解 | LaTeX参考文献规范(IEEE Trans、Conf、Arxiv)

IEEE参考文献引用格式注意事项 期刊已正式出版&#xff08;有期卷号&#xff09;录用后在线访问即Early access&#xff08;无期卷号&#xff09; Arxiv论文会议论文IEEE缩写进阶其他 IEEE论文投稿前的参考文献格式检查&#xff01;&#xff08;如果一些细节你采用别的形式&…

UE4 解决创建布料报错:三角形退化

**【问题】**创建创建布料时报错&#xff1a;三角形退化 【方法】 1.要重新绑定&#xff1a;导入到ue4为静态网格体&#xff0c;勾选“移除退化”&#xff0c;再导出fbx&#xff0c;再重新绑定 2.不用重新绑定&#xff1a;使用排除法&#xff08;费时&#xff09;&#xff0c…

开放式耳机选哪个牌子好?五大主流王炸爆款推荐!

在快节奏的现代生活中&#xff0c;音乐是不可或缺的慰藉。作为音乐迷&#xff0c;我追求音质卓越与佩戴舒适的耳机。开放式蓝牙耳机&#xff0c;以革新设计和技术&#xff0c;颠覆传统认知&#xff0c;既呈现高品质音乐盛宴&#xff0c;又确保长久佩戴的极致舒适&#xff0c;成…

记一次,由于发布配置引发的alpine中运行sqlite3的错误解决历程思路!

使用net的都知道&#xff0c;打包镜像的时候的基础包有2个选择(实际上更多) 比如我们使用aspnet6.0作为基础包&#xff0c;则有2个选择 mcr.microsoft.com/dotnet/aspnet:6.0 212MB (basic) mcr.microsoft.com/dotnet/aspnet:6.0-alpine 104MB (alpine) 问题回顾 目前的Past…