myAxes.py 7.21 KB
Newer Older
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
1
2
3
4
5
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# ================= FILE HEADER ========================================
#
Philipp Gast's avatar
Philipp Gast committed
6
#   myplotlib v3.0.1,
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#
#   @file      myAxes.py
#   @author    Yori 'AGy' Fournier
#   @licence   CC-BY-SA
#
#   MyAxes class: Overlay of matplotlib Axes class
#   It is done such that the user can concentrate on
#   the important aspect of the figure and not the
#   technical part. It consists of a constructor,
#   that requires a Figure, the ratio of the xaxis over
#   the yaxis, and the frame in which the figure
#   should be plotted.
#
#   @Class MyAxes
#
#   @Constructor(self, fig, ratio, frame, +user defined kw):
#
#   @section Functions
#
#            - plotting: this is the overwritten function
#                        from Axes. It is called by it's
#                        parent-figure's function .plot()
#
#            - formatRawData: it computes out of the rawData
#                        given as argument some quantities that
#                        are returned as a dictionary and
#                        become accessable for plotting.
#
#   @section History
#
#   v 0.0.0 - MyAxes class for the myplotlib module, consists
#             of a constructor, a pltting function and
#             formatRawData.
#
41
42
#   v 2.2.3 - Add testRawData function
#
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
43
44
45
46
# ======================================================================
#
#
# IMPORT ---------------------------------------------------------------
47
48
49
from . import SEVR, DBUG
from . import Axes
from . import rcParams
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
50

51
_D_FRAME = [0.1, 0.1, 0.9, 0.9]
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
52

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# COMPUTE SMART FRAME -----------------------------------------------
def computeFitRect(fig, ratio, frameRect):
        
    # get the frame allowed
    framePosX, framePosY, frameWidth, frameHeight = frameRect
    # get the size of the figure
    figWidth  = fig.get_figwidth()
    figHeight = fig.get_figheight()
    figDpi    = fig.get_dpi()
        
    # get the font size in inches
    fontsize = rcParams['font.size'] / figDpi
        
    # the largest width and height allowed in inches
    maxWidth = figWidth * frameWidth - 8. * (figDpi / 75.) * fontsize
    maxHeight = figHeight * frameHeight - 4. * (figDpi / 75.) * fontsize
        
    # the hypothetical width and height in inches
    # for a given aspect ratio
    hypoWidth = maxHeight / ratio
    hypoHeight = maxWidth * ratio
        
    # if the hypothetical width is larger that the
    # maximum allowed width (in inches) then chose
    # the hypothetical Height
    if (hypoWidth > maxWidth):
        height = hypoHeight / figHeight  # height in percent
        width  = maxWidth / figWidth     # width in percent
        posX   = framePosX + 4. * (figDpi / 75.) * fontsize / figWidth      # posX
        posY   = framePosY + 3. * (figDpi / 75.) * fontsize / figHeight     # posY
    else:
        height = maxHeight / figHeight
        width  = hypoWidth / figWidth
        posX   = framePosX + (frameWidth - width) / 2.
        posY   = framePosY + 3. * (figDpi / 75.) * fontsize / figHeight
        
    rect = [posX, posY, width, height]
        
    return(rect)


Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
94
95
# Class MyAxes Overwriting Matplotlib.figure.Axes
class MyAxes(Axes):
96
    
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
97
    # CONSTRUCTOR --------------------------------------------------------
98
    def __init__(self, fig, frame=_D_FRAME, *args, **kwargs):
99
100
        
        self.fig = fig
101
        self.declareKeywords()
102
        
103
        rect = self.computeRect(frame, *args, **kwargs)
104
105
        
        # clean kwargs
106
        kwargs.pop('ratio', None)
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
107
108
        kwargs.pop('forceRatioOnWidth', None)
        kwargs.pop('forceRatioOnHeight', None)
109
        kwargs.pop('fitInFrame', None)
110
111
112
        
        # parent constructor
        Axes.__init__(self, fig, rect, **kwargs)
113
114
        
        # set a default name. Should be individualized by instance
115
        self.name = 'default'
116

117
    # COMPUTE RECT -------------------------------------------------------
118
    def computeRect(self, frameRect, *args, **kwargs):
119
120
        
        # Get the optional keyword
121
        ratio = kwargs.pop('ratio', None)
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
122
123
        forceRatioOnWidth = kwargs.pop('forceRatioOnWidth', None)
        forceRatioOnHeight = kwargs.pop('forceRatioOnHeight', None)
124
        fitInFrame = kwargs.pop('fitInFrame', None)
125
        
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
126
127
        # get the frame allowed
        framePosX, framePosY, frameWidth, frameHeight = frameRect
128
        
129
130
131
132
        # get the size of the figure
        figWidth  = self.fig.get_figwidth()
        figHeight = self.fig.get_figheight()
        
133
134
135
136
137
138
139
140
        if ratio is not None:
            
            if(forceRatioOnWidth):
                frameWidth = ratio * figWidth / (frameHeight * figHeight)
            elif(forceRatioOnHeight):
                frameHeight = ratio * (frameWidth * figWidth) / figHeight
            else:
                frameHeight = ratio * (frameWidth * figWidth) / figHeight
141
142
143
        
        rect = [framePosX, framePosY, frameWidth, frameHeight]
        
144
145
146
        if (fitInFrame):
            
            if ratio is None:
147
                ratio = figHeight/figWidth
148
            
149
            rect = computeFitRect(self.fig, ratio, rect)
150
        
151
        return(rect)
152
153
154
    
    # DECLARE KEYWORDS -------------------------------------------------
    def declareKeywords(self):
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
155
        self.keywords = {}
156
    
157
    # PLOTTING ---------------------------------------------------------
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
158
    def plotting(self):
159
160
        raise(NotImplementedError, 'You should have overwrite the plotting function.')
        return(False)
161
162
163
164
165
166
167
168
169
170
171
172

    # UNPACKING --------------------------------------------------------
    def unpackFormattedData(self, packedData):
        '''Get a string return it evaluation. can be overwritten by user.'''
        return(eval(packedData))    

    # PACKING ----------------------------------------------------------
    def packFormattedData(self, formattedData):
        '''Get an object return its representation. can be overwritten by user.'''
        return(str(formattedData))        

    # FORMATTING -------------------------------------------------------
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
173
    def formatRawData(self, rawdata):
174
175
        raise(NotImplementedError, 'You should have overwrite the formatRawData function.')        
        return(False)
176
    
177
    # TESTING THE RAWDATA ----------------------------------------------
178
    def testRawData(self, rawdata):
179
        return(True)
180
    
181
    # UPDATE -----------------------------------------------------------
182
    def update(self, *args, **kwargs):
183

184
        # Because matplotlib.axes.update expect kwargs and not **kwargs ... (stupid!! no, this is just WRONG!!)
185
        if args:  # catch matplotlib kwargs
186
187
#            kwargs = args[0]
            kwargs.update(args[0])
188
189
            # kw_for_axes = {key: value for (key, value) in args[0].items() if key not in self.keywords}  # Not compatible with python2.6
            
190
191
192
193
        kw_for_axes = {}
        for (key, value) in kwargs.items():
            if key not in self.keywords:
                kw_for_axes.update({key: value})
194
            
195
        Axes.update(self, kw_for_axes)  # update matplotlib.Axes
196
        
197
        # myplotlib update
198
199
200
201
202
203
        # self.keywords.update({key: value for (key, value) in kwargs.items() if key in self.keywords})  # Not compatible with python2.6
        
        for (key, value) in kwargs.items():
            if key in self.keywords:
                self.keywords.update({key: value})