Ver código fonte

Add Bart's plotting library

Yentl Van Tendeloo 8 anos atrás
pai
commit
c4f79b6b57

+ 95 - 0
interface/plot/MatPlotLibWrapper.py

@@ -0,0 +1,95 @@
+'''
+Created on May 15, 2017
+
+@author: Bart
+'''
+import matplotlib.pyplot as plt
+import json
+from plot import Color, LineStyle
+
+class MatPlotLibWrapper:
+        
+    def visualize(self, plots):
+        i = 1
+        for plot in plots:
+            plot = json.loads(plot)
+            # create a new subplot
+            plt.subplot(len(plots), 1, i)
+            # do all datasets for this subplot
+            for dataset in plot['datasets']:
+                stylecode = ""
+                if dataset['color'] != None or dataset['linestyle'] != None:
+                    stylecode = MatPlotLibWrapper.__color_code(dataset['color'])+MatPlotLibWrapper.__linestyle_code(dataset['linestyle'])
+                # plot data with code and style 
+                plt.plot([p['x'] for p in dataset['datapoints']], 
+                        [p['y'] for p in dataset['datapoints']], 
+                        stylecode)
+            # set title
+            if plot['title'] != None:
+                plt.title(plot['title'])
+            # set x and y axis labels
+            if plot['x']['unit']:
+                plt.xlabel("%s (%s)" % (plot['x']['name'], plot['x']['unit']))
+            else:
+                plt.xlabel("%s" % plot['x']['name'])
+            if plot['y']['unit']:
+                plt.ylabel("%s (%s)" % (plot['y']['name'], plot['y']['unit']))
+            else:
+                plt.ylabel("%s" % plot['y']['name'])
+            # make legend
+            if plot['legend']:
+                plt.legend([ds['legend'] for ds in plot['datasets']])
+            # set axis ranges
+            if plot['x']['lim_low'] != None and plot['x']['lim_high'] != None:
+                plt.xlim([plot['x']['lim_low'], plot['x']['lim_high']])
+            if plot['y']['lim_low'] != None and plot['y']['lim_high'] != None:
+                plt.ylim([plot['y']['lim_low'], plot['y']['lim_high']])
+            i += 1
+        plt.show()
+    
+    @staticmethod
+    def __color_code(color):
+        if color == Color.BLUE:
+            return "b"
+        elif color == Color.GREEN:
+            return "g"
+        elif color == Color.RED:
+            return "r"
+        elif color == Color.CYAN:
+            return "c"
+        elif color == Color.MAGENTA:
+            return "m"
+        elif color == Color.YELLOW:
+            return "y"
+        elif color == Color.BLACK:
+            return "k"
+        elif color == Color.WHITE:
+            return "w"
+        else:
+            return MatPlotLibWrapper.__color_code(Color.BLUE)
+    
+    @staticmethod
+    def __linestyle_code(linestyle):
+        if linestyle == LineStyle.SOLID:
+            return "-"
+        elif linestyle == LineStyle.DASHDOT:
+            return "-."
+        elif linestyle == LineStyle.DASHED:
+            return "--"
+        elif linestyle == LineStyle.DOTTED:
+            return ":"
+        elif linestyle == LineStyle.PIXEL:
+            return ","
+        elif linestyle == LineStyle.POINT:
+            return "."
+        elif linestyle == LineStyle.CIRCLE:
+            return "o"
+        elif linestyle == LineStyle.STAR:
+            return "*"
+        elif linestyle == LineStyle.PLUS:
+            return "+"
+        elif linestyle == LineStyle.X:
+            return "x"
+        else:
+            return MatPlotLibWrapper.__linestyle_code(LineStyle.CIRCLE)
+        

+ 0 - 0
interface/plot/__init__.py


+ 62 - 0
interface/plot/plot.py

@@ -0,0 +1,62 @@
+'''
+Created on May 15, 2017
+
+@author: Bart
+'''
+from serializable import Serializable
+
+class Plot(Serializable):
+
+    def __init__(self, datasets, title=None, x=None, y=None, legend=None):
+        self.title = title
+        if x == None:
+            x = Axis()
+        self.x = x
+        if y == None:
+            y = Axis()
+        self.y = y
+        if legend == None:
+            # we set legend to true in case of a multiplot where all legend entries are defined
+            legend = len(datasets) > 1 and all(map(lambda d : d.legend, datasets))
+        self.legend = legend
+        self.datasets = datasets
+    
+      
+class DataSet(Serializable):
+
+    def __init__(self, datapoints, color=None, linestyle=None, legend=None):
+        self.color = color
+        self.linestyle = linestyle
+        self.datapoints = datapoints
+        self.legend = legend
+
+class DataPoint(Serializable):
+    
+    def __init__(self, x, y):
+        self.x = x
+        self.y = y
+    
+        
+class Color:
+    # enumeration of all colors
+    BLUE, GREEN, RED, CYAN, MAGENTA, YELLOW, BLACK, WHITE = range(8)
+
+class LineStyle:
+    # enumeration of all line styles
+    SOLID, DASHED, DASHDOT, DOTTED, PIXEL, POINT, CIRCLE, STAR, PLUS, X = range(10)
+        
+class Axis(Serializable):
+    
+    def __init__(self, name=None, unit=None, lim_low=None, lim_high=None):
+        if not name:
+            name = ""
+        self.name = name
+        if not unit:
+            unit = ""
+        self.unit = unit
+        self.lim_low = lim_low
+        self.lim_high = lim_high
+
+class XAxis(Axis): pass
+class YAxis(Axis): pass
+        

+ 26 - 0
interface/plot/serializable.py

@@ -0,0 +1,26 @@
+'''
+Created on May 15, 2017
+
+@author: Bart
+'''
+
+import json
+
+class Serializable:
+    
+    def serialize(self):
+        """ does not take into account cyclic links, and only works with attribute types basic, list and Serializable """
+        attrs = vars(self)
+        for attr_name in attrs.keys():
+            attr_val = attrs[attr_name]
+            try:
+                json.dumps(attr_val)
+            except TypeError:
+                if isinstance(attr_val, list):
+                    attrs[attr_name] = [item.serialize() for item in attr_val]
+                else:
+                    attrs[attr_name] = attr_val.serialize()
+        return attrs
+    
+    def to_json(self):
+        return json.dumps(self.serialize())

+ 0 - 0
interface/plot/test/__init__.py


+ 86 - 0
interface/plot/test/wrapper.py

@@ -0,0 +1,86 @@
+'''
+Created on May 15, 2017
+
+@author: Bart
+'''
+import unittest
+
+from MatPlotLibWrapper import MatPlotLibWrapper
+from plot import Plot, DataSet, DataPoint, Color, LineStyle, XAxis, YAxis
+
+
+class Test(unittest.TestCase):
+    
+    def setUp(self):
+        unittest.TestCase.setUp(self)
+        self.dps1 = []
+        self.dps1.append(DataPoint(0, 1))
+        self.dps1.append(DataPoint(0.1, 1.0))
+        self.dps1.append(DataPoint(0.2, 1.2))
+        self.dps1.append(DataPoint(0.3, 1.5))
+        self.dps1.append(DataPoint(0.4, 1.6))
+        self.dps1.append(DataPoint(0.5, 1.65))
+        self.dps1.append(DataPoint(0.6, 1.67))
+        self.dps2 = []
+        self.dps2.append(DataPoint(0, 2))
+        self.dps2.append(DataPoint(0.1, 2.1))
+        self.dps2.append(DataPoint(0.2, 2.2))
+        self.dps2.append(DataPoint(0.3, 2.0))
+        self.dps2.append(DataPoint(0.4, 1.6))
+        self.dps2.append(DataPoint(0.5, 1))
+        self.dps2.append(DataPoint(0.6, 0))
+        self.dps2.append(DataPoint(0.7, 0))
+        self.dps3 = []
+        self.dps3.append(DataPoint(0, 1.2))
+        self.dps3.append(DataPoint(0.2, 1.1))
+        self.dps3.append(DataPoint(0.4, 1))
+        self.mw = MatPlotLibWrapper()
+
+    def test_oneplot(self):
+        ds1 = DataSet(self.dps1, color=Color.BLUE, linestyle=LineStyle.X, legend="t1")
+        p1 = Plot([ds1], "test 1", x=XAxis("time", "s", 0, 1), y=YAxis("val", "kg/s**2", 0, 2), legend=True).to_json()
+        self.mw.visualize([p1])
+ 
+    def test_threeplots(self):
+        ds1 = DataSet(self.dps1, color=Color.RED, linestyle=LineStyle.X, legend="t1")
+        p1 = Plot([ds1], "test 1", x=XAxis("time", "s", 0, 1), y=YAxis("val1", "kg/s**2", 0, 2), legend=True).to_json()
+        ds2 = DataSet(self.dps2, color=Color.CYAN, linestyle=LineStyle.DASHED, legend="t2")
+        p2 = Plot([ds2], "test 2", x=XAxis("time", "seconds", 0, 1), y=YAxis("val2", "kg/s**2", 0, 3), legend=True).to_json()
+        ds3 = DataSet(self.dps3, color=Color.BLUE, linestyle=LineStyle.POINT, legend="t3")
+        p3 = Plot([ds3], "test 3", x=XAxis("time", "s", 0, 1), y=YAxis("val3", "kg/s**2", 0, 2), legend=True).to_json()
+        self.mw.visualize([p1, p2, p3])
+        
+    def test_onemultiplot(self):
+        ds1 = DataSet(self.dps1, color=Color.RED, linestyle=LineStyle.X, legend="t1")
+        ds2 = DataSet(self.dps2, color=Color.CYAN, linestyle=LineStyle.DASHED, legend="t2")
+        ds3 = DataSet(self.dps3, color=Color.BLUE, linestyle=LineStyle.POINT, legend="t3")
+        p1 = Plot([ds1, ds2, ds3], "test 1+2+3", x=XAxis("time", "s", 0, 1), y=YAxis("val1", "kg/s**2", 0, 2), legend=True).to_json()
+        self.mw.visualize([p1])
+        
+    def test_twomultiplot(self):
+        ds1 = DataSet(self.dps1, color=Color.RED, linestyle=LineStyle.X, legend="t1")
+        ds2 = DataSet(self.dps2, color=Color.CYAN, linestyle=LineStyle.DASHED, legend="t2")
+        ds3 = DataSet(self.dps3, color=Color.BLUE, linestyle=LineStyle.POINT, legend="t3")
+        p1 = Plot([ds1, ds2, ds3], "test 1+2+3", x=XAxis("time", "s", 0, 1), y=YAxis("val1", "kg/s**2", 0, 2), legend=True).to_json()
+        ds1 = DataSet(self.dps1, color=Color.GREEN, linestyle=LineStyle.CIRCLE, legend="t1'")
+        ds2 = DataSet(self.dps2, color=Color.BLACK, linestyle=LineStyle.DASHDOT, legend="t2'")
+        ds3 = DataSet(self.dps3, color=Color.MAGENTA, linestyle=LineStyle.STAR, legend="t3'")
+        p2 = Plot([ds1, ds2, ds3], "test 1+2+3'", x=XAxis("time", "s", 0, 0.8), y=YAxis("val1", "kg/s**2", 0, 2), legend=True).to_json()
+        self.mw.visualize([p1, p2])
+        
+    def test_incomplete(self):
+        ds1 = DataSet(self.dps1)
+        p1 = Plot([ds1]).to_json()
+        self.mw.visualize([p1])
+        
+    def test_multiplotincomplete(self):
+        ds1 = DataSet(self.dps1)
+        ds2 = DataSet(self.dps2)
+        ds3 = DataSet(self.dps3)
+        p1 = Plot([ds1, ds2, ds3]).to_json()
+        self.mw.visualize([p1])
+
+
+if __name__ == "__main__":
+    #import sys;sys.argv = ['', 'Test.testName']
+    unittest.main()