myAxes.py 6.46 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


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
# COMPUTE SMART FRAME -----------------------------------------------
def computeSmartRect(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
93
94
# Class MyAxes Overwriting Matplotlib.figure.Axes
class MyAxes(Axes):
95
    
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
96
    # CONSTRUCTOR --------------------------------------------------------
97
    def __init__(self, fig, frameRect, ratio=None, *args, **kwargs):
98
99
        
        self.fig = fig
100
        self.declareKeywords()
101
        
102
103
104
        rect = self.computeRect(frameRect, ratio=ratio, *args, **kwargs)
        
        # clean kwargs
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
105
106
        kwargs.pop('forceRatioOnWidth', None)
        kwargs.pop('forceRatioOnHeight', None)
107
        kwargs.pop('fitInFrame', None)
108
109
110
        
        # parent constructor
        Axes.__init__(self, fig, rect, **kwargs)
111
112
        
        # set a default name. Should be individualized by instance
113
        self.name = 'default'
114
115
    
    # COMPUTE RECT -------------------------------------------------------
116
    def computeRect(self, frameRect, ratio=None, *args, **kwargs):
117
118
        
        # Get the optional keyword
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
119
120
        forceRatioOnWidth = kwargs.pop('forceRatioOnWidth', None)
        forceRatioOnHeight = kwargs.pop('forceRatioOnHeight', None)
121
        fitInFrame = kwargs.pop('fitInFrame', None)
122
        
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
123
124
        # get the frame allowed
        framePosX, framePosY, frameWidth, frameHeight = frameRect
125
        
126
127
128
129
        # get the size of the figure
        figWidth  = self.fig.get_figwidth()
        figHeight = self.fig.get_figheight()
        
130
131
132
133
134
135
136
137
        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
138
139
140
        
        rect = [framePosX, framePosY, frameWidth, frameHeight]
        
141
142
143
144
145
146
147
        if (fitInFrame):
            
            if ratio is None:
                ratio = rect[3]/rect[2]
            
            rect = computeSmartRect(self, ratio, rect)
        
148
        return(rect)
149
150
151
    
    # DECLARE KEYWORDS -------------------------------------------------
    def declareKeywords(self):
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
152
        self.keywords = {}
153
    
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
154
155
    # PLOTTING -----------------------------------------------------------
    def plotting(self):
156
        return(True)
157
    
Yori 'AGy' Fournier's avatar
Yori 'AGy' Fournier committed
158
159
    # FORMATTING ---------------------------------------------------------
    def formatRawData(self, rawdata):
160
        return(True)
161
    
162
163
    # TESTING THE RAWDATA ------------------------------------------------
    def testRawData(self, rawdata):
164
        return(True)
165
166
    
    # UPDATE -------------------------------------------------------------
167
168
169
    def update(self, *args, **kwargs):
        
        # Because matplotlib.axes.update expect kwargs and not **kwargs ... (stupid!!)
170
171
        if args:  # catch matplotlib kwargs
            kwargs = args[0]
172
173
174
175
176
177
178
            # kw_for_axes = {key: value for (key, value) in args[0].items() if key not in self.keywords}  # Not compatible with python2.6
            
            kw_for_axes = {}
            for (key, value) in args[0].items():
                if key not in self.keywords:
                    kw_for_axes.update({key: value})
            
179
            Axes.update(self, kw_for_axes)  # update matplotlib.Axes
180
        
181
        # myplotlib update
182
183
184
185
186
187
        # 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})