Source

aproxim / app_window.py

__author__ = 'Fire Lizard'

from main_window import MainWindow
from data_format import DataFormat
from util_data import calculate_ab, calculate_coefficients
from app_settings_dialog import AppSettingsDialog
from wx.lib.wordwrap import wordwrap
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from xml.etree import ElementTree
from sys import platform
from math import fabs
import wx

class AppWindow(MainWindow):

    def __init__(self, *args, **kwds):
        super(AppWindow, self).__init__(*args, **kwds)
        self.create_graph()
        self.wildcard = "CSV files|*.csv|"\
                        "XML files|*.xml|"\
                        "Microsoft Excel files|*.xlsx" if platform == "win32" else "CSV files|*.csv|"\
                                                                                   "XML files|*.xml|"
        self.draw_polar = False
        self.adjust_columns()

    def create_graph(self):
        self.figure = Figure()

        self.canvas = FigureCanvasWxAgg(self.notebook_1_pane_3, wx.ID_ANY, self.figure)
        self.sizer_3 = wx.BoxSizer(wx.VERTICAL)
        self.sizer_3.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND)

        self.plot_toolbar = NavigationToolbar2Wx(self.canvas)
        self.plot_toolbar.Realize()
        self.sizer_3.Add(self.plot_toolbar, 0, wx.LEFT | wx.EXPAND)
        self.plot_toolbar.Show()

        self.notebook_1_pane_3.SetSizer(self.sizer_3)
        self.Fit()

    def fetch_data(self):
        data = []
        n = self.data_grid.GetNumberRows()
        for i in range(0, n):
            x = self.data_grid.GetCellValue(i, 0)
            y = self.data_grid.GetCellValue(i, 1)
            try:
                data.append((float(x), float(y)))
            except ValueError:
                pass
        return data

    def fill_data(self, data):
        n = self.data_grid.GetNumberRows()
        if n > 0: self.data_grid.DeleteRows(0, n)
        index = 0
        for (x, y) in data:
            self.data_grid.AppendRows(1)
            self.data_grid.SetCellValue(index, 0 , x)
            self.data_grid.SetCellValue(index, 1 , y)
            index += 1

    def btnNew_Click(self, event):  # wxGlade: MainWindow.<event_handler>
        n = self.data_grid.GetNumberRows()
        if n > 0: self.data_grid.DeleteRows(0, n)
        self.data_grid.AppendRows(1)

    def btnOpen_Click(self, event):  # wxGlade: MainWindow.<event_handler>
        dlg = wx.FileDialog(
            self, message="Choose a file",
            defaultDir="",
            defaultFile="",
            wildcard=self.wildcard,
            style=wx.OPEN
        )
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            if dlg.FilterIndex == 0:
                f = open(path, 'r')
                lines = f.readlines()
                f.close()
                self.fill_data(DataFormat().csv2data(lines))
            elif dlg.FilterIndex == 1:
                f = open(path, 'r')
                tree = ElementTree.parse(f)
                f.close()
                self.fill_data(DataFormat().xml2data(tree))
            elif dlg.FilterIndex == 2:
                self.fill_data(DataFormat().xlsx2data(path))
        dlg.Destroy()
        self.adjust_columns()

    def btnSave_Click(self, event):  # wxGlade: MainWindow.<event_handler>
        dlg = wx.FileDialog(self, message="Save file as ...",
            defaultDir="",
            defaultFile="",
            wildcard=self.wildcard,
            style=wx.SAVE | wx.FD_OVERWRITE_PROMPT
        )
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            data = self.fetch_data()
            if dlg.FilterIndex == 0:
                f = open(path, 'w')
                lines = DataFormat().data2csv(data)
                f.writelines(lines)
                f.close()
            elif dlg.FilterIndex == 1:
                f = open(path, 'w')
                lines = DataFormat().data2xml(data)
                f.writelines(lines)
                f.close()
            elif dlg.FilterIndex == 2:
                DataFormat().data2xlsx(data, path)
        dlg.Destroy()

    def generate_test_data(self, x, f):
        y = [f(float(val)) for val in x]
        if len(x) - self.data_grid.GetNumberRows() > 0:
            self.data_grid.AppendRows(len(x) - self.data_grid.GetNumberRows())
        for i in range(0, len(x)): self.data_grid.SetCellValue(i, 0, str(x[i]))
        for i in range(0, len(x)): self.data_grid.SetCellValue(i, 1, str(y[i]))
        self.adjust_columns()

    def adjust_columns(self):
        n = self.data_grid.NumberCols
        w = self.data_grid.Size.GetWidth() / (n + 1)
        for index in range(0, n):
            self.data_grid.SetColSize(index, w)

    def btnRun_Click(self, event):  # wxGlade: MainWindow.<event_handler>

        #self.generate_test_data(range(-5, 5, 1), lambda x : x)

        src_data = self.fetch_data()
        dst_data = []
        f = self.function.GetCurrentSelection() + 1
        mbx = []
        n0 = 0
        if f == 18 or f == 19:
            n0 = self.polynom_power.GetValue()
        a1, b1, b2 = calculate_ab(src_data, dst_data, n0, mbx, f)
        if a1 is None or b1 is None or (f == 20 and b2 is None):
            dlg = wx.MessageDialog(self, "Solution not found",
                'Error',
                wx.OK | wx.ICON_INFORMATION
            )
            dlg.ShowModal()
            dlg.Destroy()
            return

        n = len(src_data)

        for index in range(0, n):
            self.data_grid.SetCellValue(index, 2 , str(dst_data[index][1]))
            if not dst_data[index][1] is None:
                deviation = src_data[index][1] - dst_data[index][1]
                self.data_grid.SetCellValue(index, 3 , str(100 * fabs(deviation)))
            else:
                self.data_grid.SetCellValue(index, 3 , '')

        self.adjust_columns()

        self.figure.clf()
        if self.draw_polar:
            self.axes = self.figure.add_subplot(111, projection='polar')
        else:
            self.axes = self.figure.add_subplot(111)
        x1 = [val[0] for val in src_data]
        y1 = [val[1] for val in src_data]
        x2 = [val[0] for val in dst_data]
        y2 = [val[1] for val in dst_data]
        self.axes.plot(x1, y1, 'b.', x2, y2, 'r')
        #self.axes.legend(['Source Data', 'Interpolated Data'], loc='best')
        self.figure.canvas.draw()
        self.Fit()

        delta, sigma, r = calculate_coefficients(src_data, dst_data, mbx, n0, f)
        textBoxes = [self.txtParamA, self.txtParamB, self.txtParamB2, self.txtParamDelta,
                     self.txtParamNu, self.txtParamSigma]
        for textBox in textBoxes:
            textBox.SetValue("")
            if f <= 18 or f == 20:
                self.txtParamA.SetValue("A = " + str(b1))
                self.txtParamB.SetValue("B = " + str(a1))
                if f == 20:
                    self.txtParamB2.Text = "B2 = " + str(b2)
            elif f == 19:
                caption = ""
                n = int(fabs(n0))
                for index in range(0, n + 1):
                    caption += "B"
                    caption += str(index)
                    caption += " = "
                    caption += str(mbx[index])
                    caption += "; "
                self.txtParamA.SetValue(caption)
            self.txtParamDelta.SetValue("Average Deviation: " + str(delta))
            self.txtParamSigma.SetValue("Mean Square Deviation: " + str(sigma))
            if f <= 18 or f == 20:
                self.txtParamNu.SetValue("Correlation Coefficient: " + str(r))
            elif f == 19:
                self.txtParamNu.SetValue("Correlation Ratio: " + str(r))

    def btnSettings_Click(self, event):  # wxGlade: MainWindow.<event_handler>
        dlg = AppSettingsDialog(self)
        dlg.polar.SetValue(self.draw_polar)
        val = dlg.ShowModal()

        if val == wx.ID_OK:
            self.draw_polar = dlg.polar.GetValue()

        dlg.Destroy()

    def btnInfo_Click(self, event):  # wxGlade: MainWindow.<event_handler>
        info = wx.AboutDialogInfo()
        info.Name = "Approximator"
        info.Version = "1.7"
        info.Copyright = "(C) 2012 Fire Lizard Software"
        info.Description = wordwrap(
            "Approximator is a program for experimental data approximation and interpolation (20 dependencies for select).",
            350, wx.ClientDC(self))
        info.WebSite = ("http://firelizardsoftware.com", "Fire Lizard Software")
        info.Developers = [ "Anatoliy Sova" ]

        licenseText = "This program is free software: you can redistribute it and/or modify\n\
        it under the terms of the GNU General Public License as published by\n\
        the Free Software Foundation, either version 3 of the License, or\n\
        (at your option) any later version.\n\
        ""\n\
        This program is distributed in the hope that it will be useful,\n\
        but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
        GNU General Public License for more details.\n\
        ""\n\
        You should have received a copy of the GNU General Public License\n\
        along with this program.  If not, see <http://www.gnu.org/licenses/>."
        info.License = wordwrap(licenseText, 500, wx.ClientDC(self))

        wx.AboutBox(info)

    def btnExit_Click(self, event):  # wxGlade: MainWindow.<event_handler>
        self.Close()

    def data_grid_CellChange(self, event):  # wxGlade: MainWindow.<event_handler>
        n = self.data_grid.GetNumberRows()
        row = event.GetRow()
        if row == n - 1:
            self.data_grid.AppendRows(1)