【问题标题】:PySimpleGUI that generates a table of summary statistics and histogram in one plotPySimpleGUI,在一个图中生成汇总统计和直方图表
【发布时间】:2021-12-13 19:48:19
【问题描述】:

我在 Python 中遇到了问题。请看下面的代码。它在控制台中生成汇总统计信息和直方图。但是,我想使用 PySimpleGUI 创建一个 GUI,它将提供一个 GUI,允许用户更改绘图的参数,因此每次都会生成新的直方图和汇总统计信息。我对如何进行此操作一无所知,因为我对 Python 和 Stack Overflow 还是很陌生。我希望在运行代码时出现一个用户界面,要求用户更改用于生成绘制直方图的数据集的方程中的参数。 `

import PySimpleGUI as sg
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.ticker import PercentFormatter


def read_table():
    sg.set_options(auto_size_buttons=True)
    filename = sg.popup_get_file(
        'Dataset to read',
        title='Dataset to read',
        no_window=True,
        file_types=(("CSV Files", ".csv"), ("Text Files", "*.txt")))
    # --- populate table with file contents --- #
    if filename == '':
        return

    colnames_prompt = sg.popup_yes_no('Does this file have column names already?')
    nan_prompt = sg.popup_yes_no('Drop NaN entries?')

    if filename is not None:
        fn = filename.split('/')[-1]
        try:
            if colnames_prompt == 'Yes':
                df = pd.read_csv(filename, sep=',', engine='python')
                # Uses the first row (which should be column names) as columns names
                header_list = list(df.columns)
                # Drops the first row in the table (otherwise the header names and the first row will be the same)
                data = df[1:].values.tolist()
            else:
                df = pd.read_csv(filename, sep=',', engine='python', header=None)
                # Creates columns names for each column ('column0', 'column1', etc)
                header_list = ['column' + str(x) for x in range(len(df.iloc[0]))]
                df.columns = header_list
                # read everything else into a list of rows
                data = df.values.tolist()
            # NaN drop?
            if nan_prompt == 'Yes':
                df = df.dropna()

            return df, data, header_list, fn
        except:
            sg.popup_error('Error reading file')
            return


def show_table(data, header_list, fn):
    layout = [
        [sg.Table(values=data,
                  headings=header_list,
                  font='Helvetica',
                  pad=(25, 25),
                  display_row_numbers=False,
                  auto_size_columns=True,
                  num_rows=min(25, len(data)))]
    ]

    window = sg.Window(fn, layout, grab_anywhere=False)
    event, values = window.read()
    window.close()


def show_stats(df):
    stats = df.describe().T
    header_list = list(stats.columns)
    data = stats.values.tolist()
    for i, d in enumerate(data):
        d.insert(0, list(stats.index)[i])
    header_list = ['Summary Statistics'] + header_list
    layout = [
        [sg.Table(values=data[12:],
                  headings=header_list,
                  font='Helvetica',
                  pad=(12, 12),
                  display_row_numbers=False,
                  auto_size_columns=True,
                  num_rows=min(25, len(data)))]
    ]

    window = sg.Window("Statistics", layout, grab_anywhere=False)
    event, values = window.read()
    window.close()


def plot_fig(df):
    """
    Plots
    """
    # Identify link to arrays
    input_file = r"input_csv_files/testfile.csv"

    # Read input files using pandas dataframe
    data_hss = pd.read_csv(input_file, na_values=':', usecols=['result1'])
    data_sp = pd.read_csv(input_file, na_values=':', usecols=['result2'])

    # Read input files from one file
    data = pd.read_csv(input_file, na_values=':', usecols=['result1', 'result2'])

    # Prepare files by eliminating NaN values
    dataDrop_hss = data_hss.dropna(how='any', subset=['result1'], axis=0)
    dataDrop_sp = data_sp.dropna(how='any', subset=['result2'], axis=0)

    # Make a separate list for each histogram
    hss = list(dataDrop_hss['result1'])
    s_p = list(dataDrop_sp['result2'])

    # Assign colors to each histogram and the legend names
    colors = ['tab:blue', 'tab:orange']
    names = ['hss', 'sp']

    # Plot the histogram
    fig, ax1 = plt.subplots()
    ax1.hist([hss, s_p], bins=20, label=names, color=colors)
    ax1.set_xlim(-0.14, 0.30)
    ax1.set_ylim(0, 120)
    plt.gca().xaxis.set_major_formatter(PercentFormatter(1))

    # Format the plots
    plt.xlabel('Return')
    plt.ylabel('Count')
    plt.title('hss and sp')
    plt.legend(loc='upper right')

    # ------------------------------- END OF YOUR MATPLOTLIB CODE -------------------------------

    # ------------------------------- Beginning of Matplotlib helper code -----------------------

    def draw_figure(canvas, figure):
        figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
        figure_canvas_agg.draw()
        figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1)
        return figure_canvas_agg

    # ------------------------------- Beginning of GUI CODE -------------------------------

    # Define the window layout
    layout = [[sg.Text('Plot test')],
              [sg.Canvas(key='-CANVAS-')],
              [sg.Button('Ok')]]

    # create the form and show it without the plot
    window = sg.Window('graph', layout, location=(0, 0), finalize=True, element_justification='center',
                       font='Helvetica 18', resizable=True)

    # Add the plot to the window
    draw_figure(window['-CANVAS-'].TKCanvas, fig)

    event, values = window.read()

    window.close()


def main():
    df, data, header_list, fn = read_table()

    # Show data?
    show_prompt = sg.popup_yes_no('Show the dataset?')
    if show_prompt == 'Yes':
        show_table(data, header_list, fn)

    # Show stats?
    stats_prompt = sg.popup_yes_no('Show the descriptive stats?')
    if stats_prompt == 'Yes':
        show_stats(df)

    # Show a plot?
    plot_prompt = sg.popup_yes_no('Show a histogram plot?')
    if plot_prompt == 'Yes':
        plot_fig(df)


# Executes main
if __name__ == '__main__':
    main()

`

这是我得到的汇总统计输出,但我没有用户界面供用户更改输入变量以操作图表和汇总统计

直方图:

汇总统计:

【问题讨论】:

  • 可能首先创建带有一些用于参数的输入/输入/文本字段的 GUI,并使用按钮运行函数,该函数将从小部件中获取参数并进行计算。
  • 谢谢。这是我的问题。我可以看到如何创建 GUI,但是如何使按钮能够使用输入参数进行计算?换句话说,如何将用户输入链接到执行计算的函数定义?
  • 你不要链接它 - 每个小部件都有自己的 key 并且 Button 应该运行从小部件获取值并使用值运行计算的函数。
  • 谢谢。例如,当我运行我的代码时,我得到了@Jason Yang 显示的界面。但是如果我点击直方图栏,什么也不会发生。显示统计信息栏产生预期的输出。我需要在那里放什么key
  • 您是否在控制台中运行它以查看错误消息?您是否将函数添加到代码中?如果您没有添加,那么它可能会在控制台而不是预期的窗口中显示错误消息。并查看答案中的代码 - 在Input(key='Dataset') 中有key,后来它使用event, values = window.read() 从GUI 获取所有值,并使用values["Dataset"]Input(key='Dataset') 获取值 - 所以它使用相同的DatasetInput()中有key='Dataset'

标签: python user-interface pysimplegui


【解决方案1】:

您需要花时间为您的应用程序设计 GUI,如果可能的话,一个主窗口。

下面为你展示示例

from pathlib import Path

import PySimpleGUI as sg
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.ticker import PercentFormatter


def load_dataset(filename, headings, nan):

    if not Path(filename).is_file():
        return None
    window['Status'].update('file loading ...')
    window.refresh()

    try:
        if headings:
            df = pd.read_csv(filename, sep=',', engine='python')
            header_list = list(df.columns)
            data = df[1:].values.tolist()
        else:
            df = pd.read_csv(filename, sep=',', engine='python', header=None)
            header_list = ['column' + str(x) for x in range(len(df.iloc[0]))]
            df.columns = header_list
            data = df.values.tolist()
        if nan:
            df = df.dropna()
        window['Status'].update('File loaded')
        return df, data, header_list, Path(filename).name
    except:
        window['Status'].update('Error reading file')
        return None


def show_table(data, header_list, fn):

    layout = [
        [sg.Table(values=data,
                  headings=header_list,
                  font='Helvetica',
                  pad=(25, 25),
                  display_row_numbers=False,
                  auto_size_columns=True,
                  num_rows=min(25, len(data)))]
    ]

    sg.Window(fn, layout).read(close=True)

def show_statistics(df):

    stats = df.describe().T
    header_list = list(stats.columns)
    data = stats.values.tolist()
    for i, d in enumerate(data):
        d.insert(0, list(stats.index)[i])
    header_list = ['Summary Statistics'] + header_list

    layout = [
        [sg.Table(values=data[12:],
                  headings=header_list,
                  font='Helvetica',
                  pad=(12, 12),
                  display_row_numbers=False,
                  auto_size_columns=True,
                  num_rows=min(25, len(data)))]
    ]

    sg.Window("Statistics", layout).read(close=True)

def show_histogram(df):
    """
    Plots
    """
    # Identify link to arrays
    input_file = r"input_csv_files/testfile.csv"

    # Read input files using pandas dataframe
    data_hss = pd.read_csv(input_file, na_values=':', usecols=['result1'])
    data_sp = pd.read_csv(input_file, na_values=':', usecols=['result2'])

    # Read input files from one file
    data = pd.read_csv(input_file, na_values=':', usecols=['result1', 'result2'])

    # Prepare files by eliminating NaN values
    dataDrop_hss = data_hss.dropna(how='any', subset=['result1'], axis=0)
    dataDrop_sp = data_sp.dropna(how='any', subset=['result2'], axis=0)

    # Make a separate list for each histogram
    hss = list(dataDrop_hss['result1'])
    s_p = list(dataDrop_sp['result2'])

    # Assign colors to each histogram and the legend names
    colors = ['tab:blue', 'tab:orange']
    names = ['hss', 'sp']

    # Plot the histogram
    fig, ax1 = plt.subplots()
    ax1.hist([hss, s_p], bins=20, label=names, color=colors)
    ax1.set_xlim(-0.14, 0.30)
    ax1.set_ylim(0, 120)
    plt.gca().xaxis.set_major_formatter(PercentFormatter(1))

    # Format the plots
    plt.xlabel('Return')
    plt.ylabel('Count')
    plt.title('hss and sp')
    plt.legend(loc='upper right')

    # ------------------------------- END OF YOUR MATPLOTLIB CODE -------------------------------

    # ------------------------------- Beginning of Matplotlib helper code -----------------------

    def draw_figure(canvas, figure):
        figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
        figure_canvas_agg.draw()
        figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1)
        return figure_canvas_agg

    # ------------------------------- Beginning of GUI CODE -------------------------------

    # Define the window layout
    layout = [[sg.Text('Plot test')],
              [sg.Canvas(key='-CANVAS-')],
              [sg.Button('Ok')]]

    # create the form and show it without the plot
    window = sg.Window('graph', layout, location=(0, 0), finalize=True, element_justification='center',
                       font='Helvetica 18', resizable=True)

    # Add the plot to the window
    draw_figure(window['-CANVAS-'].TKCanvas, fig)

    window.read(close=True)


layout = [
    [sg.Text("Dateset"),
     sg.Checkbox("With column names", enable_events=True, key="Headings"),
     sg.Checkbox("Drop NaN entries", enable_events=True, key="NaN")],
    [sg.Input(key='Dataset'), sg.FileBrowse()],
    [sg.Button("Show Dataset"), sg.Button("Show Statistics"), sg.Button("Show Histogram")],
    [sg.StatusBar('', size=20, expand_x=True, key='Status')],
]

window = sg.Window("Dataset", layout, finalize=True)
filename = None
load = False
while True:

    event, values = window.read()

    if event == sg.WINDOW_CLOSED:
        break
    if filename != values["Dataset"] or event in ("Headings", "NaN"):
        filename, headings, nan = values["Dataset"], values['Headings'], values['NaN']
        result = load_dataset(filename, headings, nan)
        if result:
            load = True
            df, data, header_list, fn = result
        else:
            load = False
    if not load:
        continue
    if event == "Show Dataset":
        show_table(data, header_list, fn)
    elif event == "Show Statistics":
        show_statistics(df)
    elif event == "Show Histogram":
        show_histogram(df)

window.close()

【讨论】:

  • 谢谢,杰森。这有助于生成 GUI。使用它,我在脚本中定义了我的函数,但不知何故,按钮没有链接到函数。例如,当我单击直方图时,在定义我的函数后,什么也没有发生。我需要在我的代码中调用一个命令来允许这种情况发生吗?
  • 你好@Jason Yang 和@furas,我需要在这个界面中添加什么键才能使直方图在点击时激活?我很难理解这个概念。任何见解将不胜感激。我很惊讶“显示统计”按钮能够在没有分配任何 key 的情况下运行,但“显示直方图”按钮在单击时不会运行。
  • 如果keyk 两个选项都未指定,则sg.Button 的第一个选项button_text 将用作此按钮的键。从window.read() 中获取eventvaluesevent 将成为按钮按下时的按键。注意按钮文本的拼写和用于比较的文本event,它们应该是相同的并且区分大小写。
  • 应该注意key不能在一个窗口中重复,否则key会被隐式替换为带索引的key。
  • 只需将你的代码添加到我的示例代码中,未经测试,可能有问题,IMO,你可以自己修改。
猜你喜欢
  • 1970-01-01
  • 2020-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多