99import os
1010import sys
1111import numpy as np
12- import matplotlib .pyplot as plt
13- from mpl_toolkits .axes_grid1 import make_axes_locatable
12+
1413from mintpy .defaults .template import get_template_content
15- from mintpy .utils import readfile , ptime , utils as ut , plot as pp
14+ from mintpy .utils import readfile , utils as ut , plot as pp
1615from mintpy .utils .arg_utils import create_argument_parser
1716
1817
@@ -103,15 +102,14 @@ def analyze_rms(date_list, rms_list, inps):
103102 print ('save date to file: ' + ref_date_file )
104103
105104 # exclude date(s) - outliers
106- try :
107- rms_threshold = ut .median_abs_deviation_threshold (rms_list , center = 0. , cutoff = inps .cutoff )
108- except :
109- # equivalent calculation using numpy assuming Gaussian distribution
110- rms_threshold = np .median (rms_list ) / .6745 * inps .cutoff
105+ # equivalent calculation using numpy assuming Gaussian distribution as:
106+ # rms_threshold = np.median(rms_list) / .6745 * inps.cutoff
107+ rms_threshold = ut .median_abs_deviation_threshold (rms_list , center = 0. , cutoff = inps .cutoff )
111108
112109 ex_idx = [rms_list .index (i ) for i in rms_list if i > rms_threshold ]
113- print (('-' * 50 + '\n date(s) with RMS > {} * median RMS'
114- ' ({:.4f})' .format (inps .cutoff , rms_threshold )))
110+ print ('-' * 50 )
111+ print (f'date(s) with RMS > { inps .cutoff } * median RMS ({ rms_threshold :.4f} )' )
112+
115113 ex_date_file = 'exclude_date.txt'
116114 if ex_idx :
117115 # print
@@ -127,110 +125,37 @@ def analyze_rms(date_list, rms_list, inps):
127125 if os .path .isfile (ex_date_file ):
128126 os .remove (ex_date_file )
129127
130- # plot bar figure and save
131- fig_file = os .path .splitext (inps .rms_file )[0 ]+ '.pdf'
132- fig , ax = plt .subplots (figsize = inps .fig_size )
133- print ('create figure in size:' , inps .fig_size )
134- ax = plot_rms_bar (ax , date_list , np .array (rms_list )* 1000. , cutoff = inps .cutoff )
135- fig .savefig (fig_file , bbox_inches = 'tight' , transparent = True )
136- print ('save figure to file: ' + fig_file )
137128 return inps
138129
139130
140- def plot_rms_bar (ax , date_list , rms , cutoff = 3. , font_size = 12 ,
141- tick_year_num = 1 , legend_loc = 'best' ,
142- disp_legend = True , disp_side_plot = True , disp_thres_text = False ,
143- ylabel = 'Residual phase RMS [mm]' ):
144- """ Bar plot Phase Residual RMS
145- Parameters: ax : Axes object
146- date_list : list of string in YYYYMMDD format
147- rms : 1D np.array of float for RMS value in mm
148- cutoff : cutoff value of MAD outlier detection
149- tick_year_num : int, number of years per major tick
150- legend_loc : 'upper right' or (0.5, 0.5)
151- Returns: ax : Axes object
152- """
153- dates , datevector = ptime .date_list2vector (date_list )
154- dates = np .array (dates )
155- try :
156- bar_width = min (ut .most_common (np .diff (dates ).tolist (), k = 2 ))* 3 / 4
157- except :
158- bar_width = np .min (np .diff (dates ).tolist ())* 3 / 4
159- rms = np .array (rms )
160-
161- # Plot all dates
162- ax .bar (dates , rms , bar_width .days , color = pp .mplColors [0 ])
163-
164- # Plot reference date
165- ref_idx = np .argmin (rms )
166- ax .bar (dates [ref_idx ], rms [ref_idx ], bar_width .days , color = pp .mplColors [1 ], label = 'Reference date' )
167-
168- # Plot exclude dates
169- rms_threshold = ut .median_abs_deviation_threshold (rms , center = 0. , cutoff = cutoff )
170- ex_idx = rms > rms_threshold
171- if not np .all (ex_idx == False ):
172- ax .bar (dates [ex_idx ], rms [ex_idx ], bar_width .days , color = 'darkgray' , label = 'Exclude date' )
173-
174- # Plot rms_threshold line
175- (ax , xmin , xmax ) = pp .auto_adjust_xaxis_date (ax , datevector , font_size , every_year = tick_year_num )
176- ax .plot (np .array ([xmin , xmax ]), np .array ([rms_threshold , rms_threshold ]), '--k' ,
177- label = 'Median Abs Dev * {}' .format (cutoff ))
178-
179- # axis format
180- ax = pp .auto_adjust_yaxis (ax , np .append (rms , rms_threshold ), font_size , ymin = 0.0 )
181- #ax.set_xlabel('Time [years]', fontsize=font_size)
182- ax .set_ylabel (ylabel , fontsize = font_size )
183- ax .tick_params (which = 'both' , direction = 'in' , labelsize = font_size ,
184- bottom = True , top = True , left = True , right = True )
185-
186- # 2nd axes for circles
187- if disp_side_plot :
188- divider = make_axes_locatable (ax )
189- ax2 = divider .append_axes ("right" , "10%" , pad = "2%" )
190- ax2 .plot (np .ones (rms .shape , np .float32 ) * 0.5 , rms , 'o' , mfc = 'none' , color = pp .mplColors [0 ])
191- ax2 .plot (np .ones (rms .shape , np .float32 )[ref_idx ] * 0.5 , rms [ref_idx ], 'o' , mfc = 'none' , color = pp .mplColors [1 ])
192- if not np .all (ex_idx == False ):
193- ax2 .plot (np .ones (rms .shape , np .float32 )[ex_idx ] * 0.5 , rms [ex_idx ], 'o' , mfc = 'none' , color = 'darkgray' )
194- ax2 .plot (np .array ([0 , 1 ]), np .array ([rms_threshold , rms_threshold ]), '--k' )
195-
196- ax2 .set_ylim (ax .get_ylim ())
197- ax2 .set_xlim ([0 , 1 ])
198- ax2 .tick_params (which = 'both' , direction = 'in' , labelsize = font_size ,
199- bottom = True , top = True , left = True , right = True )
200- ax2 .get_xaxis ().set_ticks ([])
201- ax2 .get_yaxis ().set_ticklabels ([])
202-
203- if disp_legend :
204- ax .legend (loc = legend_loc , frameon = False , fontsize = font_size )
205-
206- # rms_threshold text
207- if disp_thres_text :
208- ymin , ymax = ax .get_ylim ()
209- yoff = (ymax - ymin ) * 0.1
210- if (rms_threshold - ymin ) > 0.5 * (ymax - ymin ):
211- yoff *= - 1.
212- ax .annotate ('Median Abs Dev * {}' .format (cutoff ),
213- xy = (xmin + (xmax - xmin )* 0.05 , rms_threshold + yoff ),
214- color = 'k' , xycoords = 'data' , fontsize = font_size )
215- return ax
216-
217-
218131######################################################################################################
219132def main (iargs = None ):
220- plt .switch_backend ('Agg' ) # Backend setting
221133
134+ # read inputs
222135 inps = cmd_line_parse (iargs )
223136 if inps .template_file :
224137 inps = read_template2inps (inps .template_file , inps )
225138
226139 # calculate timeseries of residual Root Mean Square
227- ( inps .rms_list ,
228- inps .date_list ,
229- inps . rms_file ) = ut . get_residual_rms ( inps .timeseries_file ,
230- mask_file = inps .maskFile ,
231- ramp_type = inps . deramp )
140+ inps .rms_list , inps . date_list , inps . rms_file = ut . get_residual_rms (
141+ inps .timeseries_file ,
142+ mask_file = inps .maskFile ,
143+ ramp_type = inps .deramp ,
144+ )
232145
146+ # analyze RMS: generate reference/exclude_date.txt files
233147 analyze_rms (inps .date_list , inps .rms_list , inps )
148+
149+ # plot RMS
150+ pp .plot_timeseries_rms (
151+ rms_file = inps .rms_file ,
152+ cutoff = inps .cutoff ,
153+ out_fig = os .path .splitext (inps .rms_file )[0 ]+ '.pdf' ,
154+ disp_fig = False ,
155+ fig_size = inps .fig_size ,
156+ tick_year_num = inps .tick_year_num ,
157+ )
158+
234159 return
235160
236161
0 commit comments