wawi 0.0.16__py3-none-any.whl → 0.0.17__py3-none-any.whl

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.
wawi/plot.py CHANGED
@@ -8,7 +8,42 @@ from scipy.interpolate import RectBivariateSpline, interp1d
8
8
 
9
9
 
10
10
  def plot_ads(ad_dict, v, terms='stiffness', num=None, test_v=dict(), test_ad=dict(), zasso_type=False, ranges=None):
11
- # v: v or K
11
+ """
12
+ Plot aerodynamic derivative (AD) curves for multiple terms and test data.
13
+
14
+ Parameters
15
+ ----------
16
+ ad_dict : dict
17
+ Dictionary mapping term names (e.g., 'P4', 'H6', etc.) to functions that compute aerodynamic derivative values for a given `v`.
18
+ v : array-like
19
+ Array of reduced velocity (or reduced frequency) at which to evaluate the aerodynamic derivative functions.
20
+ terms : str or list of list of str, optional
21
+ Specifies which terms to plot. If 'stiffness' or 'damping', uses predefined groupings. Otherwise, expects a nested list of term names.
22
+ num : int or None, optional
23
+ Figure number for matplotlib. If None, a new figure is created.
24
+ test_v : dict, optional
25
+ Dictionary mapping term names to arrays of test reduced velocity values for overlaying test data.
26
+ test_ad : dict, optional
27
+ Dictionary mapping term names to arrays of test aerodynamic derivative data corresponding to `test_v`.
28
+ zasso_type : bool, optional
29
+ If True, applies special formatting and scaling for Zasso-type plots.
30
+ ranges : dict or None, optional
31
+ Dictionary mapping term names to (min, max) tuples, specifying valid ranges for plotting. Values outside the range are clipped.
32
+
33
+ Returns
34
+ -------
35
+ fig : matplotlib.figure.Figure
36
+ The matplotlib Figure object containing the plots.
37
+ ax : numpy.ndarray of matplotlib.axes.Axes
38
+ Array of Axes objects for each subplot.
39
+
40
+ Notes
41
+ -----
42
+ - The function arranges subplots in a grid according to the structure of `terms`.
43
+ - Each subplot shows the fitted aerodynamic derivative curve and, if provided, test data points.
44
+ - Axis labels and scaling are adjusted depending on `zasso_type` and the term type.
45
+ """
46
+
12
47
  if terms == 'stiffness':
13
48
  terms = [['P4', 'P6', 'P3'], ['H6', 'H4', 'H3'], ['A6', 'A4', 'A3']]
14
49
  elif terms == 'damping':
@@ -68,6 +103,22 @@ def plot_ads(ad_dict, v, terms='stiffness', num=None, test_v=dict(), test_ad=dic
68
103
  return fig, ax
69
104
 
70
105
  def save_plot(pl, path, w=None, h=None):
106
+ '''
107
+ Saves pyvista plotter screenshot to file.
108
+
109
+ Parameters
110
+ ----------
111
+ pl : pyvista.Plotter
112
+ PyVista plotter object.
113
+ path : str
114
+ Path to save the screenshot.
115
+ w : int, optional
116
+ Width of the screenshot. If None, uses the width of the plotter window.
117
+ h : int, optional
118
+ Height of the screenshot. If None, uses the height of the plotter window.
119
+
120
+
121
+ '''
71
122
  ws = pl.window_size
72
123
  if w is not None and h is None:
73
124
  w = int(np.round(w))
@@ -86,9 +137,46 @@ def save_plot(pl, path, w=None, h=None):
86
137
  def plot_dir_and_crests(theta0, Tp, arrow_length=100, origin=np.array([0,0]),
87
138
  ax=None, n_repeats=2, crest_length=1000,
88
139
  alpha_crests=0.2, arrow_options={}):
140
+
141
+ """
142
+ Plot wave direction arrow and wave crests on a matplotlib axis.
143
+
144
+ Parameters
145
+ ----------
146
+ theta0 : float
147
+ Wave direction in degrees (0 degrees is along the x-axis).
148
+ Tp : float
149
+ Peak wave period in seconds.
150
+ arrow_length : float, optional
151
+ Length of the direction arrow (default is 100).
152
+ origin : np.ndarray, optional
153
+ 2D coordinates of the arrow origin (default is np.array([0, 0])).
154
+ ax : matplotlib.axes.Axes, optional
155
+ Axis to plot on. If None, uses current axis (default is None).
156
+ n_repeats : int, optional
157
+ Number of wave crests to plot (default is 2).
158
+ crest_length : float, optional
159
+ Length of each wave crest line (default is 1000).
160
+ alpha_crests : float, optional
161
+ Transparency (alpha) for the crest lines (default is 0.2).
162
+ arrow_options : dict, optional
163
+ Additional keyword arguments for the arrow (default is {}).
164
+
165
+ Returns
166
+ -------
167
+ ax : matplotlib.axes.Axes
168
+ The axis with the plotted wave direction and crests.
169
+
170
+ Notes
171
+ -----
172
+ - Requires `matplotlib.pyplot` as `plt` and `numpy` as `np` to be imported.
173
+ - The function also requires a `get_kappa` function to compute the wavenumber.
174
+
175
+ Docstring generated by GitHub Copilot.
176
+ """
89
177
  arr_opts = {'head_width': 4, 'width':2, 'edgecolor':'none'}
90
178
  arr_opts.update(**arrow_options)
91
-
179
+
92
180
  if ax is None:
93
181
  ax = plt.gca()
94
182
 
@@ -112,6 +200,41 @@ def plot_dir_and_crests(theta0, Tp, arrow_length=100, origin=np.array([0,0]),
112
200
  return ax
113
201
 
114
202
  def rotate_image_about_pivot(Z, x, y, angle, x0=0, y0=0):
203
+ """
204
+ Rotate an image array about a specified pivot point.
205
+ This function rotates a 2D image array `Z` by a given angle (in degrees) about a pivot point (`x0`, `y0`),
206
+ where the image axes are defined by the coordinate arrays `x` and `y`. The rotation is performed in the
207
+ coordinate space defined by `x` and `y`, not necessarily pixel indices.
208
+
209
+ Parameters
210
+ ----------
211
+ Z : ndarray
212
+ 2D array representing the image to be rotated.
213
+ x : array_like
214
+ 1D array of x-coordinates corresponding to the columns of `Z`.
215
+ y : array_like
216
+ 1D array of y-coordinates corresponding to the rows of `Z`.
217
+ angle : float
218
+ Rotation angle in degrees. Positive values correspond to counter-clockwise rotation.
219
+ x0 : float, optional
220
+ X-coordinate of the pivot point about which to rotate. Default is 0.
221
+ y0 : float, optional
222
+ Y-coordinate of the pivot point about which to rotate. Default is 0.
223
+
224
+ Returns
225
+ -------
226
+ rotated_Z : ndarray
227
+ The rotated image array, with the same shape as `Z`.
228
+
229
+ Notes
230
+ -----
231
+ - The function uses interpolation to map between coordinate space and pixel indices.
232
+ - The rotation is performed about the specified pivot point (`x0`, `y0`) in the coordinate system defined by `x` and `y`.
233
+ - Requires `numpy`, `scipy.ndimage.shift`, `scipy.ndimage.rotate`, and `scipy.interpolate.interp1d`.
234
+
235
+ Docstring generated by GitHub Copilot.
236
+ """
237
+
115
238
  xc = np.mean(x)
116
239
  yc = np.mean(y)
117
240
 
@@ -130,6 +253,45 @@ def rotate_image_about_pivot(Z, x, y, angle, x0=0, y0=0):
130
253
  return shift(rotate(shift(Z, ds[::-1]), angle), -ds_rot[::-1])
131
254
 
132
255
  def combine_eta(eta_fine, eta_course, x_fine, y_fine, x_course, y_course, x=None, y=None):
256
+ """
257
+ Combine two 2D fields (fine and coarse) into a single field, using the fine field where available.
258
+
259
+ Parameters
260
+ ----------
261
+ eta_fine : ndarray
262
+ 2D array of the fine-resolution field values.
263
+ eta_course : ndarray
264
+ 2D array of the coarse-resolution field values.
265
+ x_fine : ndarray
266
+ 1D array of x-coordinates for the fine field.
267
+ y_fine : ndarray
268
+ 1D array of y-coordinates for the fine field.
269
+ x_course : ndarray
270
+ 1D array of x-coordinates for the coarse field.
271
+ y_course : ndarray
272
+ 1D array of y-coordinates for the coarse field.
273
+ x : ndarray, optional
274
+ 1D array of x-coordinates for the output grid. If None, generated from coarse grid.
275
+ y : ndarray, optional
276
+ 1D array of y-coordinates for the output grid. If None, generated from coarse grid.
277
+
278
+ Returns
279
+ -------
280
+ eta_combined : ndarray
281
+ 2D array of the combined field, using fine field values where available and coarse elsewhere.
282
+ x : ndarray
283
+ 1D array of x-coordinates for the combined field.
284
+ y : ndarray
285
+ 1D array of y-coordinates for the combined field.
286
+
287
+ Notes
288
+ -----
289
+ The function interpolates both input fields onto a common grid. The fine field overwrites the coarse field
290
+ in the region where it is defined.
291
+
292
+ Docstring generated by GitHub Copilot.
293
+ """
294
+
133
295
  dx_fine = x_fine[1]-x_fine[0]
134
296
  dy_fine = y_fine[1]-y_fine[0]
135
297
 
@@ -156,7 +318,47 @@ def combine_eta(eta_fine, eta_course, x_fine, y_fine, x_course, y_course, x=None
156
318
  def animate_surface(eta, x, y, t, filename=None, fps=None,
157
319
  speed_ratio=1.0, figsize=None, writer='ffmpeg',
158
320
  ax=None, surface=None):
159
-
321
+ """
322
+ Animates a time-evolving eta (sea surface).
323
+
324
+ Parameters
325
+ ----------
326
+ eta : ndarray
327
+ 3D array of surface values with shape (nx, ny, nt), where nt is the number of time steps.
328
+ x : ndarray
329
+ 1D or 2D array representing the x-coordinates of the surface grid.
330
+ y : ndarray
331
+ 1D or 2D array representing the y-coordinates of the surface grid.
332
+ t : ndarray
333
+ 1D array of time points corresponding to the third dimension of `eta`.
334
+ filename : str or None, optional
335
+ If provided, the animation is saved to this file. If None, the animation is displayed interactively.
336
+ fps : float or None, optional
337
+ Frames per second for the animation. If None, it is computed from the time step and `speed_ratio`.
338
+ speed_ratio : float, optional
339
+ Ratio to speed up or slow down the animation relative to real time. Default is 1.0.
340
+ figsize : tuple or None, optional
341
+ Size of the figure in inches. Passed to `plt.subplots` if a new figure is created.
342
+ writer : str, optional
343
+ Writer to use for saving the animation (e.g., 'ffmpeg'). Default is 'ffmpeg'.
344
+ ax : matplotlib.axes.Axes or None, optional
345
+ Axes object to plot on. If None, a new figure and axes are created.
346
+ surface : matplotlib.image.AxesImage or None, optional
347
+ Existing surface image to update. If None, a new surface is created.
348
+
349
+ Returns
350
+ -------
351
+ None
352
+ The function either displays the animation or saves it to a file.
353
+
354
+ Notes
355
+ -----
356
+ - Requires matplotlib and numpy.
357
+ - The function uses `matplotlib.animation.FuncAnimation` for animation.
358
+ - If `filename` is provided, the animation is saved and not displayed interactively.
359
+
360
+ Docstring generated by GitHub Copilot.
361
+ """
160
362
 
161
363
  if surface is None:
162
364
  if ax is None:
@@ -195,6 +397,31 @@ def animate_surface(eta, x, y, t, filename=None, fps=None,
195
397
  plt.show()
196
398
 
197
399
  def xy_to_latlon(latlon0, coors, rot=0):
400
+ """
401
+ Convert local Cartesian (x, y) coordinates to latitude and longitude using geodesic calculations.
402
+
403
+ Parameters
404
+ ----------
405
+ latlon0 : array-like, shape (2,)
406
+ The reference latitude and longitude (in degrees) as a 2-element array or list [lat, lon].
407
+ coors : array-like, shape (N, 2)
408
+ Array of local Cartesian coordinates (x, y) to be converted, where each row is a point.
409
+ rot : float, optional
410
+ Rotation angle in degrees to be subtracted from the computed azimuth, default is 0.
411
+
412
+ Returns
413
+ -------
414
+ latlon : ndarray, shape (N, 2)
415
+ Array of latitude and longitude pairs (in degrees) corresponding to the input coordinates.
416
+
417
+ Notes
418
+ -----
419
+ Uses Cartopy's geodesic calculations to convert local (x, y) displacements from a reference point
420
+ (latlon0) to geographic coordinates, accounting for Earth's curvature.
421
+
422
+ Docstring generated by GitHub Copilot.
423
+ """
424
+
198
425
  import cartopy.crs as ccrs, cartopy.geodesic as cgds
199
426
  dist = np.linalg.norm(coors, axis=1)
200
427
  azi = np.arctan2(coors[:,0], coors[:,1])*180/np.pi - rot # atan2(x,y) to get azimuth (relative to N-vector)
@@ -208,6 +435,56 @@ def plot_surface_in_map(eta, x, y, eta_geo0, extent,
208
435
  wms_url='https://openwms.statkart.no/skwms1/wms.terrengmodell?request=GetCapabilities&service=WMS',
209
436
  wms_layers=['relieff'], ax=None,
210
437
  cm='Blues_r', colorbar=True, figsize=None, eta_rot=0, labels=False):
438
+ """
439
+ Plot a 2D surface (e.g., elevation or other field) on a map with optional scatter points and WMS background.
440
+
441
+ Parameters
442
+ ----------
443
+ eta : ndarray or None
444
+ 2D array representing the surface to plot (e.g., elevation values). If None, only scatter and WMS are shown.
445
+ x : ndarray
446
+ 1D or 2D array of x-coordinates corresponding to `eta`.
447
+ y : ndarray
448
+ 1D or 2D array of y-coordinates corresponding to `eta`.
449
+ eta_geo0 : array-like
450
+ Reference geographic coordinates (e.g., origin for coordinate transformation).
451
+ extent : array-like
452
+ Map extent in the format [xmin, xmax, ymin, ymax] (in longitude and latitude).
453
+ eta_scatter : ndarray or None, optional
454
+ Array of points to scatter on the map, shape (N, 2). Default is None.
455
+ wms_url : str, optional
456
+ URL to the WMS service for background map. Default is Statkart's terrain model.
457
+ wms_layers : list of str, optional
458
+ List of WMS layer names to display. Default is ['relieff'].
459
+ ax : matplotlib.axes.Axes or None, optional
460
+ Existing axes to plot on. If None, a new axes with Mercator projection is created.
461
+ cm : str or Colormap, optional
462
+ Colormap for the surface plot. Default is 'Blues_r'.
463
+ colorbar : bool, optional
464
+ If True, display a colorbar for the surface. Default is True.
465
+ figsize : tuple or None, optional
466
+ Figure size. Not used if `ax` is provided. Default is None.
467
+ eta_rot : float, optional
468
+ Rotation angle (degrees) to apply to `eta` and scatter points. Default is 0.
469
+ labels : bool, optional
470
+ If True, draw gridlines with labels. Default is False.
471
+
472
+ Returns
473
+ -------
474
+ ax : matplotlib.axes.Axes
475
+ The axes with the plotted map.
476
+ scatter : matplotlib.collections.PathCollection or None
477
+ The scatter plot object, or None if `eta_scatter` is None.
478
+ surface : matplotlib.image.AxesImage or None
479
+ The surface plot object, or None if `eta` is None.
480
+
481
+ Notes
482
+ -----
483
+ - Requires cartopy and matplotlib.
484
+ - Assumes existence of `xy_to_latlon` and `rotate` helper functions.
485
+
486
+ Docstring generated by GitHub Copilot.
487
+ """
211
488
 
212
489
  import cartopy.crs as ccrs, cartopy.geodesic as cgds
213
490
 
@@ -270,6 +547,42 @@ def plot_surface_in_map(eta, x, y, eta_geo0, extent,
270
547
  def plot_surface(eta, x, y, ax=None,
271
548
  cm='Blues_r', colorbar=True,
272
549
  labels=True, figsize=None, interpolation='none'):
550
+ """
551
+ Plot a 2D surface using imshow.
552
+
553
+ Parameters
554
+ ----------
555
+ eta : ndarray
556
+ 2D array representing the surface to plot (e.g., elevation values).
557
+ x : ndarray
558
+ 1D or 2D array of x-coordinates corresponding to `eta`.
559
+ y : ndarray
560
+ 1D or 2D array of y-coordinates corresponding to `eta`.
561
+ ax : matplotlib.axes.Axes or None, optional
562
+ Existing axes to plot on. If None, a new axes is created.
563
+ cm : str or Colormap, optional
564
+ Colormap for the surface plot. Default is 'Blues_r'.
565
+ colorbar : bool, optional
566
+ If True, display a colorbar for the surface. Default is True.
567
+ labels : bool, optional
568
+ If True, draw gridlines with labels. Default is True.
569
+ figsize : tuple or None, optional
570
+ Figure size. Not used if `ax` is provided. Default is None.
571
+ interpolation : str, optional
572
+ Interpolation method for the surface plot. Default is 'none'.
573
+
574
+ Returns
575
+ -------
576
+ surface : matplotlib.image.AxesImage
577
+ The surface plot object.
578
+ ax : matplotlib.axes.Axes
579
+ The axes with the plotted surface.
580
+
581
+ Notes
582
+ -----
583
+ Docstring generated by GitHub Copilot.
584
+
585
+ """
273
586
 
274
587
  if ax is None:
275
588
  fig, ax = plt.subplots(figsize=figsize)
@@ -295,7 +608,6 @@ def plot_surface(eta, x, y, ax=None,
295
608
 
296
609
 
297
610
  def set_axes_equal(ax: plt.Axes):
298
- import matplotlib.pyplot as plt
299
611
  """Set 3D plot axes to equal scale.
300
612
 
301
613
  Make axes of 3D plot have equal scale so that spheres appear as
@@ -375,103 +687,38 @@ def plot_transformation_mats(x,y,z,T,figno=None, ax=None, scaling='auto'):
375
687
  equal_3d(ax)
376
688
  return ax,h
377
689
 
378
-
379
- def plot_elements(element_matrix, node_matrix, chosen_nodes_ix=[], disp=None, node_labels=False, element_labels=False, plot_nodes=True, plot_elements=True, ax=None, fig=None, element_settings={}, node_settings={}, node_label_settings={}, chosen_node_settings={}, disp_settings={}, element_label_settings={}, three_d=True):
380
- e_dict = {'color': 'LimeGreen', 'alpha': 1}
381
- e_dict.update(**element_settings)
382
-
383
- n_dict = {'color':'Black', 'linestyle':'', 'marker':'.', 'markersize':4, 'alpha':0.8}
384
- n_dict.update(**node_settings)
385
-
386
- n_chosen_dict = {'color':'GreenYellow', 'linestyle':'', 'marker':'o', 'markersize':8, 'alpha':1, 'markeredgecolor':'dimgray'}
387
- n_chosen_dict.update(**chosen_node_settings)
388
-
389
- disp_dict = {'color':'IndianRed', 'alpha':1}
390
- disp_dict.update(**disp_settings)
391
-
392
- l_nodes_dict = {'color':'Black', 'fontsize': 8, 'fontweight':'normal'}
393
- l_nodes_dict.update(**node_label_settings)
394
-
395
- l_elements_dict = {'color':'LimeGreen', 'fontsize': 8, 'fontweight':'bold', 'style':'italic'}
396
- l_elements_dict.update(**element_label_settings)
397
-
398
- if ax is None and fig is None:
399
- fig = plt.figure()
400
-
401
- if ax == None and three_d:
402
- ax = fig.gca(projection='3d')
403
- elif ax == None:
404
- ax = fig.gca()
405
- elif three_d:
406
- 1
407
- # ax.set(projection='3d') #mangler funksjonalitet her...
408
-
409
- element_handles = [None]*len(element_matrix[:,0])
410
-
411
- if plot_elements:
412
- for element_ix, __ in enumerate(element_matrix[:,0]):
413
- node1 = element_matrix[element_ix, 1]
414
- node2 = element_matrix[element_ix, 2]
415
- nodeix1 = np.where(node_matrix[:,0]==node1)[0]
416
- nodeix2 = np.where(node_matrix[:,0]==node2)[0]
417
- x01 = node_matrix[nodeix1,1:4]
418
- x02 = node_matrix[nodeix2,1:4]
419
- x0 = np.vstack([x01,x02])
420
-
421
- if three_d:
422
- element_handles[element_ix] = ax.plot(xs=x0[:,0], ys=x0[:,1], zs=x0[:,2], **e_dict)
423
- else:
424
- element_handles[element_ix] = ax.plot(x0[:,0], x0[:,1], **e_dict)
425
-
426
- if element_labels:
427
- xmean = np.mean(x0, axis=0)
428
- if three_d:
429
- ax.text(xmean[0],xmean[1],xmean[2],'%i' % element_matrix[element_ix,0], **l_elements_dict)
430
- else:
431
- ax.text(xmean[0],xmean[1],s='%i' % element_matrix[element_ix,0], **l_elements_dict)
432
-
433
- if disp is not None:
434
- disp_node1 = disp[nodeix1[0]*6:(nodeix1[0]*6+6)]
435
- disp_node2 = disp[nodeix2[0]*6:(nodeix2[0]*6+6)]
436
- x1 = x01+disp_node1[0:3]
437
- x2 = x02+disp_node2[0:3]
438
- x = np.vstack([x1,x2])
439
-
440
- if three_d:
441
- ax.plot(xs=x[:,0], ys=x[:,1], zs=x[:,2], **disp_dict)
442
- else:
443
- ax.plot(x[:,0], x[:,1], **disp_dict)
444
-
445
- if plot_nodes:
446
- if three_d:
447
- ax.plot(xs=node_matrix[:, 1], ys=node_matrix[:, 2], zs=node_matrix[:, 3], **n_dict)
448
- else:
449
- ax.plot(node_matrix[:, 1], node_matrix[:, 2], **n_dict)
450
-
451
- if chosen_nodes_ix != []:
452
- if three_d:
453
- ax.plot(xs=node_matrix[chosen_nodes_ix, 1], ys=node_matrix[chosen_nodes_ix, 2], zs=node_matrix[chosen_nodes_ix, 3], **n_chosen_dict)
454
- else:
455
- ax.plot(node_matrix[chosen_nodes_ix, 1], node_matrix[chosen_nodes_ix, 2], **n_chosen_dict)
456
-
457
- if node_labels:
458
- if three_d:
459
- for node_ix in range(0, np.shape(node_matrix)[0]):
460
- ax.text(node_matrix[node_ix, 1], node_matrix[node_ix, 2], node_matrix[node_ix, 3], '%i' % node_matrix[node_ix, 0], **l_nodes_dict)
461
- else:
462
- for node_ix in range(0, np.shape(node_matrix)[0]):
463
- ax.text(node_matrix[node_ix, 1], node_matrix[node_ix, 2], '%i' % node_matrix[node_ix, 0], **l_nodes_dict)
690
+ def plot_2d(S2d, x1, x2, ax=None, levels=80, discrete=False, **kwargs):
691
+ """
692
+ Plot a 2D array as either a filled contour plot or a pseudocolor mesh.
693
+
694
+ Parameters
695
+ ----------
696
+ S2d : array_like
697
+ 2D array of values to plot.
698
+ x1 : array_like
699
+ 1D array representing the x-coordinates.
700
+ x2 : array_like
701
+ 1D array representing the y-coordinates.
702
+ ax : matplotlib.axes.Axes, optional
703
+ The axes on which to plot. If None, uses the current axes.
704
+ levels : int, optional
705
+ Number of contour levels to use for filled contour plot. Default is 80.
706
+ discrete : bool, optional
707
+ If True, use `pcolormesh` for a discrete colormap. If False, use `contourf` for a filled contour plot.
708
+ **kwargs
709
+ Additional keyword arguments passed to the plotting function (`contourf` or `pcolormesh`).
710
+
711
+ Returns
712
+ -------
713
+ contour : QuadMesh or QuadContourSet
714
+ The resulting plot object from `pcolormesh` or `contourf`.
715
+
716
+ Notes
717
+ -----
718
+ Docstring generated by GitHub Copilot.
719
+ """
464
720
 
465
- if three_d:
466
- equal_3d(ax)
467
- else:
468
- ax.set_aspect('equal', adjustable='box')
469
-
470
- ax.grid('off')
471
- return ax, element_handles
472
-
473
721
 
474
- def plot_2d(S2d, x1, x2, ax=None, levels=80, discrete=False, **kwargs):
475
722
  if ax is None:
476
723
  ax = plt.gca()
477
724
 
@@ -484,6 +731,39 @@ def plot_2d(S2d, x1, x2, ax=None, levels=80, discrete=False, **kwargs):
484
731
 
485
732
 
486
733
  def plot_S2d(S, omega, theta, D=None, omega_range=None, theta_range=None):
734
+ """
735
+ Plot a 2D spectral density (S2d) as a contour plot, with optional marginal plots (S and D).
736
+
737
+ Parameters
738
+ ----------
739
+ S : array_like
740
+ 1D array of spectral density values as a function of omega.
741
+ omega : array_like
742
+ 1D array of frequency values (rad/s).
743
+ theta : array_like
744
+ 1D array of direction values (rad).
745
+ D : array_like, optional
746
+ 1D array of directional spreading function values as a function of theta.
747
+ If provided, marginal plots of S(omega) and D(theta) are shown.
748
+ omega_range : list or tuple, optional
749
+ Range [min, max] for the omega axis. If None, uses [0, max(omega)].
750
+ theta_range : list or tuple, optional
751
+ Range [min, max] for the theta axis. If None, uses [min(theta), max(theta)].
752
+
753
+ Returns
754
+ -------
755
+ fig : matplotlib.figure.Figure
756
+ The matplotlib Figure object containing the plot.
757
+
758
+ Notes
759
+ -----
760
+ - If `D` is provided, the function plots the 2D spectral density as a contour plot,
761
+ with marginal line plots for S(omega) and D(theta).
762
+ - If `D` is not provided, only the contour plot is shown.
763
+ - The function handles NaN values in the spectral density by setting them to zero.
764
+
765
+ Docstring generated by GitHub Copilot.
766
+ """
487
767
 
488
768
  if theta_range is None:
489
769
  theta_range = [np.min(theta), np.max(theta)]
wawi/prob.py CHANGED
@@ -1,6 +1,34 @@
1
1
  import numpy as np
2
2
 
3
3
  def gumbel_log(umax):
4
+ """
5
+ Compute the Gumbel reduced variate for a given array of maxima.
6
+
7
+ Parameters
8
+ ----------
9
+ umax : array_like
10
+ Array of maxima values.
11
+
12
+ Returns
13
+ -------
14
+ umax_ordered : ndarray
15
+ The input maxima sorted in descending order.
16
+ loglogF : ndarray
17
+ The Gumbel reduced variate corresponding to each sorted maxima.
18
+
19
+ Examples
20
+ --------
21
+ >>> import numpy as np
22
+ >>> umax = np.array([2.3, 3.1, 1.8, 2.9])
23
+ >>> umax_ordered, loglogF = gumbel_log(umax)
24
+
25
+ Notes
26
+ -------
27
+ This function sorts the input array of maxima in descending order and computes the
28
+ Gumbel reduced variate (log-log of the empirical cumulative distribution function)
29
+ for each value.
30
+ """
31
+
4
32
  umax_ordered = np.sort(umax)[::-1]
5
33
  N_stat = len(umax)
6
34
  F = 1-np.arange(1, N_stat+1)/(N_stat+1)