import datetime import tkinter import copy from tkinter import * import numpy as np import matplotlib import matplotlib.pyplot as plt from matplotlib.pylab import mpl from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk import pandas as pd from arknights_gacha_analysis_new import ArknightsInfo class ArknightsInfoDisplay(Frame): """一个经典的GUI写法""" def __init__(self, ark_info, master=None): """初始化方法""" super().__init__(master) # 调用父类的初始化方法 self.figure = None self.ark_info = ark_info self.master = master self.pack(side=TOP, fill=BOTH, expand=1) # 此处填充父窗体 self.create_matplotlib() self.createWidget(self.figure) # 添加图1区域按钮 banner_title = [item for item in self.ark_info.data_dict_by_banner] y_axis, x_axis = 120, 10 for item in banner_title: tkinter.Button(self.master, text=item, command=lambda item=item: self.change_fig1_content(item), width=10).place(x=x_axis, y=10 + y_axis) y_axis += 30 if y_axis >= 500: y_axis = 120 x_axis += 80 # 添加图2区域按钮 y_axis, x_axis = 120, 1750 tkinter.Button(self.master, text='Separate by Star', command=lambda: self.change_fig2_content('separated'), width=20).place(x=x_axis, y=10 + y_axis) tkinter.Button(self.master, text='Total Pull Count', command=lambda: self.change_fig2_content('sum'), width=20).place(x=x_axis, y=40 + y_axis) tkinter.Button(self.master, text='Stacked Pull Count', command=lambda: self.change_fig2_content('stacked'), width=20).place(x=x_axis, y=70 + y_axis) tkinter.Button(self.master, text='Probability Separated', command=lambda: self.change_fig2_content('separated', True), width=20).place(x=x_axis, y=100 + y_axis) tkinter.Button(self.master, text='Probability Six Star', command=lambda: self.change_fig2_content('six_star_only', True), width=20).place(x=x_axis, y=130 + y_axis) def change_fig1_content(self, banner_name): # print(banner_name) self.fig1.clear() self.fig3.clear() pull_count = self.ark_info.data_dict_by_banner[banner_name]['analysis']['total_pull'] self.gacha_data_visualization(self.fig1, self.ark_info.data_dict_by_banner[banner_name]['analysis'], title=f'{banner_name}({pull_count} pulls)') self.pull_time_visualization(self.fig3, banner=banner_name, mode='T') self.canvas.draw() def change_fig2_content(self, mode, probability_flag=False): self.fig2.clear() if not probability_flag: self.show_all_banner_basic_info(self.fig2, mode) else: self.show_all_banner_probability(self.fig2, mode) self.canvas.draw() def createWidget(self, figure): """创建组件""" # self.label = Label(self, text='这是一个Tkinter和Matplotlib相结合的小例子') # self.label.pack() # 创建画布 self.canvas = FigureCanvasTkAgg(figure, self) self.canvas.draw() self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1) # 把matplotlib绘制图形的导航工具栏显示到tkinter窗口上 # toolbar = NavigationToolbar2Tk(self.canvas, self) # toolbar.update() # self.canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1) # self.button = Button(master=self, text="退出", command=quit) # # 按钮放在下边 # self.button.pack(side=BOTTOM) def create_matplotlib(self): """创建绘图对象""" # 设置中文显示字体 mpl.rcParams['font.sans-serif'] = ['SimHei'] # 中文显示 mpl.rcParams['axes.unicode_minus'] = False # 负号显示 # 创建绘图对象f figsize的单位是英寸 像素 = 英寸*分辨率na self.figure = plt.figure(num=2, figsize=(7, 4), dpi=120, edgecolor='green', frameon=True) # 一张图上显示4张小图 self.fig1 = plt.subplot(2, 2, 1) # 先进行分块,最后一个参数是序号 self.gacha_data_visualization(self.fig1, self.ark_info.all_result_for_show, f'All Banner Result({self.ark_info.all_result_for_show["total_pull"]} pulls)') self.fig2 = plt.subplot(2, 2, 2) self.show_all_banner_basic_info(self.fig2, 'separated') self.fig3 = plt.subplot(2, 2, 3) self.ax3 = plt.gca() self.pull_time_visualization(self.fig3) # self.show_all_banner_probability(self.fig3) self.fig4 = plt.subplot(2, 2, 4) # self.setplot(fig4, x, y4, 'y=square(x)', 'gold') x = np.arange(12) y = np.random.uniform(0.5, 1.0, 12) * (1 - x / float(12)) loc = zip(x, y) # 将x, y 两两配对 plt.ylim(0, 1.2) # 设置y轴的范围 plt.bar(x, y, facecolor='green', edgecolor='black') # 绘制柱状图(填充颜色绿色,边框黑色) for x, y in loc: plt.text(x + 0.1, y + 0.01, '%.2f' % y, ha='center', va='bottom') def setplot(self, fig, x, y, text, color='r'): """绘制子图""" line = fig.plot(x, y, color=color, label=text) fig.set_xlabel('(x)横坐标') # 确定坐标轴标题 fig.set_ylabel("(y)纵坐标") fig.grid(which='major', axis='x', color='gray', linestyle='-', linewidth=0.5, alpha=0.2) # 设置网格 fig.legend(loc='lower right', facecolor='orange', frameon=True, shadow=True, framealpha=0.7) def gacha_data_visualization(self, fig, data_dict, title='All Banner Result'): fig.set_xlabel(title) label = ['3 Star', '4 Star', '5 Star', '6 Star'] explode = [0.01, 0.01, 0.01, 0.01] data = [values for _key, values in data_dict['by_star'].items()] for i in range(len(data)): label[i] += f": {data[i]}" fig.pie(data, explode=explode, labels=label, autopct='%1.2f%%') def pull_time_visualization(self, fig, banner='全部结果', mode='M'): mode_list = ['Y', 'M', 'D', 'H', 'T', 'S'] if banner == '全部结果': mode = 'M' raw_time_dict = self.ark_info.data_dict_by_banner[banner]['gacha_result_by_time'] start_time = (list(raw_time_dict.values())[0][1] - datetime.timedelta(seconds=60)).strftime('%Y-%m-%d %H:%M:%S') end_time = (list(raw_time_dict.values())[-1][1] + datetime.timedelta(seconds=60)).strftime('%Y-%m-%d %H:%M:%S') new_time_dict = {key: len(item[0]) for key, item in raw_time_dict.items()} new_time_dict[start_time] = 0 new_time_dict[end_time] = 0 s = copy.deepcopy(pd.Series(new_time_dict)) s.index = pd.to_datetime(s.index) # 重采样并求和 resampled = s.resample(mode).sum() while len(resampled) > 10000: try: resampled = s.resample(mode_list[mode_list.index(mode)-1]).sum() except: break resampled.plot(style='-', label=banner, ax=self.ax3) fig.set_xlabel(banner) # time_series = [item[1] for item in raw_time_dict.values()] # pull_count_list = [len(item[0]) for item in raw_time_dict.values()] # # fig.plot(time_series, pull_count_list, label=banner) # start_time = self.time_filter(list(raw_time_dict.values())[0][1], mode).strftime('%Y-%m-%d %H:%M:%S') # end_time = self.time_filter(list(raw_time_dict.values())[-1][1], mode).strftime('%Y-%m-%d %H:%M:%S') # time_stamp = pd.date_range(start=start_time, end=end_time, freq=mode_dict[mode], normalize=False) # time_dict = {str(item): 0 for item in time_stamp} # for item in raw_time_dict.values(): # new_time = self.time_filter(item[1], mode) # if new_time.strftime('%Y-%m-%d %H:%M:%S') not in time_dict: # time_dict[new_time.strftime('%Y-%m-%d %H:%M:%S')] = len(item[0]) # else: # time_dict[new_time.strftime('%Y-%m-%d %H:%M:%S')] += len(item[0]) # # fig.plot(time_dict.keys(), time_dict.values(), label=banner) # # tick_spacing = int(len(time_dict) / 10) + 1 # ax3.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(tick_spacing)) # ax3.tick_params(axis='x', labelrotation=45, labelsize=8) fig.legend() @staticmethod def time_filter(target_time, mode=4): filter_list = [target_time.year, target_time.month, target_time.day, target_time.hour, target_time.minute, target_time.second] for i in range(len(filter_list)): if i >= mode: filter_list[i] = 0 return datetime.datetime(filter_list[0], filter_list[1], filter_list[2], filter_list[3], filter_list[4], filter_list[5]) def show_all_banner_basic_info(self, fig, mode='separated'): tmp_dict = self.ark_info.data_dict_by_banner banner_title = [item for item in tmp_dict][0:-1:1] banner_data_3 = [value['analysis']['by_star']['3'] for _key, value in tmp_dict.items()][0:-1:1] banner_data_4 = [value['analysis']['by_star']['4'] for _key, value in tmp_dict.items()][0:-1:1] banner_data_5 = [value['analysis']['by_star']['5'] for _key, value in tmp_dict.items()][0:-1:1] banner_data_6 = [value['analysis']['by_star']['6'] for _key, value in tmp_dict.items()][0:-1:1] banner_data_sum = [value['analysis']['total_pull'] for _key, value in tmp_dict.items()][0:-1:1] if mode == 'separated': self.show_separated_data(fig, banner_title, banner_data_3, banner_data_4, banner_data_5, banner_data_6) elif mode == 'sum': self.show_sum_data(fig, banner_title, banner_data_sum, 'Total Pulls') elif mode == 'stacked': self.show_stacked_data(fig, banner_title, banner_data_3, banner_data_4, banner_data_5, banner_data_6) def show_all_banner_probability(self, fig, mode='separated'): tmp_dict = self.ark_info.data_dict_by_banner banner_title = [item for item in tmp_dict] banner_data_3 = [value['analysis']['three_star_percent'] for _key, value in tmp_dict.items()] banner_data_4 = [value['analysis']['four_star_percent'] for _key, value in tmp_dict.items()] banner_data_5 = [value['analysis']['five_star_percent'] for _key, value in tmp_dict.items()] banner_data_6 = [value['analysis']['six_star_percent'] for _key, value in tmp_dict.items()] if mode == 'separated': self.show_separated_data(fig, banner_title, banner_data_3, banner_data_4, banner_data_5, banner_data_6) elif mode == 'six_star_only': self.show_sum_data(fig, banner_title, banner_data_6, 'Six Star Probability') def show_separated_data(self, fig, banner_title, banner_data_3, banner_data_4, banner_data_5, banner_data_6): y_axis = np.arange(len(banner_title)) width = 0.25 fig.barh(y_axis + width / 2, banner_data_3, width / 2, label='3 star') fig.barh(y_axis, banner_data_4, width / 2, label='4 star') fig.barh(y_axis - width / 2, banner_data_5, width / 2, label='5 star') fig.barh(y_axis - width, banner_data_6, width / 2, label='6 star') fig.set_yticks(y_axis, banner_title) # 添加数值标签 for i in y_axis: fig.text(x=banner_data_6[i] + 1, y=i - width, s=round(banner_data_6[i], 2), ha='center', fontsize=8, family='Calibri', va='center') fig.text(x=banner_data_5[i] + 1, y=i - width / 2, s=round(banner_data_5[i], 2), ha='center', fontsize=8, family='Calibri', va='center') fig.text(x=banner_data_4[i] + 1, y=i, s=round(banner_data_4[i], 2), ha='center', fontsize=8, family='Calibri', va='center') fig.text(x=banner_data_3[i] + 1, y=i + width / 2, s=round(banner_data_3[i], 2), ha='center', fontsize=8, family='Calibri', va='center') fig.legend() def show_stacked_data(self, fig, banner_title, banner_data_3, banner_data_4, banner_data_5, banner_data_6): y_axis = np.arange(len(banner_title)) width = 0.8 fig.barh(y_axis, banner_data_3, width, label='3 star') fig.barh(y_axis, banner_data_4, width, left=banner_data_3, label='4 star') fig.barh(y_axis, banner_data_5, width, left=[banner_data_3[i] + banner_data_4[i] for i in range(len(banner_data_4))], label='5 star') fig.barh(y_axis, banner_data_6, width, label='6 star', left=[banner_data_3[i] + banner_data_4[i] + banner_data_5[i] for i in range(len(banner_data_4))]) fig.set_yticks(y_axis, banner_title) # 添加数值标签 # off_set = -0.1 # for i in y_axis: # fig.text(x=banner_data_6[i] + 1, y=i - width + off_set, s=round(banner_data_6[i], 2), # ha='center', fontsize=8, family='Calibri') # fig.text(x=banner_data_5[i] + 1, y=i - width / 2 + off_set, s=round(banner_data_5[i], 2), # ha='center', fontsize=8, family='Calibri') # fig.text(x=banner_data_4[i] + 1, y=i + off_set, s=round(banner_data_4[i], 2), # ha='center', fontsize=8, family='Calibri') # fig.text(x=banner_data_3[i] + 1, y=i + width / 2 + off_set, s=round(banner_data_3[i], 2), # ha='center', fontsize=8, family='Calibri') fig.legend() def show_sum_data(self, fig, banner_title, sum_data, label='Total Pulls'): y_axis = np.arange(len(banner_title)) width = 0.8 fig.barh(y_axis, sum_data, width, label=label) fig.set_yticks(y_axis, banner_title) # 添加数值标签 for i in y_axis: fig.text(x=sum_data[i] / 2, y=i, s=round(sum_data[i], 2), ha='center', va='center', fontsize=8, family='Calibri', color='w') fig.legend() def destroy(self): """重写destroy方法""" super().destroy() quit() def quit(self): """点击退出按钮时调用这个函数""" root.quit() # 结束主循环 root.destroy() # 销毁窗口 if __name__ == '__main__': root = Tk() root.title('Arknights Info Panel') root.geometry('1920x1200') # app = ArknightsInfoDisplay(ArknightsInfo('18021026530'), master=root) app = ArknightsInfoDisplay(ArknightsInfo('13693680360'), master=root) root.mainloop()