roms-tools 2.4.0__py3-none-any.whl → 2.6.0__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.
Files changed (214) hide show
  1. ci/environment-with-xesmf.yml +16 -0
  2. roms_tools/__init__.py +1 -1
  3. roms_tools/analysis/roms_output.py +339 -234
  4. roms_tools/analysis/utils.py +137 -0
  5. roms_tools/plot.py +353 -214
  6. roms_tools/regrid.py +154 -9
  7. roms_tools/setup/boundary_forcing.py +51 -37
  8. roms_tools/setup/datasets.py +129 -74
  9. roms_tools/setup/grid.py +32 -33
  10. roms_tools/setup/initial_conditions.py +30 -37
  11. roms_tools/setup/nesting.py +238 -64
  12. roms_tools/setup/river_forcing.py +256 -86
  13. roms_tools/setup/surface_forcing.py +40 -28
  14. roms_tools/setup/tides.py +10 -13
  15. roms_tools/setup/topography.py +27 -4
  16. roms_tools/setup/utils.py +28 -12
  17. roms_tools/tests/test_analysis/test_roms_output.py +299 -80
  18. roms_tools/tests/test_regrid.py +85 -2
  19. roms_tools/tests/test_setup/test_boundary_forcing.py +63 -0
  20. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zattrs +3 -1
  21. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zmetadata +3 -1
  22. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/0.0.0 +0 -0
  23. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_south/0.0.0 +0 -0
  24. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/0.0.0 +0 -0
  25. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/0.0.0 +0 -0
  26. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_south/0.0.0 +0 -0
  27. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/0.0.0 +0 -0
  28. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/0.0.0 +0 -0
  29. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_south/0.0.0 +0 -0
  30. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/0.0.0 +0 -0
  31. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/0.0.0 +0 -0
  32. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_south/0.0.0 +0 -0
  33. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/0.0.0 +0 -0
  34. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/0.0.0 +0 -0
  35. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_south/0.0.0 +0 -0
  36. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/0.0.0 +0 -0
  37. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/0.0.0 +0 -0
  38. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_south/0.0.0 +0 -0
  39. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/0.0.0 +0 -0
  40. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/0.0.0 +0 -0
  41. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_south/0.0.0 +0 -0
  42. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/0.0.0 +0 -0
  43. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/0.0.0 +0 -0
  44. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_south/0.0.0 +0 -0
  45. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/0.0.0 +0 -0
  46. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/0.0.0 +0 -0
  47. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_south/0.0.0 +0 -0
  48. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/0.0.0 +0 -0
  49. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/0.0.0 +0 -0
  50. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_south/0.0.0 +0 -0
  51. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/0.0.0 +0 -0
  52. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/0.0.0 +0 -0
  53. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_south/0.0.0 +0 -0
  54. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/0.0.0 +0 -0
  55. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/0.0.0 +0 -0
  56. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_south/0.0.0 +0 -0
  57. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/0.0.0 +0 -0
  58. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/0.0.0 +0 -0
  59. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_north/0.0.0 +0 -0
  60. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_south/0.0.0 +0 -0
  61. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/0.0.0 +0 -0
  62. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/0.0.0 +0 -0
  63. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_south/0.0.0 +0 -0
  64. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/0.0.0 +0 -0
  65. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/0.0.0 +0 -0
  66. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_south/0.0.0 +0 -0
  67. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/0.0.0 +0 -0
  68. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/0.0.0 +0 -0
  69. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_south/0.0.0 +0 -0
  70. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/0.0.0 +0 -0
  71. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/0.0.0 +0 -0
  72. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_south/0.0.0 +0 -0
  73. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/0.0.0 +0 -0
  74. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/0.0.0 +0 -0
  75. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_north/0.0.0 +0 -0
  76. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_south/0.0.0 +0 -0
  77. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/0.0.0 +0 -0
  78. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/0.0.0 +0 -0
  79. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_north/0.0.0 +0 -0
  80. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_south/0.0.0 +0 -0
  81. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/0.0.0 +0 -0
  82. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/0.0.0 +0 -0
  83. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_north/0.0.0 +0 -0
  84. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_south/0.0.0 +0 -0
  85. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/0.0.0 +0 -0
  86. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/0.0.0 +0 -0
  87. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_north/0.0.0 +0 -0
  88. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_south/0.0.0 +0 -0
  89. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/0.0.0 +0 -0
  90. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/0.0.0 +0 -0
  91. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_north/0.0.0 +0 -0
  92. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_south/0.0.0 +0 -0
  93. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/0.0.0 +0 -0
  94. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/0.0.0 +0 -0
  95. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_north/0.0.0 +0 -0
  96. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_south/0.0.0 +0 -0
  97. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/0.0.0 +0 -0
  98. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/0.0.0 +0 -0
  99. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_north/0.0.0 +0 -0
  100. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_south/0.0.0 +0 -0
  101. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/0.0.0 +0 -0
  102. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/0.0.0 +0 -0
  103. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_north/0.0.0 +0 -0
  104. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_south/0.0.0 +0 -0
  105. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/0.0.0 +0 -0
  106. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/0.0.0 +0 -0
  107. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_north/0.0.0 +0 -0
  108. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_south/0.0.0 +0 -0
  109. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/0.0.0 +0 -0
  110. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/0.0.0 +0 -0
  111. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_north/0.0.0 +0 -0
  112. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_south/0.0.0 +0 -0
  113. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/0.0.0 +0 -0
  114. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/0.0.0 +0 -0
  115. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_north/0.0.0 +0 -0
  116. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_south/0.0.0 +0 -0
  117. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/0.0.0 +0 -0
  118. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/0.0.0 +0 -0
  119. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_north/0.0.0 +0 -0
  120. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_south/0.0.0 +0 -0
  121. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/0.0.0 +0 -0
  122. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/0.0.0 +0 -0
  123. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_north/0.0.0 +0 -0
  124. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_south/0.0.0 +0 -0
  125. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/0.0.0 +0 -0
  126. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/0.0.0 +0 -0
  127. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_north/0.0.0 +0 -0
  128. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_south/0.0.0 +0 -0
  129. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/0.0.0 +0 -0
  130. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/0.0.0 +0 -0
  131. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_north/0.0.0 +0 -0
  132. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_south/0.0.0 +0 -0
  133. roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/0.0.0 +0 -0
  134. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zattrs +2 -2
  135. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zmetadata +8 -7
  136. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/abs_time/.zattrs +1 -0
  137. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/dust/0.0.0 +0 -0
  138. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/dust_time/.zattrs +1 -1
  139. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/iron/0.0.0 +0 -0
  140. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/iron_time/.zattrs +1 -1
  141. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nhy/0.0.0 +0 -0
  142. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nhy_time/.zattrs +1 -1
  143. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nox/0.0.0 +0 -0
  144. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nox_time/.zattrs +1 -1
  145. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air/0.0.0 +0 -0
  146. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air_alt/0.0.0 +0 -0
  147. roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_time/.zattrs +1 -1
  148. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zattrs +2 -2
  149. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zmetadata +2 -2
  150. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/dust/0.0.0 +0 -0
  151. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/iron/0.0.0 +0 -0
  152. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nhy/0.0.0 +0 -0
  153. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nox/0.0.0 +0 -0
  154. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air/0.0.0 +0 -0
  155. roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air_alt/0.0.0 +0 -0
  156. roms_tools/tests/test_setup/test_data/grid.zarr/.zattrs +1 -1
  157. roms_tools/tests/test_setup/test_data/grid.zarr/.zmetadata +2 -2
  158. roms_tools/tests/test_setup/test_data/grid.zarr/angle/0.0 +0 -0
  159. roms_tools/tests/test_setup/test_data/grid.zarr/angle_coarse/0.0 +0 -0
  160. roms_tools/tests/test_setup/test_data/grid.zarr/f/0.0 +0 -0
  161. roms_tools/tests/test_setup/test_data/grid.zarr/h/.zattrs +1 -1
  162. roms_tools/tests/test_setup/test_data/grid.zarr/h/0.0 +0 -0
  163. roms_tools/tests/test_setup/test_data/grid.zarr/lat_coarse/0.0 +0 -0
  164. roms_tools/tests/test_setup/test_data/grid.zarr/lat_rho/0.0 +0 -0
  165. roms_tools/tests/test_setup/test_data/grid.zarr/lat_u/0.0 +0 -0
  166. roms_tools/tests/test_setup/test_data/grid.zarr/lat_v/0.0 +0 -0
  167. roms_tools/tests/test_setup/test_data/grid.zarr/pm/0.0 +0 -0
  168. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zattrs +1 -1
  169. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zmetadata +1 -1
  170. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/angle/0.0 +0 -0
  171. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/angle_coarse/0.0 +0 -0
  172. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/f/0.0 +0 -0
  173. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/0.0 +0 -0
  174. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_coarse/0.0 +0 -0
  175. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_rho/0.0 +0 -0
  176. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_u/0.0 +0 -0
  177. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_v/0.0 +0 -0
  178. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_coarse/0.0 +0 -0
  179. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_rho/0.0 +0 -0
  180. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_u/0.0 +0 -0
  181. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_v/0.0 +0 -0
  182. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/pm/0.0 +0 -0
  183. roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/pn/0.0 +0 -0
  184. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zattrs +1 -1
  185. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zmetadata +1 -1
  186. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/salt/0.0.0.0 +0 -0
  187. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/temp/0.0.0.0 +0 -0
  188. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/u/0.0.0.0 +0 -0
  189. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ubar/0.0.0 +0 -0
  190. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/v/0.0.0.0 +0 -0
  191. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/vbar/0.0.0 +0 -0
  192. roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zeta/0.0.0 +0 -0
  193. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zmetadata +27 -1
  194. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/.zarray +20 -0
  195. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/.zattrs +6 -0
  196. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/0 +0 -0
  197. roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/.zattrs +1 -1
  198. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/.zmetadata +27 -1
  199. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/.zarray +20 -0
  200. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/.zattrs +6 -0
  201. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/0 +0 -0
  202. roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/.zattrs +1 -1
  203. roms_tools/tests/test_setup/test_initial_conditions.py +16 -0
  204. roms_tools/tests/test_setup/test_nesting.py +141 -104
  205. roms_tools/tests/test_setup/test_river_forcing.py +580 -266
  206. roms_tools/tests/test_setup/test_surface_forcing.py +47 -0
  207. roms_tools/tests/test_setup/test_validation.py +34 -2
  208. roms_tools/utils.py +11 -7
  209. roms_tools/vertical_coordinate.py +1 -0
  210. {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/METADATA +22 -11
  211. {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/RECORD +214 -206
  212. {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/WHEEL +1 -1
  213. {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info/licenses}/LICENSE +0 -0
  214. {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/top_level.txt +0 -0
roms_tools/plot.py CHANGED
@@ -19,8 +19,8 @@ def _plot(
19
19
 
20
20
  Parameters
21
21
  ----------
22
- field : xarray.DataArray, optional
23
- The field to plot. If None, only the grid is plotted.
22
+ field : xarray.DataArray
23
+ The field to plot.
24
24
  depth_contours : bool, optional
25
25
  If True, adds depth contours to the plot.
26
26
  c : str, optional
@@ -33,9 +33,15 @@ def _plot(
33
33
  kwargs : dict, optional
34
34
  Additional keyword arguments to pass to `pcolormesh` (e.g., colormap or color limits).
35
35
 
36
- Notes
37
- -----
38
- The function raises a `NotImplementedError` if the domain contains the North or South Pole.
36
+ Returns
37
+ -------
38
+ matplotlib.figure.Figure
39
+ The generated figure with the plotted data.
40
+
41
+ Raises
42
+ ------
43
+ NotImplementedError
44
+ If the domain contains the North or South Pole.
39
45
  """
40
46
 
41
47
  field = field.squeeze()
@@ -84,6 +90,348 @@ def _plot(
84
90
 
85
91
  ax.set_title(title)
86
92
 
93
+ return fig
94
+
95
+
96
+ def _plot_nesting(parent_grid_ds, child_grid_ds, parent_straddle, with_dim_names=False):
97
+ """Plots nested parent and child grids with boundary overlays and grid masking.
98
+
99
+ Parameters
100
+ ----------
101
+ parent_grid_ds : xarray.Dataset
102
+ The parent grid dataset containing `lon_rho`, `lat_rho`, and `mask_rho` variables.
103
+ child_grid_ds : xarray.Dataset
104
+ The child grid dataset containing `lon_rho` and `lat_rho` variables.
105
+ parent_straddle : bool
106
+ Whether the parent grid straddles the 180-degree meridian. If True, longitudes
107
+ greater than 180° are wrapped to the -180° to 180° range.
108
+ with_dim_names : bool, optional
109
+ Whether to include dimension names in the plotted grid boundaries. Defaults to False.
110
+
111
+ Returns
112
+ -------
113
+ matplotlib.figure.Figure
114
+ The generated figure displaying the parent and child grid boundaries, mask,
115
+ and additional map features.
116
+ """
117
+
118
+ parent_lon_deg = parent_grid_ds["lon_rho"]
119
+ parent_lat_deg = parent_grid_ds["lat_rho"]
120
+
121
+ child_lon_deg = child_grid_ds["lon_rho"]
122
+ child_lat_deg = child_grid_ds["lat_rho"]
123
+
124
+ if parent_straddle:
125
+ parent_lon_deg = xr.where(
126
+ parent_lon_deg > 180, parent_lon_deg - 360, parent_lon_deg
127
+ )
128
+ child_lon_deg = xr.where(
129
+ child_lon_deg > 180, child_lon_deg - 360, child_lon_deg
130
+ )
131
+
132
+ trans = _get_projection(parent_lon_deg, parent_lat_deg)
133
+
134
+ parent_lon_deg = parent_lon_deg.values
135
+ parent_lat_deg = parent_lat_deg.values
136
+ child_lon_deg = child_lon_deg.values
137
+ child_lat_deg = child_lat_deg.values
138
+
139
+ fig, ax = plt.subplots(1, 1, figsize=(13, 7), subplot_kw={"projection": trans})
140
+
141
+ _add_boundary_to_ax(
142
+ ax,
143
+ parent_lon_deg,
144
+ parent_lat_deg,
145
+ trans,
146
+ c="r",
147
+ label="parent grid",
148
+ with_dim_names=with_dim_names,
149
+ )
150
+
151
+ _add_boundary_to_ax(
152
+ ax,
153
+ child_lon_deg,
154
+ child_lat_deg,
155
+ trans,
156
+ c="g",
157
+ label="child grid",
158
+ with_dim_names=with_dim_names,
159
+ )
160
+
161
+ vmax = 3
162
+ vmin = 0
163
+ cmap = plt.colormaps.get_cmap("Blues")
164
+ kwargs = {"vmax": vmax, "vmin": vmin, "cmap": cmap}
165
+
166
+ _add_field_to_ax(
167
+ ax,
168
+ parent_lon_deg,
169
+ parent_lat_deg,
170
+ parent_grid_ds.mask_rho,
171
+ add_colorbar=False,
172
+ kwargs=kwargs,
173
+ )
174
+
175
+ ax.coastlines(
176
+ resolution="50m", linewidth=0.5, color="black"
177
+ ) # add map of coastlines
178
+
179
+ # Add gridlines with labels for latitude and longitude
180
+ gridlines = ax.gridlines(
181
+ draw_labels=True, linewidth=0.5, color="gray", alpha=0.7, linestyle="--"
182
+ )
183
+ gridlines.top_labels = False # Hide top labels
184
+ gridlines.right_labels = False # Hide right labels
185
+ gridlines.xlabel_style = {
186
+ "size": 10,
187
+ "color": "black",
188
+ } # Customize longitude label style
189
+ gridlines.ylabel_style = {
190
+ "size": 10,
191
+ "color": "black",
192
+ } # Customize latitude label style
193
+
194
+ ax.legend(loc="best")
195
+
196
+ return fig
197
+
198
+
199
+ def _section_plot(field, interface_depth=None, title="", kwargs={}, ax=None):
200
+ """Plots a vertical section of a field with optional interface depths.
201
+
202
+ Parameters
203
+ ----------
204
+ field : xarray.DataArray
205
+ The field to plot, typically representing a vertical section of ocean data.
206
+ interface_depth : xarray.DataArray, optional
207
+ Interface depth values to overlay on the plot, useful for visualizing vertical layers.
208
+ Defaults to None.
209
+ title : str, optional
210
+ Title of the plot. Defaults to an empty string.
211
+ kwargs : dict, optional
212
+ Additional keyword arguments to pass to `xarray.plot`. Defaults to an empty dictionary.
213
+ ax : matplotlib.axes.Axes, optional
214
+ Pre-existing axes to draw the plot on. If None, a new figure and axes are created.
215
+
216
+ Returns
217
+ -------
218
+ matplotlib.figure.Figure
219
+ The generated figure with the plotted section.
220
+
221
+ Raises
222
+ ------
223
+ ValueError
224
+ If no dimension in `field.dims` starts with any of the recognized horizontal dimension
225
+ prefixes (`eta_rho`, `eta_v`, `xi_rho`, `xi_u`, `lat`, `lon`).
226
+ ValueError
227
+ If no coordinate in `field.coords` starts with either `layer` or `interface`.
228
+
229
+ Notes
230
+ -----
231
+ - NaN values at the horizontal ends are dropped before plotting.
232
+ """
233
+
234
+ if ax is None:
235
+ fig, ax = plt.subplots(1, 1, figsize=(9, 5))
236
+
237
+ dims_to_check = ["eta_rho", "eta_v", "xi_rho", "xi_u", "lat", "lon"]
238
+ try:
239
+ xdim = next(
240
+ dim
241
+ for dim in field.dims
242
+ if any(dim.startswith(prefix) for prefix in dims_to_check)
243
+ )
244
+ except StopIteration:
245
+ raise ValueError(
246
+ "None of the dimensions found in field.dims starts with (eta_rho, eta_v, xi_rho, xi_u, lat, lon)"
247
+ )
248
+
249
+ depths_to_check = [
250
+ "layer",
251
+ "interface",
252
+ ]
253
+ try:
254
+ depth_label = next(
255
+ depth_label
256
+ for depth_label in field.coords
257
+ if any(depth_label.startswith(prefix) for prefix in depths_to_check)
258
+ )
259
+ except StopIteration:
260
+ raise ValueError(
261
+ "None of the coordinates found in field.coords starts with (layer_depth, interface_depth)"
262
+ )
263
+
264
+ # Handle NaNs on either horizontal end
265
+ field = field.where(~field[depth_label].isnull(), drop=True)
266
+
267
+ more_kwargs = {"x": xdim, "y": depth_label, "yincrease": False}
268
+
269
+ field.plot(**kwargs, **more_kwargs, ax=ax)
270
+
271
+ if interface_depth is not None:
272
+ layer_key = "s_rho" if "s_rho" in interface_depth.dims else "s_w"
273
+
274
+ for i in range(len(interface_depth[layer_key])):
275
+ ax.plot(
276
+ interface_depth[xdim], interface_depth.isel({layer_key: i}), color="k"
277
+ )
278
+
279
+ ax.set_title(title)
280
+ ax.set_ylabel("Depth [m]")
281
+
282
+ if xdim == "lon":
283
+ xlabel = "Longitude [°E]"
284
+ elif xdim == "lat":
285
+ xlabel = "Latitude [°N]"
286
+ else:
287
+ xlabel = xdim
288
+ ax.set_xlabel(xlabel)
289
+
290
+ return fig
291
+
292
+
293
+ def _profile_plot(field, title="", ax=None):
294
+ """Plots a vertical profile of the given field against depth.
295
+
296
+ This function generates a profile plot by plotting the field values against
297
+ depth. It automatically detects the appropriate depth coordinate and
298
+ reverses the y-axis to follow the convention of increasing depth downward.
299
+
300
+ Parameters
301
+ ----------
302
+ field : xarray.DataArray
303
+ The field to plot, typically representing vertical profile data.
304
+ title : str, optional
305
+ Title of the plot. Defaults to an empty string.
306
+ ax : matplotlib.axes.Axes, optional
307
+ Pre-existing axes to draw the plot on. If None, a new figure and axes are created.
308
+
309
+ Returns
310
+ -------
311
+ matplotlib.figure.Figure
312
+ The generated figure with the plotted profile.
313
+
314
+ Raises
315
+ ------
316
+ ValueError
317
+ If no coordinate in `field.coords` starts with either `layer_depth` or `interface_depth`.
318
+
319
+ Notes
320
+ -----
321
+ - The y-axis is inverted to ensure that depth increases downward.
322
+ """
323
+
324
+ depths_to_check = [
325
+ "layer_depth",
326
+ "interface_depth",
327
+ ]
328
+ try:
329
+ depth_label = next(
330
+ depth_label
331
+ for depth_label in field.coords
332
+ if any(depth_label.startswith(prefix) for prefix in depths_to_check)
333
+ )
334
+ except StopIteration:
335
+ raise ValueError(
336
+ "None of the coordinates found in field.coords starts with (layer_depth, interface_depth)"
337
+ )
338
+
339
+ if ax is None:
340
+ fig, ax = plt.subplots(1, 1, figsize=(4, 7))
341
+ kwargs = {"y": depth_label, "yincrease": False}
342
+ field.plot(**kwargs, linewidth=2)
343
+ ax.set_title(title)
344
+ ax.set_ylabel("Depth [m]")
345
+ ax.grid()
346
+
347
+ return fig
348
+
349
+
350
+ def _line_plot(field, title="", ax=None):
351
+ """Plots a line graph of the given field with grey vertical bars indicating NaN
352
+ regions.
353
+
354
+ Parameters
355
+ ----------
356
+ field : xarray.DataArray
357
+ The field to plot, typically a 1D or 2D field with one spatial dimension.
358
+ title : str, optional
359
+ Title of the plot. Defaults to an empty string.
360
+ ax : matplotlib.axes.Axes, optional
361
+ Pre-existing axes to draw the plot on. If None, a new figure and axes are created.
362
+
363
+ Returns
364
+ -------
365
+ matplotlib.figure.Figure
366
+ The generated figure with the plotted data and highlighted NaN regions.
367
+
368
+ Raises
369
+ ------
370
+ ValueError
371
+ If none of the dimensions in `field.dims` starts with one of the expected
372
+ prefixes: `eta_rho`, `eta_v`, `xi_rho`, `xi_u`, `lat`, or `lon`.
373
+
374
+ Notes
375
+ -----
376
+ - NaN regions are identified and marked using `axvspan` with a grey shade.
377
+ """
378
+
379
+ if ax is None:
380
+ fig, ax = plt.subplots(1, 1, figsize=(7, 4))
381
+
382
+ field.plot(ax=ax, linewidth=2)
383
+
384
+ # Loop through the NaNs in the field and add grey vertical bars
385
+ dims_to_check = ["eta_rho", "eta_v", "xi_rho", "xi_u", "lat", "lon"]
386
+ try:
387
+ xdim = next(
388
+ dim
389
+ for dim in field.dims
390
+ if any(dim.startswith(prefix) for prefix in dims_to_check)
391
+ )
392
+ except StopIteration:
393
+ raise ValueError(
394
+ "None of the dimensions found in field.dims starts with (eta_rho, eta_v, xi_rho, xi_u, lat, lon)"
395
+ )
396
+
397
+ nan_mask = np.isnan(field.values)
398
+ nan_indices = np.where(nan_mask)[0]
399
+
400
+ if len(nan_indices) > 0:
401
+ # Add grey vertical bars for each NaN region
402
+ start_idx = nan_indices[0]
403
+ for idx in range(1, len(nan_indices)):
404
+ if nan_indices[idx] != nan_indices[idx - 1] + 1:
405
+ ax.axvspan(
406
+ field[xdim][start_idx],
407
+ field[xdim][nan_indices[idx - 1] + 1],
408
+ color="gray",
409
+ alpha=0.3,
410
+ )
411
+ start_idx = nan_indices[idx]
412
+ # Add the last region of NaNs, making sure we don't go out of bounds
413
+ ax.axvspan(
414
+ field[xdim][start_idx],
415
+ field[xdim][nan_indices[-1]],
416
+ color="gray",
417
+ alpha=0.3,
418
+ )
419
+
420
+ # Set plot title and grid
421
+ ax.set_title(title)
422
+ ax.grid()
423
+ ax.set_xlim([field[xdim][0], field[xdim][-1]])
424
+
425
+ if xdim == "lon":
426
+ xlabel = "Longitude [°E]"
427
+ elif xdim == "lat":
428
+ xlabel = "Latitude [°N]"
429
+ else:
430
+ xlabel = xdim
431
+ ax.set_xlabel(xlabel)
432
+
433
+ return fig
434
+
87
435
 
88
436
  def _add_boundary_to_ax(
89
437
  ax, lon_deg, lat_deg, trans, c="red", label="", with_dim_names=False
@@ -238,212 +586,3 @@ def _get_projection(lon, lat):
238
586
  return ccrs.NearsidePerspective(
239
587
  central_longitude=lon.mean().values, central_latitude=lat.mean().values
240
588
  )
241
-
242
-
243
- def _section_plot(field, interface_depth=None, title="", kwargs={}, ax=None):
244
-
245
- if ax is None:
246
- fig, ax = plt.subplots(1, 1, figsize=(9, 5))
247
-
248
- dims_to_check = ["eta_rho", "eta_u", "eta_v", "xi_rho", "xi_u", "xi_v"]
249
- try:
250
- xdim = next(
251
- dim
252
- for dim in field.dims
253
- if any(dim.startswith(prefix) for prefix in dims_to_check)
254
- )
255
- except StopIteration:
256
- raise ValueError(
257
- "None of the dimensions found in field.dims starts with (eta_rho, eta_u, eta_v, xi_rho, xi_u, xi_v)"
258
- )
259
-
260
- depths_to_check = [
261
- "layer_depth",
262
- "interface_depth",
263
- ]
264
- try:
265
- depth_label = next(
266
- depth_label
267
- for depth_label in field.coords
268
- if any(depth_label.startswith(prefix) for prefix in depths_to_check)
269
- )
270
- except StopIteration:
271
- raise ValueError(
272
- "None of the coordinates found in field.coords starts with (layer_depth_rho, layer_depth_u, layer_depth_v, interface_depth_rho, interface_depth_u, interface_depth_v)"
273
- )
274
-
275
- more_kwargs = {"x": xdim, "y": depth_label, "yincrease": False}
276
- field.plot(**kwargs, **more_kwargs, ax=ax)
277
-
278
- if interface_depth is not None:
279
- layer_key = "s_rho" if "s_rho" in interface_depth.dims else "s_w"
280
-
281
- for i in range(len(interface_depth[layer_key])):
282
- ax.plot(
283
- interface_depth[xdim], interface_depth.isel({layer_key: i}), color="k"
284
- )
285
-
286
- ax.set_title(title)
287
-
288
-
289
- def _profile_plot(field, title="", ax=None):
290
- """Plots a profile of the given field against depth.
291
-
292
- Parameters
293
- ----------
294
- field : xarray.DataArray
295
- Data to plot.
296
- title : str, optional
297
- Title of the plot.
298
- ax : matplotlib.axes.Axes, optional
299
- Axes to plot on. If None, a new figure is created.
300
-
301
- Raises
302
- ------
303
- ValueError
304
- If no expected depth coordinate is found in the field.
305
- """
306
-
307
- depths_to_check = [
308
- "layer_depth",
309
- "interface_depth",
310
- ]
311
- try:
312
- depth_label = next(
313
- depth_label
314
- for depth_label in field.coords
315
- if any(depth_label.startswith(prefix) for prefix in depths_to_check)
316
- )
317
- except StopIteration:
318
- raise ValueError(
319
- "None of the expected coordinates (layer_depth_rho, layer_depth_u, layer_depth_v, interface_depth_rho, interface_depth_u, interface_depth_v) found in field.coords"
320
- )
321
-
322
- if ax is None:
323
- fig, ax = plt.subplots(1, 1, figsize=(4, 7))
324
- kwargs = {"y": depth_label, "yincrease": False}
325
- field.plot(**kwargs)
326
- ax.set_title(title)
327
- ax.grid()
328
-
329
-
330
- def _line_plot(field, title="", ax=None):
331
- """Plots a line graph of the given field, with grey vertical bars where NaNs are
332
- located.
333
-
334
- Parameters
335
- ----------
336
- field : xarray.DataArray
337
- Data to plot.
338
- title : str, optional
339
- Title of the plot.
340
- ax : matplotlib.axes.Axes, optional
341
- Axes to plot on. If None, a new figure is created.
342
-
343
- Returns
344
- -------
345
- None
346
- Modifies the plot in-place.
347
- """
348
- if ax is None:
349
- fig, ax = plt.subplots(1, 1, figsize=(7, 4))
350
- field.plot(ax=ax)
351
-
352
- # Loop through the NaNs in the field and add grey vertical bars
353
- nan_mask = np.isnan(field.values)
354
- nan_indices = np.where(nan_mask)[0]
355
-
356
- if len(nan_indices) > 0:
357
- # Add grey vertical bars for each NaN region
358
- start_idx = nan_indices[0]
359
- for idx in range(1, len(nan_indices)):
360
- if nan_indices[idx] != nan_indices[idx - 1] + 1:
361
- ax.axvspan(start_idx, nan_indices[idx - 1] + 1, color="gray", alpha=0.3)
362
- start_idx = nan_indices[idx]
363
- # Add the last region of NaNs
364
- ax.axvspan(start_idx, nan_indices[-1] + 1, color="gray", alpha=0.3)
365
-
366
- # Set plot title and grid
367
- ax.set_title(title)
368
- ax.grid()
369
-
370
-
371
- def _plot_nesting(parent_grid_ds, child_grid_ds, parent_straddle, with_dim_names=False):
372
-
373
- parent_lon_deg = parent_grid_ds["lon_rho"]
374
- parent_lat_deg = parent_grid_ds["lat_rho"]
375
-
376
- child_lon_deg = child_grid_ds["lon_rho"]
377
- child_lat_deg = child_grid_ds["lat_rho"]
378
-
379
- if parent_straddle:
380
- parent_lon_deg = xr.where(
381
- parent_lon_deg > 180, parent_lon_deg - 360, parent_lon_deg
382
- )
383
- child_lon_deg = xr.where(
384
- child_lon_deg > 180, child_lon_deg - 360, child_lon_deg
385
- )
386
-
387
- trans = _get_projection(parent_lon_deg, parent_lat_deg)
388
-
389
- parent_lon_deg = parent_lon_deg.values
390
- parent_lat_deg = parent_lat_deg.values
391
- child_lon_deg = child_lon_deg.values
392
- child_lat_deg = child_lat_deg.values
393
-
394
- fig, ax = plt.subplots(1, 1, figsize=(13, 7), subplot_kw={"projection": trans})
395
-
396
- _add_boundary_to_ax(
397
- ax,
398
- parent_lon_deg,
399
- parent_lat_deg,
400
- trans,
401
- c="r",
402
- label="parent grid",
403
- with_dim_names=with_dim_names,
404
- )
405
-
406
- _add_boundary_to_ax(
407
- ax,
408
- child_lon_deg,
409
- child_lat_deg,
410
- trans,
411
- c="g",
412
- label="child grid",
413
- with_dim_names=with_dim_names,
414
- )
415
-
416
- vmax = 3
417
- vmin = 0
418
- cmap = plt.colormaps.get_cmap("Blues")
419
- kwargs = {"vmax": vmax, "vmin": vmin, "cmap": cmap}
420
-
421
- _add_field_to_ax(
422
- ax,
423
- parent_lon_deg,
424
- parent_lat_deg,
425
- parent_grid_ds.mask_rho,
426
- add_colorbar=False,
427
- kwargs=kwargs,
428
- )
429
-
430
- ax.coastlines(
431
- resolution="50m", linewidth=0.5, color="black"
432
- ) # add map of coastlines
433
-
434
- # Add gridlines with labels for latitude and longitude
435
- gridlines = ax.gridlines(
436
- draw_labels=True, linewidth=0.5, color="gray", alpha=0.7, linestyle="--"
437
- )
438
- gridlines.top_labels = False # Hide top labels
439
- gridlines.right_labels = False # Hide right labels
440
- gridlines.xlabel_style = {
441
- "size": 10,
442
- "color": "black",
443
- } # Customize longitude label style
444
- gridlines.ylabel_style = {
445
- "size": 10,
446
- "color": "black",
447
- } # Customize latitude label style
448
-
449
- ax.legend(loc="best")