From e6e96d6246e39677e0a6641e091a8e79796030ac Mon Sep 17 00:00:00 2001 From: cncfanatics Date: Tue, 9 Nov 2010 22:47:32 +0100 Subject: [PATCH] Add graphing support into pyfa (first iteration, very basic) --- eos | 2 +- gui/builtinGraphs/__init__.py | 1 + gui/builtinGraphs/fitDps.py | 93 +++++++++++++++++++++++++++++++++ gui/graph.py | 36 +++++++++++++ gui/graphFrame.py | 98 +++++++++++++++++++++++++++++++++-- 5 files changed, 226 insertions(+), 4 deletions(-) create mode 100755 gui/builtinGraphs/__init__.py create mode 100755 gui/builtinGraphs/fitDps.py create mode 100755 gui/graph.py diff --git a/eos b/eos index e9c7fe1c4c..e04c5588ba 160000 --- a/eos +++ b/eos @@ -1 +1 @@ -Subproject commit e9c7fe1c4c3a73b3e25e65717ff4e3548fa223f6 +Subproject commit e04c5588ba20947cc406f0f26f29a47eb8b15563 diff --git a/gui/builtinGraphs/__init__.py b/gui/builtinGraphs/__init__.py new file mode 100755 index 0000000000..ec25b90b2b --- /dev/null +++ b/gui/builtinGraphs/__init__.py @@ -0,0 +1 @@ +__all__ = ["fitDps"] diff --git a/gui/builtinGraphs/fitDps.py b/gui/builtinGraphs/fitDps.py new file mode 100755 index 0000000000..615c7a7929 --- /dev/null +++ b/gui/builtinGraphs/fitDps.py @@ -0,0 +1,93 @@ +#=============================================================================== +# Copyright (C) 2010 Diego Duclos +# +# This file is part of pyfa. +# +# pyfa is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pyfa is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pyfa. If not, see . +#=============================================================================== + +from gui.graph import Graph +import service +from gui import bitmapLoader +from eos.graph.fitDps import FitDpsGraph as FitDps +from eos.graph import Data +import gui.mainFrame +import service + +class FitDpsGraph(Graph): + propertyAttributeMap = {"transversal": "maxVelocity", + "distance": "maxRange", + "signatureRadius": "signatureRadius", + "velocity": "maxVelocity"} + + propertyLabelMap = {"transversal": "Transversal Speed:", + "distance": "Distance to Target:", + "signatureRadius": "Target Signature Radius:", + "velocity": "Target Velocity:"} + + def __init__(self): + Graph.__init__(self) + self.name = "DPS" + self.fitDps = None + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def getFields(self): + return FitDps.defaults + + def getLabels(self): + return self.propertyLabelMap + + def getIcons(self): + icons = {} + sFit = service.Attribute.getInstance() + for key, attrName in self.propertyAttributeMap.iteritems(): + iconFile = sFit.getAttributeInfo(attrName).icon.iconFile + bitmap = bitmapLoader.getBitmap(iconFile, "pack") + if bitmap: + icons[key] = bitmap + + return icons + + def getPoints(self, fields): + sFit = service.Fit.getInstance() + fit = sFit.getFit(self.mainFrame.getActiveFit()) + fitDps = getattr(self, "fitDps", None) + if fitDps is None or fitDps.fit != fit: + fitDps = self.fitDps = FitDps(fit) + + fitDps.clearData() + variable = None + for fieldName, value in fields.iteritems(): + d = Data(fieldName, value) + if not d.isConstant(): + if variable is None: + variable = fieldName + else: + #We can't handle more then one variable atm, OOPS FUCK OUT + return False, "Can only handle 1 variable" + + fitDps.setData(d) + + if variable is None: + return False, "No variable" + + x = [] + y = [] + for point, val in fitDps.getIterator(): + x.append(point[variable]) + y.append(val) + + return x, y + +FitDpsGraph.register() diff --git a/gui/graph.py b/gui/graph.py new file mode 100755 index 0000000000..d327d0b947 --- /dev/null +++ b/gui/graph.py @@ -0,0 +1,36 @@ +#=============================================================================== +# Copyright (C) 2010 Diego Duclos +# +# This file is part of pyfa. +# +# pyfa is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# pyfa is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pyfa. If not, see . +#=============================================================================== + +class Graph(object): + views = [] + + @classmethod + def register(cls): + Graph.views.append(cls) + + def __init__(self): + self.name = "" + + def getFields(self): + raise NotImplementedError() + + def getIcons(self): + return None + +from gui.builtinGraphs import * diff --git a/gui/graphFrame.py b/gui/graphFrame.py index d27ae5c5ec..f7cc53d932 100644 --- a/gui/graphFrame.py +++ b/gui/graphFrame.py @@ -20,21 +20,113 @@ import wx try: import matplotlib as mpl + mpl.use('wxagg') from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas + from matplotlib.figure import Figure + import mpl_toolkits.axisartist as AA + enabled = True except: print "problems importing matplotlib, continueing without graphs" + Enabled = False + +from gui.graph import Graph +from gui import bitmapLoader class GraphFrame(wx.Frame): - def __init__(self, parent): - wx.Frame.__init__(self, parent) + def __init__(self, parent, style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE): + wx.Frame.__init__(self, parent, style=style) self.mainSizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(self.mainSizer) self.graphSelection = wx.Choice(self, wx.ID_ANY, style=0) self.mainSizer.Add(self.graphSelection, 0, wx.EXPAND) - self.figure = mpl.figure.Figure(figsize=(4,2)) + self.figure = Figure(figsize=(4, 3)) self.canvas = Canvas(self, -1, self.figure) + self.subplot = self.figure.add_subplot(111) self.mainSizer.Add(self.canvas, 0, wx.EXPAND) + self.gridPanel = wx.Panel(self) + self.mainSizer.Add(self.gridPanel, 1, wx.EXPAND) + + dummyBox = wx.BoxSizer(wx.VERTICAL) + self.gridPanel.SetSizer(dummyBox) + + self.gridSizer = wx.FlexGridSizer(0, 3) + self.gridSizer.AddGrowableCol(2) + dummyBox.Add(self.gridSizer, 0, wx.EXPAND) + + for view in Graph.views: + view = view() + self.graphSelection.Append(view.name, view) + + self.graphSelection.SetSelection(0) + self.fields = {} + self.select(0) + + def getView(self): + return self.graphSelection.GetClientData(self.graphSelection.GetSelection()) + + def getValues(self): + values = {} + for fieldName, field in self.fields.iteritems(): + values[fieldName] = field.GetLabel() + + return values + + def select(self, index): + view = self.getView() + icons = view.getIcons() + labels = view.getLabels() + sizer = self.gridSizer + self.gridPanel.DestroyChildren() + self.fields.clear() + + #Setup textboxes + for field, defaultVal in view.getFields().iteritems(): + if icons: + icon = icons.get(field) + if icon is not None: + static = wx.StaticBitmap(self.gridPanel) + static.SetBitmap(icon) + sizer.Add(static, 0) + + if labels: + label = labels.get(field) + label = label if label is not None else field + else: + label = field + + sizer.Add(wx.StaticText(self.gridPanel, wx.ID_ANY, label), 0) + textBox = wx.TextCtrl(self.gridPanel, wx.ID_ANY, style=0) + self.fields[field] = textBox + textBox.Bind(wx.EVT_TEXT, self.onFieldChanged) + sizer.Add(textBox, 1, wx.EXPAND | wx.TOP, 2) + if defaultVal is not None: + if not isinstance(defaultVal, basestring): + defaultVal = ("%f" % defaultVal).rstrip("0") + if defaultVal[-1:] == ".": + defaultVal = defaultVal + "0" + + textBox.ChangeValue(defaultVal) + + self.draw() + + def draw(self): + values = self.getValues() + view = self.getView() + success, status = view.getPoints(values) + if not success: + #TODO: Add a pwetty statys bar to report errors with + return + + x, y = success, status + + self.subplot.plot(x, y) + self.canvas.draw() + def onFieldChanged(self, event): + try: + self.draw() + except: + pass