6
6
import pandas as pd
7
7
from pygmt .clib import Session
8
8
from pygmt .exceptions import GMTError , GMTInvalidInput
9
- from pygmt .helpers import (
10
- build_arg_string ,
11
- data_kind ,
12
- dummy_context ,
13
- fmt_docstring ,
14
- kwargs_to_strings ,
15
- use_alias ,
16
- )
9
+ from pygmt .helpers import build_arg_string , fmt_docstring , kwargs_to_strings , use_alias
17
10
18
11
19
12
def data_format_code (convention , component = "full" ):
@@ -160,17 +153,14 @@ def meca(
160
153
proportional to the magnitude. Scale defines the size for magnitude = 5
161
154
(i.e. scalar seismic moment M0 = 4.0E23 dynes-cm)
162
155
longitude: int, float, list, or 1d numpy array
163
- Longitude(s) of event location. Ignored if `spec` is not a dictionary.
164
- List must be the length of the number of events. Ignored if `spec` is a
165
- DataFrame and contains a 'longitude' column.
156
+ Longitude(s) of event location. Will override the longitudes in ``spec``
157
+ if ``spec`` is a dict or DataFrame.
166
158
latitude: int, float, list, or 1d numpy array
167
- Latitude(s) of event location. Ignored if `spec` is not a dictionary.
168
- List must be the length of the number of events. Ignored if `spec` is a
169
- DataFrame and contains a 'latitude' column.
159
+ Latitude(s) of event location. Will override the latitudes in ``spec``
160
+ if ``spec`` is a dict or DataFrame.
170
161
depth: int, float, list, or 1d numpy array
171
- Depth(s) of event location in kilometers. Ignored if `spec` is not a
172
- dictionary. List must be the length of the number of events. Ignored if
173
- `spec` is a DataFrame and contains a 'depth' column.
162
+ Depth(s) of event location in kilometers. Will override the depths in
163
+ ``spec`` if ``spec`` is a dict or DataFrame.
174
164
convention: str
175
165
``"aki"`` (Aki & Richards), ``"gcmt"`` (global CMT), ``"mt"`` (seismic
176
166
moment tensor), ``"partial"`` (partial focal mechanism), or
@@ -181,13 +171,13 @@ def meca(
181
171
full seismic moment tensor), ``"dc"`` (the closest double couple with
182
172
zero trace and zero determinant), ``"deviatoric"`` (zero trace)
183
173
plot_longitude: int, float, list, or 1d numpy array
184
- Longitude(s) at which to place beachball, only used if `spec` is a
185
- dictionary. List must be the length of the number of events. Ignored if
186
- `spec` is a DataFrame and contains a 'plot_longitude' column.
174
+ Longitude(s) at which to place beachball. List must be the length of the
175
+ number of events. Will override the plot_longitude in ``spec`` if
176
+ `` spec`` is a dict or DataFrame
187
177
plot_latitude: int, float, list, or 1d numpy array
188
- Latitude(s) at which to place beachball, only used if `spec` is a
189
- dictionary. List must be the length of the number of events. Ignored if
190
- `spec` is a DataFrame and contains a 'plot_latitude' column .
178
+ Latitude(s) at which to place beachball. List must be the length of the
179
+ number of events. Will override the plot_latideu in ``spec`` if ``spec``
180
+ is a dict or DataFrame .
191
181
offset: bool or str
192
182
Offsets beachballs to the longitude, latitude specified in the last two
193
183
columns of the input file or array, or by `plot_longitude` and
@@ -208,48 +198,11 @@ def meca(
208
198
{t}
209
199
"""
210
200
211
- # pylint warnings that need to be fixed
212
- # pylint: disable=too-many-locals
213
- # pylint: disable=too-many-nested-blocks
214
- # pylint: disable=too-many-branches
215
- # pylint: disable=too-many-statements
216
-
217
- def set_pointer (data_pointers , spec ):
218
- """
219
- Set optional parameter pointers based on DataFrame or dict, if those
220
- parameters are present in the DataFrame or dict.
221
- """
222
- for param in list (data_pointers ):
223
- if param in spec :
224
- # set pointer based on param name
225
- data_pointers [param ] = spec [param ]
226
-
227
- def update_pointers (data_pointers ):
228
- """
229
- Updates variables based on the location of data, as the following data
230
- can be passed as parameters or it can be contained in `spec`.
231
- """
232
- # update all pointers
233
- longitude = data_pointers ["longitude" ]
234
- latitude = data_pointers ["latitude" ]
235
- depth = data_pointers ["depth" ]
236
- plot_longitude = data_pointers ["plot_longitude" ]
237
- plot_latitude = data_pointers ["plot_latitude" ]
238
- return (longitude , latitude , depth , plot_longitude , plot_latitude )
239
-
240
201
kwargs = self ._preprocess (** kwargs ) # pylint: disable=protected-access
241
- # Check the spec and parse the data according to the specified
242
- # convention
243
202
if isinstance (spec , (dict , pd .DataFrame )):
244
- # dicts and DataFrames are handed similarly but not identically
245
- if (longitude is None or latitude is None or depth is None ) and not isinstance (
246
- spec , (dict , pd .DataFrame )
247
- ):
248
- raise GMTError ("Location not fully specified." )
249
-
250
203
param_conventions = {
251
- "AKI " : ["strike" , "dip" , "rake" , "magnitude" ],
252
- "GCMT " : [
204
+ "aki " : ["strike" , "dip" , "rake" , "magnitude" ],
205
+ "gcmt " : [
253
206
"strike1" ,
254
207
"dip1" ,
255
208
"rake1" ,
@@ -259,9 +212,9 @@ def update_pointers(data_pointers):
259
212
"mantissa" ,
260
213
"exponent" ,
261
214
],
262
- "MT " : ["mrr" , "mtt" , "mff" , "mrt" , "mrf" , "mtf" , "exponent" ],
263
- "PARTIAL " : ["strike1" , "dip1" , "strike2" , "fault_type" , "magnitude" ],
264
- "PRINCIPAL_AXIS " : [
215
+ "mt " : ["mrr" , "mtt" , "mff" , "mrt" , "mrf" , "mtf" , "exponent" ],
216
+ "partial " : ["strike1" , "dip1" , "strike2" , "fault_type" , "magnitude" ],
217
+ "pricipal_axis " : [
265
218
"t_exponent" ,
266
219
"t_azimuth" ,
267
220
"t_plunge" ,
@@ -274,195 +227,58 @@ def update_pointers(data_pointers):
274
227
"exponent" ,
275
228
],
276
229
}
277
-
278
- # to keep track of where optional parameters exist
279
- data_pointers = {
280
- "longitude" : longitude ,
281
- "latitude" : latitude ,
282
- "depth" : depth ,
283
- "plot_longitude" : plot_longitude ,
284
- "plot_latitude" : plot_latitude ,
285
- }
286
-
287
- # make a DataFrame copy to check convention if it contains other params
288
- # check if a copy is necessary
289
- copy = False
290
- drop_list = []
291
- for pointer in data_pointers :
292
- if pointer in spec :
293
- copy = True
294
- drop_list .append (pointer )
295
- if copy :
296
- spec_conv = spec .copy ()
297
- # delete optional parameters from copy for convention check
298
- for item in drop_list :
299
- del spec_conv [item ]
300
- else :
301
- spec_conv = spec
302
-
303
- # set convention and focal parameters based on spec convention
304
- for conv in list (param_conventions ):
305
- if set (spec_conv ) == set (param_conventions [conv ]):
306
- convention = conv .lower ()
307
- foc_params = param_conventions [conv ]
230
+ # determine the convention based on dict keys
231
+ for conv , paras in param_conventions .items ():
232
+ if set (paras ).issubset (set (spec .keys ())):
233
+ convention = conv
308
234
break
309
- else : # if there is no convention assigned
235
+ else :
310
236
raise GMTError (
311
237
"Parameters in spec dictionary do not match known conventions."
312
238
)
313
239
314
- # create a dict type pointer for easier to read code
315
- if isinstance (spec , dict ):
316
- dict_type_pointer = list (spec .values ())[0 ]
317
- elif isinstance (spec , pd .DataFrame ):
318
- # use df.values as pointer for DataFrame behavior
319
- dict_type_pointer = spec .values
320
-
321
- # assemble the 1D array for the case of floats and ints as values
322
- if isinstance (dict_type_pointer , (int , float )):
323
- # update pointers
324
- set_pointer (data_pointers , spec )
325
- # look for optional parameters in the right place
326
- (
327
- longitude ,
328
- latitude ,
329
- depth ,
330
- plot_longitude ,
331
- plot_latitude ,
332
- ) = update_pointers (data_pointers )
333
-
334
- # Construct the array (order matters)
335
- spec = [longitude , latitude , depth ] + [spec [key ] for key in foc_params ]
336
-
337
- # Add in plotting options, if given, otherwise add 0s
338
- for arg in plot_longitude , plot_latitude :
339
- if arg is None :
340
- spec .append (0 )
341
- else :
342
- if "A" not in kwargs :
343
- kwargs ["A" ] = True
344
- spec .append (arg )
345
-
346
- # or assemble the 2D array for the case of lists as values
347
- elif isinstance (dict_type_pointer , list ):
348
- # update pointers
349
- set_pointer (data_pointers , spec )
350
- # look for optional parameters in the right place
351
- (
352
- longitude ,
353
- latitude ,
354
- depth ,
355
- plot_longitude ,
356
- plot_latitude ,
357
- ) = update_pointers (data_pointers )
358
-
359
- # before constructing the 2D array lets check that each key
360
- # of the dict has the same quantity of values to avoid bugs
361
- list_length = len (list (spec .values ())[0 ])
362
- for value in list (spec .values ()):
363
- if len (value ) != list_length :
364
- raise GMTError (
365
- "Unequal number of focal mechanism "
366
- "parameters supplied in 'spec'."
367
- )
368
- # lets also check the inputs for longitude, latitude,
369
- # and depth if it is a list or array
370
- if (
371
- isinstance (longitude , (list , np .ndarray ))
372
- or isinstance (latitude , (list , np .ndarray ))
373
- or isinstance (depth , (list , np .ndarray ))
374
- ):
375
- if (len (longitude ) != len (latitude )) or (
376
- len (longitude ) != len (depth )
377
- ):
378
- raise GMTError (
379
- "Unequal number of focal mechanism " "locations supplied."
380
- )
381
-
382
- # values are ok, so build the 2D array
383
- spec_array = []
384
- for index in range (list_length ):
385
- # Construct the array one row at a time (note that order
386
- # matters here, hence the list comprehension!)
387
- row = [longitude [index ], latitude [index ], depth [index ]] + [
388
- spec [key ][index ] for key in foc_params
389
- ]
390
-
391
- # Add in plotting options, if given, otherwise add 0s as
392
- # required by GMT
393
- for arg in plot_longitude , plot_latitude :
394
- if arg is None :
395
- row .append (0 )
396
- else :
397
- if "A" not in kwargs :
398
- kwargs ["A" ] = True
399
- row .append (arg [index ])
400
- spec_array .append (row )
401
- spec = spec_array
402
-
403
- # or assemble the array for the case of pd.DataFrames
404
- elif isinstance (dict_type_pointer , np .ndarray ):
405
- # update pointers
406
- set_pointer (data_pointers , spec )
407
- # look for optional parameters in the right place
408
- (
409
- longitude ,
410
- latitude ,
411
- depth ,
412
- plot_longitude ,
413
- plot_latitude ,
414
- ) = update_pointers (data_pointers )
415
-
416
- # lets also check the inputs for longitude, latitude, and depth
417
- # just in case the user entered different length lists
418
- if (
419
- isinstance (longitude , (list , np .ndarray ))
420
- or isinstance (latitude , (list , np .ndarray ))
421
- or isinstance (depth , (list , np .ndarray ))
422
- ):
423
- if (len (longitude ) != len (latitude )) or (len (longitude ) != len (depth )):
424
- raise GMTError (
425
- "Unequal number of focal mechanism locations supplied."
426
- )
427
-
428
- # values are ok, so build the 2D array in the correct order
429
- spec_array = []
430
- for index in range (len (spec )):
431
- # Construct the array one row at a time (note that order
432
- # matters here, hence the list comprehension!)
433
- row = [longitude [index ], latitude [index ], depth [index ]] + [
434
- spec [key ][index ] for key in foc_params
435
- ]
436
-
437
- # Add in plotting options, if given, otherwise add 0s as
438
- # required by GMT
439
- for arg in plot_longitude , plot_latitude :
440
- if arg is None :
441
- row .append (0 )
442
- else :
443
- if "A" not in kwargs :
444
- kwargs ["A" ] = True
445
- row .append (arg [index ])
446
- spec_array .append (row )
447
- spec = spec_array
448
-
449
- else :
450
- raise GMTError ("Parameter 'spec' contains values of an unsupported type." )
240
+ # prepare for input arrays
241
+ # longitude, latitude, depth, focal_parameters, [plot_longitude, plot_latitude] [labels]
242
+ arrays = []
243
+ # a temporary dict for event locations
244
+ loc_spec = {
245
+ "longitude" : longitude if longitude is not None else spec ["longitude" ],
246
+ "latitude" : latitude if latitude is not None else spec ["latitude" ],
247
+ "depth" : depth if depth is not None else spec ["depth" ],
248
+ }
249
+ # a temporary dict for plotting beachballs
250
+ plotloc_spec = {
251
+ "plot_longtiude" : plot_longitude if plot_longitude is not None else spec .get ("plot_longitude" , None ),
252
+ "plot_latitude" : plot_latitude if plot_latitude is not None else spec .get ("plot_latitude" , None ),
253
+ }
254
+ # reset the plotloc_spec dict to empty if no plotting locations are given
255
+ if not all (plotloc_spec .values ()):
256
+ plotloc_spec = {}
257
+
258
+ # location arrays
259
+ arrays .extend (np .atleast_1d (value ) for param , value in loc_spec .items ())
260
+ # focal parameter arrays
261
+ arrays .extend (
262
+ np .atleast_1d (spec [param ]) for param in param_conventions [convention ]
263
+ )
264
+ # plotting location arrays if given
265
+ arrays .extend (np .atleast_1d (value ) for param , value in plotloc_spec .items ())
266
+ # TODO: label arrays
267
+ # transpose the 2D array
268
+ spec = np .atleast_2d (arrays ).T
269
+
270
+ # Convert 1d array types into 2d arrays
271
+ if isinstance (spec , np .ndarray ) and spec .ndim == 1 :
272
+ spec = np .atleast_2d (spec )
451
273
452
274
# determine data_foramt from convection and component
453
275
data_format = data_format_code (convention = convention , component = component )
454
276
455
277
# Assemble -S flag
456
278
kwargs ["S" ] = data_format + scale
457
-
458
- kind = data_kind (spec )
459
279
with Session () as lib :
460
- if kind == "matrix" :
461
- file_context = lib .virtualfile_from_matrix (np .atleast_2d (spec ))
462
- elif kind == "file" :
463
- file_context = dummy_context (spec )
464
- else :
465
- raise GMTInvalidInput (f"Unrecognized data type: { type (spec )} " )
280
+ # Choose how data will be passed into the module
281
+ file_context = lib .virtualfile_from_data (check_kind = "vector" , data = spec )
466
282
with file_context as fname :
467
283
arg_str = " " .join ([fname , build_arg_string (kwargs )])
468
284
lib .call_module ("meca" , arg_str )
0 commit comments