Identify all code logic errors in this python code "import wx
import wx.ribbon as RB
import wx.grid as gridlib
import pandas as pd
import numpy as np
import pyEDM
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from mpl_toolkits.mplot3d import Axes3D


class SimplexFrame(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='PyEDM Simplex Projection', size=(1200, 800))
        self.InitUI()

    def InitUI(self):
        panel = wx.Panel(self)

        # Create ribbon
        self.ribbon = RB.RibbonBar(panel, wx.ID_ANY)

        # Data tab
        data_page = RB.RibbonPage(self.ribbon, wx.ID_ANY, "Data")
        data_panel = RB.RibbonPanel(data_page, wx.ID_ANY, "Data Operations")
        data_bar = RB.RibbonButtonBar(data_panel)

        load_button_id = wx.NewIdRef()
        data_bar.AddButton(load_button_id, "Load Data", wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER))
        self.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnLoadData, id=load_button_id)

        new_button_id = wx.NewIdRef()
        data_bar.AddButton(new_button_id, "New Data", wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_OTHER))
        self.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnNewData, id=new_button_id)

        save_button_id = wx.NewIdRef()
        data_bar.AddButton(save_button_id, "Save Data", wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_OTHER))
        self.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnSaveData, id=save_button_id)

        random_data_button_id = wx.NewIdRef()
        data_bar.AddButton(random_data_button_id, "Generate Random Data",
                           wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_OTHER))
        self.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnGenerateRandomData,
                  id=random_data_button_id)

        row_col_panel = RB.RibbonPanel(data_page, wx.ID_ANY, "Row/Column Operations")
        row_col_bar = RB.RibbonButtonBar(row_col_panel)

        add_row_button_id = wx.NewIdRef()
        row_col_bar.AddButton(add_row_button_id, "Add Row", wx.ArtProvider.GetBitmap(wx.ART_PLUS, wx.ART_OTHER))
        self.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnAddRow, id=add_row_button_id)

        remove_row_button_id = wx.NewIdRef()
        row_col_bar.AddButton(remove_row_button_id, "Remove Row", wx.ArtProvider.GetBitmap(wx.ART_MINUS, wx.ART_OTHER))
        self.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnRemoveRow, id=remove_row_button_id)

        add_col_button_id = wx.NewIdRef()
        row_col_bar.AddButton(add_col_button_id, "Add Column", wx.ArtProvider.GetBitmap(wx.ART_PLUS, wx.ART_OTHER))
        self.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnAddColumn, id=add_col_button_id)

        remove_col_button_id = wx.NewIdRef()
        row_col_bar.AddButton(remove_col_button_id, "Remove Column",
                              wx.ArtProvider.GetBitmap(wx.ART_MINUS, wx.ART_OTHER))
        self.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnRemoveColumn, id=remove_col_button_id)

        # Settings tab
        settings_page = RB.RibbonPage(self.ribbon, wx.ID_ANY, "Settings")
        settings_sizer = wx.BoxSizer(wx.VERTICAL)

        embedding_panel = RB.RibbonPanel(settings_page, wx.ID_ANY, "Embedding")
        embedding_sizer = wx.BoxSizer(wx.VERTICAL)

        e_sizer = wx.BoxSizer(wx.HORIZONTAL)
        e_sizer.Add(wx.StaticText(embedding_panel, label="E:"), 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
        self.E_ctrl = wx.SpinCtrl(embedding_panel, wx.ID_ANY, value='3', min=1, max=10)
        e_sizer.Add(self.E_ctrl, 1, wx.ALL | wx.EXPAND, 5)
        embedding_sizer.Add(e_sizer, 0, wx.EXPAND, 5)

        tau_sizer = wx.BoxSizer(wx.HORIZONTAL)
        tau_sizer.Add(wx.StaticText(embedding_panel, label="tau:"), 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
        self.tau_ctrl = wx.SpinCtrl(embedding_panel, wx.ID_ANY, value='1', min=1, max=10)
        tau_sizer.Add(self.tau_ctrl, 1, wx.ALL | wx.EXPAND, 5)
        embedding_sizer.Add(tau_sizer, 0, wx.EXPAND, 5)

        embedding_panel.SetSizer(embedding_sizer)
        settings_sizer.Add(embedding_panel, 0, wx.EXPAND, 5)

        simplex_panel = RB.RibbonPanel(settings_page, wx.ID_ANY, "Simplex")
        simplex_sizer = wx.BoxSizer(wx.HORIZONTAL)
        simplex_sizer.Add(wx.StaticText(simplex_panel, label="Tp:"), 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
        self.Tp_ctrl = wx.SpinCtrl(simplex_panel, wx.ID_ANY, value='1', min=1, max=10)
        simplex_sizer.Add(self.Tp_ctrl, 1, wx.ALL | wx.EXPAND, 5)
        simplex_panel.SetSizer(simplex_sizer)
        settings_sizer.Add(simplex_panel, 0, wx.EXPAND, 5)

        # Advanced Simplex Settings Panel
        advanced_panel = RB.RibbonPanel(settings_page, wx.ID_ANY, "Advanced Simplex")
        advanced_sizer = wx.FlexGridSizer(2, 2, 5, 5)

        advanced_sizer.Add(wx.StaticText(advanced_panel, label="knn:"), 0, wx.ALIGN_CENTER_VERTICAL)
        self.knn_ctrl = wx.SpinCtrl(advanced_panel, wx.ID_ANY, value='0', min=0, max=100)
        advanced_sizer.Add(self.knn_ctrl, 1, wx.EXPAND)

        advanced_sizer.Add(wx.StaticText(advanced_panel, label="Exclusion Radius:"), 0, wx.ALIGN_CENTER_VERTICAL)
        self.exclusionRadius_ctrl = wx.SpinCtrl(advanced_panel, wx.ID_ANY, value='0', min=0, max=100)
        advanced_sizer.Add(self.exclusionRadius_ctrl, 1, wx.EXPAND)

        advanced_panel.SetSizer(advanced_sizer)
        settings_sizer.Add(advanced_panel, 0, wx.EXPAND, 5)

        column_panel = RB.RibbonPanel(settings_page, wx.ID_ANY, "Column Selection")
        column_sizer = wx.BoxSizer(wx.VERTICAL)
        column_sizer.Add(wx.StaticText(column_panel, label="Columns:"), 0, wx.ALL | wx.EXPAND, 5)
        self.columns_ctrl = wx.CheckListBox(column_panel, wx.ID_ANY, style=wx.LB_MULTIPLE, size=(-1, 100))
        column_sizer.Add(self.columns_ctrl, 1, wx.EXPAND | wx.ALL, 5)
        column_sizer.Add(wx.StaticText(column_panel, label="Target:"), 0, wx.ALL | wx.EXPAND, 5)
        self.target_ctrl = wx.Choice(column_panel, wx.ID_ANY)
        column_sizer.Add(self.target_ctrl, 0, wx.EXPAND | wx.ALL, 5)
        column_panel.SetSizer(column_sizer)
        settings_sizer.Add(column_panel, 0, wx.EXPAND, 5)

        run_panel = RB.RibbonPanel(settings_page, wx.ID_ANY, "Run")
        run_sizer = wx.BoxSizer(wx.HORIZONTAL)
        run_button_id = wx.NewIdRef()
        self.run_button = wx.Button(run_panel, run_button_id, "Run Simplex")
        run_sizer.Add(self.run_button, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
        self.Bind(wx.EVT_BUTTON, self.OnRunSimplex, id=run_button_id)
        run_panel.SetSizer(run_sizer)
        settings_sizer.Add(run_panel, 0, wx.EXPAND, 5)

        settings_page.SetSizer(settings_sizer)

        # Surrogate Data tab
        surrogate_page = RB.RibbonPage(self.ribbon, wx.ID_ANY, "Surrogate Data")
        surrogate_panel = RB.RibbonPanel(surrogate_page, wx.ID_ANY, "Surrogate Data Operations")
        surrogate_bar = RB.RibbonButtonBar(surrogate_panel)

        generate_surrogate_button_id = wx.NewIdRef()
        surrogate_bar.AddButton(generate_surrogate_button_id, "Generate Surrogate Data",
                                wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_OTHER))
        self.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnGenerateSurrogateData,
                  id=generate_surrogate_button_id)

        # Main content
        content_sizer = wx.BoxSizer(wx.HORIZONTAL)

        # Data Grid
        self.grid = gridlib.Grid(panel)
        self.grid.CreateGrid(100, 5)
        content_sizer.Add(self.grid, 1, wx.EXPAND | wx.ALL, 5)

        # Right panel for visualization and results
        right_panel = wx.Panel(panel)
        right_sizer = wx.BoxSizer(wx.VERTICAL)

        # Visualization
        self.figure = Figure(figsize=(5, 4), dpi=100)
        self.canvas = FigureCanvas(right_panel, wx.ID_ANY, self.figure)
        self.ax = self.figure.add_subplot(111, projection='3d')
        right_sizer.Add(self.canvas, 1, wx.EXPAND | wx.ALL, 5)

        # Results display
        self.results_text = wx.TextCtrl(right_panel, wx.ID_ANY, style=wx.TE_MULTILINE | wx.TE_READONLY)
        right_sizer.Add(self.results_text, 1, wx.EXPAND | wx.ALL, 5)

        right_panel.SetSizer(right_sizer)
        content_sizer.Add(right_panel, 1, wx.EXPAND | wx.ALL, 5)

        # Main layout
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(self.ribbon, 0, wx.EXPAND)
        main_sizer.Add(content_sizer, 1, wx.EXPAND)
        panel.SetSizer(main_sizer)

        # Bind events
        self.grid.Bind(gridlib.EVT_GRID_CELL_CHANGED, self.OnGridCellChanged)

        self.data = None
        self.Show()

        # Realize the ribbon
        self.ribbon.Realize()

    def OnLoadData(self, event):
        with wx.FileDialog(self, "Open CSV file", wildcard="CSV files (*.csv)|*.csv",
                           style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return
            pathname = fileDialog.GetPath()
            try:
                self.data = pd.read_csv(pathname)
                self.EnsureTimeColumn()
                self.UpdateGrid()
                self.UpdateColumnSelection()
                self.UpdateVisualization(self.E_ctrl.GetValue(), self.tau_ctrl.GetValue(),
                                         self.GetSelectedColumns(), self.Tp_ctrl.GetValue())  # Update visualization
                wx.MessageBox(f"Data loaded successfully. Shape: {self.data.shape}", "Success")
            except Exception as e:
                wx.MessageBox(f"Error loading file: {str(e)}", "Error")

    def OnNewData(self, event):
        dlg = wx.TextEntryDialog(self, "Enter number of columns:", "New Data")
        if dlg.ShowModal() == wx.ID_OK:
            try:
                num_cols = int(dlg.GetValue())
                self.data = pd.DataFrame({'Time': [], **{f'Column_{i + 1}': [] for i in range(num_cols)}})
                self.UpdateGrid()
                self.UpdateColumnSelection()
            except ValueError:
                wx.MessageBox("Please enter a valid number", "Error")
        dlg.Destroy()

    def OnSaveData(self, event):
        if self.data is None:
            wx.MessageBox("No data to save", "Error")
            return
        with wx.FileDialog(self, "Save CSV file", wildcard="CSV files (*.csv)|*.csv",
                           style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as fileDialog:
            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return
            pathname = fileDialog.GetPath()
            try:
                self.data.to_csv(pathname, index=False)
                wx.MessageBox("Data saved successfully", "Success")
            except Exception as e:
                wx.MessageBox(f"Error saving file: {str(e)}", "Error")

    def OnAddRow(self, event):
        if self.data is None:
            wx.MessageBox("Please create or load data first", "Error")
            return
        self.grid.AppendRows(1)
        new_row = pd.DataFrame({col: [np.nan] for col in self.data.columns})
        self.data = self.data.append(new_row, ignore_index=True)  # Use append with ignore_index=True
        self.UpdateGrid()

    def OnRemoveRow(self, event):
        if self.data is None or self.data.empty:
            wx.MessageBox("No data to remove", "Error")
            return
        if self.grid.GetNumberRows() > 0:
            row = self.grid.GetGridCursorRow()
            self.grid.DeleteRows(row, 1)
            self.data = self.data.drop(index=row).reset_index(drop=True)  # Use drop with index and reset_index
            self.UpdateGrid()

    def OnAddColumn(self, event):
        if self.data is None:
            wx.MessageBox("Please create or load data first", "Error")
            return
        dlg = wx.TextEntryDialog(self, "Enter new column name:", "Add Column")
        if dlg.ShowModal() == wx.ID_OK:
            new_col_name = dlg.GetValue()
            if new_col_name in self.data.columns:
                wx.MessageBox("Column name already exists", "Error")
            else:
                self.grid.AppendCols(1)
                self.data[new_col_name] = [np.nan] * len(self.data)  # Initialize with correct number of NaN values
                self.UpdateGrid()
                self.UpdateColumnSelection()
        dlg.Destroy()

    def OnRemoveColumn(self, event):
        if self.data is None or self.data.empty:
            wx.MessageBox("No data to remove", "Error")
            return
        if self.grid.GetNumberCols() > 0:
            col = self.grid.GetGridCursorCol()
            col_name = self.grid.GetColLabelValue(col)
            self.grid.DeleteCols(col, 1)
            self.data = self.data.drop(columns=[col_name])
            self.UpdateColumnSelection()

    def UpdateGrid(self):
        self.grid.ClearGrid()
        if self.grid.GetNumberRows() > 0:
            self.grid.DeleteRows(0, self.grid.GetNumberRows())
        if self.grid.GetNumberCols() > 0:
            self.grid.DeleteCols(0, self.grid.GetNumberCols())

        if self.data is not None:
            rows, cols = self.data.shape
            self.grid.AppendRows(rows)
            self.grid.AppendCols(cols)

            for i, col in enumerate(self.data.columns):
                self.grid.SetColLabelValue(i, col)
                for j, val in enumerate(self.data[col]):
                    self.grid.SetCellValue(j, i, str(val))

    def UpdateColumnSelection(self):
        if self.data is not None:
            columns = self.data.columns.tolist()
            if 'Time' in columns:
                columns.remove('Time')  # Remove 'Time' from column selection choices
            self.columns_ctrl.Set(columns)
            self.target_ctrl.Set(columns)
            if len(columns) > 0:
                self.target_ctrl.SetSelection(0)

    def OnGridCellChanged(self, event):
        row = event.GetRow()
        col = event.GetCol()
        value = self.grid.GetCellValue(row, col)

        if self.data is not None:
            try:
                # More robust type conversion
                converted_value = pd.to_numeric(value, errors='coerce')
                self.data.iloc[row, col] = converted_value if not pd.isna(converted_value) else value
            except Exception as e:
                print(f"Error converting cell value: {e}")
                self.data.iloc[row, col] = value  # Revert to string if conversion fails

    def OnRunSimplex(self, event):
        if self.data is None or self.data.empty:
            wx.MessageBox("Please load or create data first", "Error")
            return

        E = self.E_ctrl.GetValue()
        tau = self.tau_ctrl.GetValue()
        Tp = self.Tp_ctrl.GetValue()

        selected_columns = self.GetSelectedColumns()
        target = self.target_ctrl.GetString(self.target_ctrl.GetSelection())

        if not selected_columns or not target:
            wx.MessageBox("Please select columns and target", "Error")
            return

        # --- Embedding Logic ---
        if len(selected_columns) == 1 and E > 1:
            # Embed the data if only one column is selected and E > 1
            embedded_data = pyEDM.Embed(dataFrame=self.data, E=E, tau=tau, columns=selected_columns)
            self.data = embedded_data  # Update self.data with embedded data
        else:
            # Use selected columns directly if multiple columns are selected or E = 1
            self.data = self.data[selected_columns]

        # --- Simplex Projection ---
        try:
            simplex_result = pyEDM.Simplex(
                dataFrame=self.data.copy(),  # Pass a copy to Simplex
                target=target,
                E=E,
                Tp=Tp,
                tau=tau,
                knn=self.knn_ctrl.GetValue(),
                exclusionRadius=self.exclusionRadius_ctrl.GetValue()
            )

            self.results_text.SetValue(f"Simplex Projection Results:\n{simplex_result}")

            self.UpdateVisualization(E, tau, self.GetSelectedColumns(), Tp)  # Update visualization
        except Exception as e:
            wx.MessageBox(f"Error running Simplex projection: {str(e)}", "Error")

    def UpdateVisualization(self, E, tau, selected_columns, Tp):
        self.ax.clear()

        if self.data.shape[1] >= 3:
            self.ax.scatter(self.data.iloc[:, 0], self.data.iloc[:, 1], self.data.iloc[:, 2])
            self.ax.set_xlabel('Dimension 1')
            self.ax.set_ylabel('Dimension 2')
            self.ax.set_zlabel('Dimension 3')
            self.ax.set_title(f'State Space Reconstruction (E={E}, tau={tau}, Tp={Tp})')
        elif self.data.shape[1] == 2:
            self.ax.scatter(self.data.iloc[:, 0], self.data.iloc[:, 1])
            self.ax.set_xlabel('Dimension 1')
            self.ax.set_ylabel('Dimension 2')
            self.ax.set_title(f'State Space Reconstruction (E={E}, tau={tau}, Tp={Tp})')

        self.canvas.draw()

    def OnGenerateSurrogateData(self, event):
        if self.data is None or self.data.empty:
            wx.MessageBox("Please load or create data first", "Error")
            return

        # --- Enhanced Dialog for Surrogate Data Generation ---
        with wx.Dialog(self, title="Generate Surrogate Data") as dlg:
            method_choices = ["random_shuffle", "ebisuzaki", "seasonal"]
            method_label = wx.StaticText(dlg, label="Method:")
            method_choice = wx.Choice(dlg, choices=method_choices)
            method_choice.SetSelection(0)  # Default to random_shuffle

            column_label = wx.StaticText(dlg, label="Column:")
            column_choice = wx.Choice(dlg, choices=self.data.columns.tolist())
            column_choice.SetSelection(0)

            num_surrogates_label = wx.StaticText(dlg, label="Number of Surrogates:")
            num_surrogates_spin = wx.SpinCtrl(dlg, value="10", min=1, max=100)

            ok_button = wx.Button(dlg, wx.ID_OK)
            cancel_button = wx.Button(dlg, wx.ID_CANCEL)

            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(method_label, 0, wx.ALL, 5)
            sizer.Add(method_choice, 0, wx.EXPAND | wx.ALL, 5)
            sizer.Add(column_label, 0, wx.ALL, 5)
            sizer.Add(column_choice, 0, wx.EXPAND | wx.ALL, 5)
            sizer.Add(num_surrogates_label, 0, wx.ALL, 5)
            sizer.Add(num_surrogates_spin, 0, wx.EXPAND | wx.ALL, 5)

            button_sizer = wx.BoxSizer(wx.HORIZONTAL)
            button_sizer.Add(ok_button, 0, wx.ALL, 5)
            button_sizer.Add(cancel_button, 0, wx.ALL, 5)
            sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 5)

            dlg.SetSizer(sizer)
            dlg.Fit()

            if dlg.ShowModal() == wx.ID_OK:
                method = method_choice.GetStringSelection()
                column = column_choice.GetStringSelection()
                num_surrogates = num_surrogates_spin.GetValue()

                try:
                    # --- Generate Surrogate Data ---
                    time_column = self.data['Time']
                    data_to_surrogate = self.data.drop(columns=['Time'])

                    surrogate_data = pyEDM.SurrogateData(
                        dataFrame=data_to_surrogate,
                        column=column,
                        method=method,
                        numSurrogates=num_surrogates
                    )

                    # --- Add Time column back using proper alignment ---
                    surrogate_data.insert(0, 'Time', self.data['Time'].values)  # Insert Time at the beginning

                    # --- Data Synchronization ---
                    self.data = surrogate_data
                    self.UpdateGrid()
                    self.UpdateColumnSelection()
                    self.UpdateVisualization(self.E_ctrl.GetValue(), self.tau_ctrl.GetValue(),
                                             self.GetSelectedColumns(), self.Tp_ctrl.GetValue())

                    wx.MessageBox("Surrogate data generated successfully", "Success")

                except Exception as e:
                    wx.MessageBox(f"Error generating surrogate data: {str(e)}", "Error")

    def EnsureTimeColumn(self):
        if 'Time' not in self.data.columns:
            self.data.insert(0, 'Time', range(len(self.data)))

    def OnGenerateRandomData(self, event):
        with wx.Dialog(self, title="Generate Random Data") as dlg:
            num_cols_label = wx.StaticText(dlg, label="Number of Columns (excluding Time):")
            num_cols_spin = wx.SpinCtrl(dlg, value="3", min=1, max=10)

            num_rows_label = wx.StaticText(dlg, label="Number of Rows:")
            num_rows_spin = wx.SpinCtrl(dlg, value="100", min=10, max=1000)

            ok_button = wx.Button(dlg, wx.ID_OK)
            cancel_button = wx.Button(dlg, wx.ID_CANCEL)

            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(num_cols_label, 0, wx.ALL, 5)
            sizer.Add(num_cols_spin, 0, wx.EXPAND | wx.ALL, 5)
            sizer.Add(num_rows_label, 0, wx.ALL, 5)
            sizer.Add(num_rows_spin, 0, wx.EXPAND | wx.ALL, 5)

            button_sizer = wx.BoxSizer(wx.HORIZONTAL)
            button_sizer.Add(ok_button, 0, wx.ALL, 5)
            button_sizer.Add(cancel_button, 0, wx.ALL, 5)
            sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 5)

            dlg.SetSizer(sizer)
            dlg.Fit()

            if dlg.ShowModal() == wx.ID_OK:
                num_cols = num_cols_spin.GetValue()
                num_rows = num_rows_spin.GetValue()

                try:
                    # --- Generate Random Data ---
                    time_data = pd.date_range(start='2024-01-01', periods=num_rows, freq='D')
                    numeric_data = pd.DataFrame(np.random.rand(num_rows, num_cols),
                                                columns=[f'Column_{i + 1}' for i in range(num_cols)])

                    # --- Create DataFrame with Time and numeric data ---
                    self.data = pd.DataFrame({
                        'Time': time_data,
                        **numeric_data
                    })

                    # --- Data Synchronization ---
                    self.UpdateGrid()
                    self.UpdateColumnSelection()
                    self.UpdateVisualization(self.E_ctrl.GetValue(), self.tau_ctrl.GetValue(),
                                             self.GetSelectedColumns(), self.Tp_ctrl.GetValue())

                    wx.MessageBox("Random data generated successfully", "Success")

                except Exception as e:
                    wx.MessageBox(f"Error generating random data: {str(e)}", "Error")

    def GetSelectedColumns(self):
        return [self.columns_ctrl.GetString(i) for i in range(self.columns_ctrl.GetCount()) if
                self.columns_ctrl.IsChecked(i)]


if __name__ == '__main__':
    app = wx.App()
    frame = SimplexFrame()
    app.MainLoop()"