10
10
11
11
12
12
def cleanfigure (fighandle = None , axhandle = None , target_resolution = 600 , scalePrecision = 1.0 ):
13
- """cleans figure as a preparation for tikz export.
13
+ """Cleans figure as a preparation for tikz export.
14
14
This will minimize the number of points required for the tikz figure.
15
+ If the figure has subplots, it will recursively clean then up.
15
16
16
17
Note that this function modifies the figure directly (impure function).
18
+
17
19
18
20
Parameters
19
21
----------
20
22
fighandle : obj, optional
21
- matplotlib figure handle object. If not provided, it is obtained from gcf(), by default None
23
+ matplotlib figure handle object. If not provided, it is obtained from `plt. gcf()` , by default None
22
24
axhandle : obj, optional
23
- matplotlib figure handle object. If not provided, it is obtained from gca() , by default None
25
+ matplotlib figure handle object. If not provided, it is obtained from `plt.gcf().axes` , by default None
24
26
target_resolution : int, list of int or np.array
25
27
target resolution of final figure in PPI. If a scalar integer is provided, it is assumed to be square in both axis.
26
28
If a list or an np.array is provided, it is interpreted as [H, W], by default 600
@@ -29,11 +31,15 @@ def cleanfigure(fighandle=None, axhandle=None, target_resolution=600, scalePreci
29
31
"""
30
32
if fighandle is None and axhandle is None :
31
33
fighandle = plt .gcf ()
32
- axhandle = plt .gca ()
34
+ # recurse into subplots
35
+ for axhandle in fighandle .axes :
36
+ cleanfigure (fighandle , axhandle , target_resolution , scalePrecision )
33
37
elif fighandle is None and (axhandle is not None ):
34
38
fighandle = axhandle .get_figure ()
35
39
elif (fighandle is not None ) and (axhandle is None ):
36
- axhandle = fighandle .axes [0 ]
40
+ # recurse into subplots
41
+ for axhandle in fighandle .axes :
42
+ cleanfigure (fighandle , axhandle , target_resolution , scalePrecision )
37
43
38
44
# Note: ax.scatter and ax.plot create Line2D objects in a property ax.lines
39
45
# ax.bar creates BarContainer objects in a property ax.bar
@@ -167,6 +173,17 @@ def removeData(data, id_remove):
167
173
return np .concatenate ([xData , yData ], axis = 1 )
168
174
169
175
176
+ def diff (x , * args , ** kwargs ):
177
+ """modification of np.diff(x, *args, **kwargs).
178
+ - If x is empty, return np.array([False])
179
+ - else: return np.diff(x, *args, **kwargs)
180
+ """
181
+ if isempty (x ):
182
+ return np .array ([False ])
183
+ else :
184
+ return np .diff (x , * args , ** kwargs )
185
+
186
+
170
187
def removeNaNs (data ):
171
188
"""Removes superflous NaNs in the data, i.e. those at the end/beginning of the data and consecutive ones.
172
189
@@ -184,20 +201,24 @@ def removeNaNs(data):
184
201
xData , yData = np .split (data , 2 , 1 )
185
202
id_nan = np .any (np .isnan (data ), axis = 1 )
186
203
id_remove = np .argwhere (id_nan ).reshape ((- 1 ,))
187
- id_remove = id_remove [
188
- np .concatenate (
189
- [np .array ([True ,]).reshape ((- 1 ,)), np .diff (id_remove , axis = 0 ) == 1 ]
190
- )
191
- ]
204
+ if isempty (id_remove ):
205
+ pass
206
+ else :
207
+ id_remove = id_remove [
208
+ np .concatenate (
209
+ [diff (id_remove , axis = 0 ) == 1 , np .array ([False ,]).reshape ((- 1 ,))]
210
+ )
211
+ ]
192
212
193
213
id_first = np .argwhere (np .logical_not (id_nan ))[0 ]
194
214
id_last = np .argwhere (np .logical_not (id_nan ))[- 1 ]
195
215
196
- if elements (id_first ) == 0 :
216
+ if isempty (id_first ):
217
+ # remove entire data
197
218
id_remove = np .arange (len (xData ))
198
219
else :
199
220
id_remove = np .concatenate (
200
- [np .arange (1 , id_first - 1 ), id_remove , np .arange (id_last + 1 , len (xData ))]
221
+ [np .arange (0 , id_first ), id_remove , np .arange (id_last + 1 , len (xData ))]
201
222
)
202
223
xData = np .delete (xData , id_remove , axis = 0 )
203
224
yData = np .delete (yData , id_remove , axis = 0 )
0 commit comments