integrate_module 0.99.5__tar.gz → 0.99.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. {integrate_module-0.99.5/integrate_module.egg-info → integrate_module-0.99.6}/PKG-INFO +10 -1
  2. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate_io.py +86 -5
  3. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate_plot.py +137 -127
  4. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate_rejection.py +131 -37
  5. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate_rejection_jax.py +29 -6
  6. integrate_module-0.99.6/integrate/mlmapping.py +1110 -0
  7. {integrate_module-0.99.5 → integrate_module-0.99.6/integrate_module.egg-info}/PKG-INFO +10 -1
  8. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate_module.egg-info/SOURCES.txt +1 -0
  9. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate_module.egg-info/requires.txt +12 -0
  10. {integrate_module-0.99.5 → integrate_module-0.99.6}/pyproject.toml +13 -1
  11. {integrate_module-0.99.5 → integrate_module-0.99.6}/LICENSE +0 -0
  12. {integrate_module-0.99.5 → integrate_module-0.99.6}/README.md +0 -0
  13. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/__init__.py +0 -0
  14. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/gex.py +0 -0
  15. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate.py +0 -0
  16. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate_borehole.py +0 -0
  17. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate_hdf5_info_cli.py +0 -0
  18. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate_query.py +0 -0
  19. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate_rejection_cli.py +0 -0
  20. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate_timing_cli.py +0 -0
  21. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate/integrate_www_cli.py +0 -0
  22. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate_module.egg-info/dependency_links.txt +0 -0
  23. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate_module.egg-info/entry_points.txt +0 -0
  24. {integrate_module-0.99.5 → integrate_module-0.99.6}/integrate_module.egg-info/top_level.txt +0 -0
  25. {integrate_module-0.99.5 → integrate_module-0.99.6}/setup.cfg +0 -0
  26. {integrate_module-0.99.5 → integrate_module-0.99.6}/tests/test_likelihood_multinomial.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: integrate_module
3
- Version: 0.99.5
3
+ Version: 0.99.6
4
4
  Summary: Localized probabilistic data integration
5
5
  Author-email: Thomas Mejer Hansen <tmeha@geo.au.dk>
6
6
  License: MIT
@@ -34,6 +34,13 @@ Requires-Dist: jax
34
34
  Provides-Extra: dev
35
35
  Requires-Dist: pytest; extra == "dev"
36
36
  Requires-Dist: black; extra == "dev"
37
+ Provides-Extra: ml
38
+ Requires-Dist: tensorflow; extra == "ml"
39
+ Requires-Dist: scikit-learn; extra == "ml"
40
+ Requires-Dist: keras_tuner; extra == "ml"
41
+ Provides-Extra: examples
42
+ Requires-Dist: geopandas; extra == "examples"
43
+ Requires-Dist: shapely; extra == "examples"
37
44
  Provides-Extra: docs
38
45
  Requires-Dist: sphinx; extra == "docs"
39
46
  Requires-Dist: nbsphinx; extra == "docs"
@@ -43,6 +50,8 @@ Requires-Dist: myst-parser; extra == "docs"
43
50
  Requires-Dist: sphinx-rtd-theme; extra == "docs"
44
51
  Requires-Dist: furo; extra == "docs"
45
52
  Requires-Dist: tomli; python_version < "3.11" and extra == "docs"
53
+ Provides-Extra: jax-cuda
54
+ Requires-Dist: jax[cuda12]; extra == "jax-cuda"
46
55
  Dynamic: license-file
47
56
 
48
57
  # INTEGRATE Python Module
@@ -3240,7 +3240,7 @@ def save_data_gaussian(D_obs, D_std = [], d_std=[], Cd=[], id=1, id_prior=None,
3240
3240
  return f_data_h5
3241
3241
 
3242
3242
 
3243
- def xyz_to_h5(file_xyz, file_gex, f_data_h5=None, i_lm_skip=None, i_hm_skip=None, nan_value=None, showInfo=0, disregardFullNan=True, data_obs=None, data_std=None):
3243
+ def xyz_to_h5(file_xyz, file_gex, f_data_h5=None, i_lm_skip=None, i_hm_skip=None, nan_value=None, showInfo=0, disregardFullNan=True, data_obs=None, data_std=None, altitude=None, altitude_std=None, tx_altitude=None, tx_altitude_std=None, rx_altitude=None, rx_altitude_std=None):
3244
3244
  """
3245
3245
  Convert Aarhus Workbench XYZ export file(s) to an INTEGRATE HDF5 data file.
3246
3246
 
@@ -3292,6 +3292,38 @@ def xyz_to_h5(file_xyz, file_gex, f_data_h5=None, i_lm_skip=None, i_hm_skip=None
3292
3292
  same length as ``data_obs``. Use ``None`` for an individual entry to
3293
3293
  fall back to ``0.05 * |d_obs|`` for that column. If the whole
3294
3294
  parameter is omitted, all columns default to ``0.05 * |d_obs|``.
3295
+ altitude : str, optional
3296
+ Flightlines column name (case-insensitive) holding the platform's
3297
+ flight altitude/height, e.g. ``'Alt'``. When given, written as its
3298
+ own Gaussian data block with ``id=2`` (the second dataset, after the
3299
+ ``/D1`` dbdt data). Any ``data_obs`` columns are then written
3300
+ starting at ``id=3`` instead of ``id=2``.
3301
+ altitude_std : str, float, or None, optional
3302
+ Uncertainty for ``altitude``.
3303
+ - A **string** is treated as another flightlines column name
3304
+ (case-insensitive) holding the absolute std directly.
3305
+ - A **number** with ``abs(altitude_std) < 1`` is treated as a
3306
+ *relative* std: ``std = altitude_std * altitude``.
3307
+ - A **number** with ``abs(altitude_std) >= 1`` is treated as an
3308
+ *absolute* std in meters, constant for all soundings.
3309
+ - If ``None`` (default), falls back to ``0.05 * |altitude|``.
3310
+ tx_altitude : str, optional
3311
+ Flightlines column name (case-insensitive) holding the transmitter
3312
+ altitude/height. When given, written as its own Gaussian data block,
3313
+ immediately after ``altitude`` (if also given). Optional — omitted
3314
+ entirely if not given.
3315
+ tx_altitude_std : str, float, or None, optional
3316
+ Uncertainty for ``tx_altitude``. Same rules as ``altitude_std``
3317
+ (string column name / relative number / absolute number / default
3318
+ 5% relative if ``None``). Only used if ``tx_altitude`` is given.
3319
+ rx_altitude : str, optional
3320
+ Flightlines column name (case-insensitive) holding the receiver
3321
+ altitude/height. When given, written as its own Gaussian data block,
3322
+ after ``altitude`` and ``tx_altitude`` (if also given). Optional —
3323
+ omitted entirely if not given.
3324
+ rx_altitude_std : str, float, or None, optional
3325
+ Uncertainty for ``rx_altitude``. Same rules as ``altitude_std``.
3326
+ Only used if ``rx_altitude`` is given.
3295
3327
 
3296
3328
  Returns
3297
3329
  -------
@@ -3380,9 +3412,22 @@ def xyz_to_h5(file_xyz, file_gex, f_data_h5=None, i_lm_skip=None, i_hm_skip=None
3380
3412
  ld = {k: pd.concat([xyz.layer_data[k] for xyz in xyz_list], ignore_index=True)
3381
3413
  for k in xyz_list[0].layer_data}
3382
3414
 
3383
- # Handle XYZ files that use 'x'/'y' instead of 'utmx'/'utmy'
3415
+ # Handle XYZ files that use alternate column names for geometry
3416
+ # (e.g. tTEM: utmx/utmy/line_no/elevation, SkyTEM: e/n/line/dem)
3384
3417
  if 'utmx' not in fl.columns and 'x' in fl.columns:
3385
3418
  fl = fl.rename(columns={'x': 'utmx', 'y': 'utmy'})
3419
+ if 'utmx' not in fl.columns and 'e' in fl.columns:
3420
+ fl = fl.rename(columns={'e': 'utmx', 'n': 'utmy'})
3421
+ if 'line_no' not in fl.columns and 'line' in fl.columns:
3422
+ fl = fl.rename(columns={'line': 'line_no'})
3423
+ if 'elevation' not in fl.columns and 'dem' in fl.columns:
3424
+ fl = fl.rename(columns={'dem': 'elevation'})
3425
+
3426
+ # Handle single-channel XYZ files (e.g. SkyTEM) that store the sounding
3427
+ # data under a plain component name instead of the tTEM 'ch1gt' naming
3428
+ if 'dbdt_ch1gt' not in ld and 'z_dbdt' in ld:
3429
+ ld['dbdt_ch1gt'] = ld['z_dbdt']
3430
+ ld['dbdt_std_ch1gt'] = ld['relunc_z_dbdt']
3386
3431
 
3387
3432
  # Determine dummy/missing value: explicit arg > XYZ header > fallback 9999
3388
3433
  if nan_value is None:
@@ -3393,7 +3438,12 @@ def xyz_to_h5(file_xyz, file_gex, f_data_h5=None, i_lm_skip=None, i_hm_skip=None
3393
3438
  # --- pair ch1 / ch2 rows (mirrors MATLAB logic) ---
3394
3439
  # Every ch1 row becomes a sounding. HM data is filled where the
3395
3440
  # immediately following row is ch2; otherwise those columns stay NaN.
3396
- channel_arr = fl['channel_no'].values
3441
+ # Single-channel systems (e.g. SkyTEM) have no 'channel_no' column at
3442
+ # all: every row is its own (channel-1) sounding.
3443
+ if 'channel_no' in fl.columns:
3444
+ channel_arr = fl['channel_no'].values
3445
+ else:
3446
+ channel_arr = np.ones(len(fl))
3397
3447
  ch1_pos = np.where(channel_arr == 1)[0]
3398
3448
 
3399
3449
  # geometry from channel-1 rows (all of them)
@@ -3475,7 +3525,38 @@ def xyz_to_h5(file_xyz, file_gex, f_data_h5=None, i_lm_skip=None, i_hm_skip=None
3475
3525
  if n_channels >= 2:
3476
3526
  hf.create_dataset('/D1/i_hm', data=np.arange(i_hm_start, i_hm_end))
3477
3527
 
3478
- # --- write additional data columns as D2, D3, ... ---
3528
+ # --- write altitude / rx_altitude / tx_altitude (if given) as their own Gaussian data blocks ---
3529
+ def _resolve_std(obs, std_arg):
3530
+ if isinstance(std_arg, str):
3531
+ return fl[std_arg.lower()].values[ch1_pos][keep].reshape(-1, 1).astype(float)
3532
+ elif isinstance(std_arg, (int, float)):
3533
+ if abs(std_arg) < 1:
3534
+ return std_arg * np.abs(obs) # relative
3535
+ else:
3536
+ return np.full_like(obs, float(std_arg)) # absolute, meters
3537
+ else:
3538
+ return 0.05 * np.abs(obs) # default: 5% relative
3539
+
3540
+ next_id = 2
3541
+ for col, col_std, name in (
3542
+ (altitude, altitude_std, 'Altitude'),
3543
+ (tx_altitude, tx_altitude_std, 'Tx_altitude'),
3544
+ (rx_altitude, rx_altitude_std, 'Rx_altitude'),
3545
+ ):
3546
+ if col is not None:
3547
+ obs = fl[col.lower()].values[ch1_pos][keep].reshape(-1, 1).astype(float)
3548
+ std = _resolve_std(obs, col_std)
3549
+ save_data_gaussian(
3550
+ obs, D_std=std,
3551
+ f_data_h5=f_data_h5,
3552
+ id=next_id,
3553
+ name=name,
3554
+ delete_if_exist=False,
3555
+ showInfo=showInfo,
3556
+ )
3557
+ next_id += 1
3558
+
3559
+ # --- write additional data columns as D2, D3, ... (or shifted if altitude present) ---
3479
3560
  if data_obs is not None:
3480
3561
  _data_std = data_std if data_std is not None else [None] * len(data_obs)
3481
3562
  for i, col_obs in enumerate(data_obs):
@@ -3488,7 +3569,7 @@ def xyz_to_h5(file_xyz, file_gex, f_data_h5=None, i_lm_skip=None, i_hm_skip=None
3488
3569
  save_data_gaussian(
3489
3570
  obs, D_std=std,
3490
3571
  f_data_h5=f_data_h5,
3491
- id=i + 2,
3572
+ id=next_id + i,
3492
3573
  name=col_obs,
3493
3574
  delete_if_exist=False,
3494
3575
  showInfo=showInfo,
@@ -2902,20 +2902,23 @@ def plot_discrete_data_entropy(f_data_h5, id_list, depth_reduce='min', **kwargs)
2902
2902
  return plot_xy(H, f_data_h5=f_data_h5, **kwargs)
2903
2903
 
2904
2904
 
2905
- def plot_data(f_data_h5, i_plot=[], Dkey=[], plType='imshow', uselog=True, **kwargs):
2905
+ def plot_data(f_data_h5, i_plot=[], Dkey=[], id=None, plType='imshow', uselog=True, **kwargs):
2906
2906
  """
2907
2907
  Plot observational data from an HDF5 file.
2908
-
2908
+
2909
2909
  This function creates visualizations of electromagnetic data including time-series plots,
2910
2910
  2D image displays, and other data representations. Supports multiple data types and
2911
2911
  plotting styles for comprehensive data analysis.
2912
-
2912
+
2913
2913
  :param f_data_h5: Path to the HDF5 file containing observational data
2914
2914
  :type f_data_h5: str
2915
2915
  :param i_plot: Indices of data points to plot. If empty, plots all available data
2916
2916
  :type i_plot: list or array-like, optional
2917
2917
  :param Dkey: Data keys/identifiers to plot. If empty, uses all available datasets
2918
2918
  :type Dkey: str or list, optional
2919
+ :param id: Dataset id to plot (e.g. id=1 plots only 'D1'). If None (default) and
2920
+ Dkey is also unset, every dataset found in the file (D1, D2, ...) is plotted.
2921
+ :type id: int, optional
2919
2922
  :param plType: Plotting method - 'imshow' for 2D image display, 'plot' for line plots
2920
2923
  :type plType: str, optional
2921
2924
  :param uselog: Apply logarithmic scaling to data visualization (default is True)
@@ -2947,155 +2950,162 @@ def plot_data(f_data_h5, i_plot=[], Dkey=[], plType='imshow', uselog=True, **kwa
2947
2950
  return
2948
2951
 
2949
2952
 
2953
+ # set plot in kwarg to True if not already set
2954
+ if 'hardcopy' not in kwargs:
2955
+ kwargs['hardcopy'] = True
2956
+
2950
2957
  with h5py.File(f_data_h5,'r') as f_data:
2951
2958
 
2952
- if len(Dkey)==0:
2953
- nd = 0
2959
+ if id is not None:
2960
+ Dkeys = ['D%d' % id]
2961
+ elif len(Dkey)==0:
2954
2962
  Dkeys = []
2955
2963
  for key in f_data.keys():
2956
2964
  if key[0]=='D':
2957
2965
  if showInfo>0:
2958
2966
  print("plot_data: Found data set %s" % key)
2959
2967
  Dkeys.append(key)
2960
- nd += 1
2961
- Dkey=Dkeys[0]
2962
2968
  if showInfo>0:
2963
- print("plot_data: Using data set %s" % Dkey)
2969
+ print("plot_data: Using data set(s) %s" % Dkeys)
2970
+ elif isinstance(Dkey, str):
2971
+ Dkeys = [Dkey]
2972
+ else:
2973
+ Dkeys = list(Dkey)
2964
2974
 
2965
- noise_model = f_data['/%s' % Dkey].attrs['noise_model']
2975
+ for Dkey in Dkeys:
2976
+ noise_model = f_data['/%s' % Dkey].attrs['noise_model']
2966
2977
 
2967
- # Get name attribute if it exists
2968
- name_attr = f_data['/%s' % Dkey].attrs.get('name', None)
2978
+ # Get name attribute if it exists
2979
+ name_attr = f_data['/%s' % Dkey].attrs.get('name', None)
2969
2980
 
2970
- # Force plot type for discrete/multinomial data
2971
- if noise_model == 'multinomial' or Dkey.upper() in ['D2', 'D3', 'D4', 'D5']:
2972
- plType = 'plot'
2981
+ # Force plot type for discrete/multinomial data
2982
+ cur_plType = plType
2983
+ if noise_model == 'multinomial' or Dkey.upper() in ['D2', 'D3', 'D4', 'D5']:
2984
+ cur_plType = 'plot'
2973
2985
 
2974
- if noise_model == 'gaussian':
2975
- noise_model = 'Gaussian'
2976
- d_obs = f_data['/%s' % Dkey]['d_obs'][:]
2977
- d_std = f_data['/%s' % Dkey]['d_std'][:]
2986
+ if noise_model == 'gaussian':
2987
+ noise_model = 'Gaussian'
2988
+ d_obs = f_data['/%s' % Dkey]['d_obs'][:]
2989
+ d_std = f_data['/%s' % Dkey]['d_std'][:]
2978
2990
 
2979
2991
 
2980
- ndata,ns = f_data['/%s' % Dkey]['d_obs'].shape
2981
- # set i_plot as an array from 0 to ndata
2982
- if len(i_plot)==0:
2983
- i_plot = np.arange(ndata)
2984
- #i_plot = 1000+np.arange(5000)
2992
+ ndata,ns = f_data['/%s' % Dkey]['d_obs'].shape
2993
+ # set i_plot_cur as an array from 0 to ndata
2994
+ if len(i_plot)==0:
2995
+ i_plot_cur = np.arange(ndata)
2996
+ else:
2997
+ i_plot_cur = np.asarray(i_plot)
2985
2998
 
2986
- # remove all values in i_plot that are larger than the number of data
2987
- i_plot = i_plot[i_plot<ndata]
2988
- # remove all values in i_plot that are smaller than 0
2989
- i_plot = i_plot[i_plot>=0]
2999
+ # remove all values in i_plot_cur that are larger than the number of data
3000
+ i_plot_cur = i_plot_cur[i_plot_cur<ndata]
3001
+ # remove all values in i_plot_cur that are smaller than 0
3002
+ i_plot_cur = i_plot_cur[i_plot_cur>=0]
2990
3003
 
2991
- # find number of nan values on d_obs
2992
- non_nan = np.sum(~np.isnan(d_obs), axis=1)
3004
+ # find number of nan values on d_obs
3005
+ non_nan = np.sum(~np.isnan(d_obs), axis=1)
2993
3006
 
2994
- # Calculate the extent
2995
- # extent = [left, right, bottom, top]; imshow row 0 maps to top,
2996
- # so bottom=N_gates and top=0 gives gate 0 at the top of the plot
2997
- # with the y-axis label reading 0→N_gates from top to bottom.
2998
- xlim = [i_plot.min(), i_plot.max()]
2999
- extent = [xlim[0], xlim[1], d_obs.shape[1], 1]
3007
+ # Calculate the extent
3008
+ # extent = [left, right, bottom, top]; imshow row 0 maps to top,
3009
+ # so bottom=N_gates and top=0 gives gate 0 at the top of the plot
3010
+ # with the y-axis label reading 0→N_gates from top to bottom.
3011
+ xlim = [i_plot_cur.min(), i_plot_cur.max()]
3012
+ extent = [xlim[0], xlim[1], d_obs.shape[1], 1]
3000
3013
 
3001
- # plot figure with data
3014
+ # plot figure with data
3002
3015
 
3003
- fig, ax = plt.subplots(4,1,figsize=(10,12), gridspec_kw={'height_ratios': [3, 3, 3, 1]})
3016
+ fig, ax = plt.subplots(4,1,figsize=(10,12), gridspec_kw={'height_ratios': [3, 3, 3, 1]})
3004
3017
 
3005
- # Set suptitle with optional name attribute
3018
+ # Set suptitle with optional name attribute
3006
3019
 
3007
- if plType=='plot':
3008
- if uselog:
3009
- im1 = ax[0].semilogy(d_obs[i_plot,:], linewidth=.5)
3010
- im2 = ax[1].semilogy(d_std[i_plot,:], linewidth=.5)
3011
- im3 = ax[2].semilogy((d_obs[i_plot,:]/d_std[i_plot,:]), linewidth=.5)
3012
- else:
3013
- im1 = ax[0].plot(d_obs[i_plot,:], linewidth=.5)
3014
- im2 = ax[1].plot(d_std[i_plot,:], linewidth=.5)
3015
- im3 = ax[2].plot(100.0 * d_std[i_plot,:]/d_obs[i_plot,:], linewidth=.5)
3016
- ax[0].set_xlim(xlim)
3017
- ax[1].set_xlim(xlim)
3018
- ax[2].set_xlim(xlim)
3019
- ax[2].set_ylim([0, 20])
3020
- ax[0].set_ylabel('d_obs')
3021
- ax[1].set_ylabel('d_std')
3022
- ax[2].set_ylabel('Relative noise [%] (d_std/d_obs × 100)')
3023
-
3024
- elif plType=='imshow':
3025
- def _masked(arr):
3026
- """Mask NaN, inf, and non-positive values; leave positives intact."""
3027
- return np.ma.masked_where(~np.isfinite(arr) | (arr <= 0), arr)
3028
-
3029
- def _cmap_white_bad(name):
3030
- cmap = matplotlib.colormaps[name].copy()
3031
- cmap.set_bad('white')
3032
- return cmap
3033
-
3034
- if uselog:
3035
- im1 = ax[0].imshow(_masked(d_obs[i_plot,:]).T, aspect='auto',
3036
- cmap=_cmap_white_bad('jet_r'),
3037
- norm=matplotlib.colors.LogNorm(), extent=extent)
3038
- im2 = ax[1].imshow(_masked(d_std[i_plot,:]).T, aspect='auto',
3039
- cmap=_cmap_white_bad('hot_r'),
3040
- norm=matplotlib.colors.LogNorm(), extent=extent)
3020
+ if cur_plType=='plot':
3021
+ if uselog:
3022
+ im1 = ax[0].semilogy(d_obs[i_plot_cur,:], linewidth=.5)
3023
+ im2 = ax[1].semilogy(d_std[i_plot_cur,:], linewidth=.5)
3024
+ im3 = ax[2].semilogy((d_obs[i_plot_cur,:]/d_std[i_plot_cur,:]), linewidth=.5)
3025
+ else:
3026
+ im1 = ax[0].plot(d_obs[i_plot_cur,:], linewidth=.5)
3027
+ im2 = ax[1].plot(d_std[i_plot_cur,:], linewidth=.5)
3028
+ im3 = ax[2].plot(100.0 * d_std[i_plot_cur,:]/d_obs[i_plot_cur,:], linewidth=.5)
3029
+ ax[0].set_xlim(xlim)
3030
+ ax[1].set_xlim(xlim)
3031
+ ax[2].set_xlim(xlim)
3032
+ ax[2].set_ylim([0, 20])
3033
+ ax[0].set_ylabel('d_obs')
3034
+ ax[1].set_ylabel('d_std')
3035
+ ax[2].set_ylabel('Relative noise [%] (d_std/d_obs × 100)')
3036
+
3037
+ elif cur_plType=='imshow':
3038
+ def _masked(arr):
3039
+ """Mask NaN, inf, and non-positive values; leave positives intact."""
3040
+ return np.ma.masked_where(~np.isfinite(arr) | (arr <= 0), arr)
3041
+
3042
+ def _cmap_white_bad(name):
3043
+ cmap = matplotlib.colormaps[name].copy()
3044
+ cmap.set_bad('white')
3045
+ return cmap
3046
+
3047
+ if uselog:
3048
+ im1 = ax[0].imshow(_masked(d_obs[i_plot_cur,:]).T, aspect='auto',
3049
+ cmap=_cmap_white_bad('jet_r'),
3050
+ norm=matplotlib.colors.LogNorm(), extent=extent)
3051
+ im2 = ax[1].imshow(_masked(d_std[i_plot_cur,:]).T, aspect='auto',
3052
+ cmap=_cmap_white_bad('hot_r'),
3053
+ norm=matplotlib.colors.LogNorm(), extent=extent)
3054
+ else:
3055
+ im1 = ax[0].imshow(np.ma.masked_invalid(d_obs[i_plot_cur,:]).T,
3056
+ aspect='auto', cmap=_cmap_white_bad('jet_r'), extent=extent)
3057
+ im2 = ax[1].imshow(np.ma.masked_invalid(d_std[i_plot_cur,:]).T,
3058
+ aspect='auto', cmap=_cmap_white_bad('hot_r'), extent=extent)
3059
+
3060
+ # Relative noise in % — mask invalid entries
3061
+ rel_noise = np.ma.masked_invalid(100.0 * d_std[i_plot_cur,:] / d_obs[i_plot_cur,:])
3062
+ im3 = ax[2].imshow(rel_noise.T, aspect='auto', vmin=0, vmax=20,
3063
+ cmap=_cmap_white_bad('turbo'), extent=extent)
3064
+
3065
+ fig.colorbar(im1, ax=ax[0])
3066
+ fig.colorbar(im2, ax=ax[1])
3067
+ fig.colorbar(im3, ax=ax[2])
3068
+
3069
+ ax[0].set_ylabel('gate number')
3070
+ ax[1].set_ylabel('gate number')
3071
+ ax[2].set_ylabel('gate number')
3072
+
3073
+ ax[0].set_title('d_obs: observed data')
3074
+ ax[1].set_title('d_std: standard deviation')
3075
+ ax[2].set_title('Relative noise, % (d_std / d_obs × 100)')
3076
+
3077
+
3078
+ im4 = ax[3].plot(i_plot_cur,non_nan[i_plot_cur], 'k.', markersize=.5)
3079
+ ax[3].set_ylabel('Number of data')
3080
+ ax[3].set_xlim(xlim)
3081
+
3082
+ if cur_plType=='imshow':
3083
+ # Create an invisible colorbar for the last subplot
3084
+ cbar4 = fig.colorbar(im3, ax=ax[3])
3085
+ cbar4.solids.set(alpha=0)
3086
+ cbar4.outline.set_visible(False)
3087
+ cbar4.ax.set_yticks([]) # Hide the colorbar ticks
3088
+ cbar4.ax.set_yticklabels([]) # Hide the colorbar ticks labels
3089
+
3090
+ ax[-1].set_xlabel('Index')
3091
+
3092
+ ax[0].grid()
3093
+ ax[1].grid()
3094
+ ax[2].grid()
3095
+ ax[3].grid()
3096
+
3097
+ if name_attr is not None:
3098
+ fig.suptitle("Dataset %s: %s" % (Dkey, name_attr))
3041
3099
  else:
3042
- im1 = ax[0].imshow(np.ma.masked_invalid(d_obs[i_plot,:]).T,
3043
- aspect='auto', cmap=_cmap_white_bad('jet_r'), extent=extent)
3044
- im2 = ax[1].imshow(np.ma.masked_invalid(d_std[i_plot,:]).T,
3045
- aspect='auto', cmap=_cmap_white_bad('hot_r'), extent=extent)
3046
-
3047
- # Relative noise in % — mask invalid entries
3048
- rel_noise = np.ma.masked_invalid(100.0 * d_std[i_plot,:] / d_obs[i_plot,:])
3049
- im3 = ax[2].imshow(rel_noise.T, aspect='auto', vmin=0, vmax=20,
3050
- cmap=_cmap_white_bad('turbo'), extent=extent)
3051
-
3052
- fig.colorbar(im1, ax=ax[0])
3053
- fig.colorbar(im2, ax=ax[1])
3054
- fig.colorbar(im3, ax=ax[2])
3055
-
3056
- ax[0].set_ylabel('gate number')
3057
- ax[1].set_ylabel('gate number')
3058
- ax[2].set_ylabel('gate number')
3059
-
3060
- ax[0].set_title('d_obs: observed data')
3061
- ax[1].set_title('d_std: standard deviation')
3062
- ax[2].set_title('Relative noise, % (d_std / d_obs × 100)')
3063
-
3064
-
3065
- im4 = ax[3].plot(i_plot,non_nan[i_plot], 'k.', markersize=.5)
3066
- ax[3].set_ylabel('Number of data')
3067
- ax[3].set_xlim(xlim)
3068
-
3069
- if plType=='imshow':
3070
- # Create an invisible colorbar for the last subplot
3071
- cbar4 = fig.colorbar(im3, ax=ax[3])
3072
- cbar4.solids.set(alpha=0)
3073
- cbar4.outline.set_visible(False)
3074
- cbar4.ax.set_yticks([]) # Hide the colorbar ticks
3075
- cbar4.ax.set_yticklabels([]) # Hide the colorbar ticks labels
3076
-
3077
- ax[-1].set_xlabel('Index')
3078
-
3079
- ax[0].grid()
3080
- ax[1].grid()
3081
- ax[2].grid()
3082
- ax[3].grid()
3083
-
3084
- if name_attr is not None:
3085
- fig.suptitle("Dataset %s: %s" % (Dkey, name_attr))
3086
- else:
3087
- fig.suptitle("Dataset %s" % Dkey)
3100
+ fig.suptitle("Dataset %s" % Dkey)
3088
3101
 
3089
- plt.tight_layout()
3090
- else:
3091
- print("plot_data: Unknown noise model: %s" % noise_model)
3102
+ plt.tight_layout()
3092
3103
 
3093
- # set plot in kwarg to True if not allready set
3094
- if 'hardcopy' not in kwargs:
3095
- kwargs['hardcopy'] = True
3096
- if kwargs['hardcopy']:
3097
- # strip the filename from f_data_h5
3098
- plt.savefig('%s_%s_%s.png' % (os.path.splitext(f_data_h5)[0],Dkey,plType), bbox_inches='tight')
3104
+ if kwargs['hardcopy']:
3105
+ # strip the filename from f_data_h5
3106
+ plt.savefig('%s_%s_%s.png' % (os.path.splitext(f_data_h5)[0],Dkey,cur_plType), bbox_inches='tight')
3107
+ else:
3108
+ print("plot_data: Unknown noise model: %s" % noise_model)
3099
3109
 
3100
3110
 
3101
3111