sdf-xarray 0.7.4__tar.gz → 0.9.0__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 (71) hide show
  1. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/.github/workflows/build_publish.yml +1 -1
  2. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/.github/workflows/tests.yml +1 -1
  3. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/PKG-INFO +1 -1
  4. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/animation.md +10 -5
  5. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/animating/animate_1D_density.py +2 -2
  6. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/animating/animate_1D_poynting_flux.py +2 -2
  7. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/animating/animate_2D_dist_fn_multispecies.py +1 -1
  8. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/animating/animate_2D_dist_fn_multispecies_alternative.py +1 -1
  9. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/animating/animate_2D_poynting_flux.py +2 -2
  10. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/live_demo.ipynb +2 -2
  11. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/plotting/plot_1D_density.py +1 -1
  12. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/plotting/plot_1D_poynting_flux.py +1 -1
  13. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/plotting/plot_2D_density.py +1 -1
  14. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/plotting/plot_2D_dist_fn_multispecies.py +1 -1
  15. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/plotting/plot_2D_poynting_flux.py +1 -1
  16. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/plotting/plot_time_temperature.py +1 -1
  17. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/plotting/plot_x_px_scatter.py +1 -1
  18. sdf_xarray-0.9.0/docs/epoch_workshop_2026/workshop_details.md +7 -0
  19. sdf_xarray-0.9.0/docs/figures/voxel_plot_high_res.png +0 -0
  20. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/index.md +1 -0
  21. sdf_xarray-0.9.0/docs/plotting.md +95 -0
  22. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/understanding_datasets.md +51 -18
  23. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/unit_conversion.md +4 -4
  24. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/why_sdf_xarray.md +1 -1
  25. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/pyproject.toml +10 -2
  26. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/src/sdf_xarray/_version.py +3 -3
  27. sdf_xarray-0.9.0/src/sdf_xarray/dataarray_accessor.py +226 -0
  28. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/src/sdf_xarray/dataset_accessor.py +30 -18
  29. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/src/sdf_xarray/plotting.py +247 -10
  30. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/tests/test_epoch_dataarray_accessor.py +252 -29
  31. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/tests/test_epoch_dataset_accessor.py +43 -1
  32. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/uv.lock +141 -0
  33. sdf_xarray-0.7.4/docs/epoch_workshop_2026/workshop_details.md +0 -7
  34. sdf_xarray-0.7.4/src/sdf_xarray/dataarray_accessor.py +0 -74
  35. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/.github/workflows/lint.yml +0 -0
  36. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/.gitignore +0 -0
  37. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/.gitmodules +0 -0
  38. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/.readthedocs.yaml +0 -0
  39. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/CITATION.cff +0 -0
  40. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/CMakeLists.txt +0 -0
  41. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/CONTRIBUTING.md +0 -0
  42. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/LICENCE +0 -0
  43. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/README.md +0 -0
  44. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/.gitignore +0 -0
  45. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/_static/BEAM.png +0 -0
  46. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/_static/PlasmaFAIR.svg +0 -0
  47. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/_static/force_render_dark_xarray_objects.css +0 -0
  48. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/_static/sdf-xarray-logo-dark.svg +0 -0
  49. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/_static/sdf-xarray-logo-light.svg +0 -0
  50. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/_templates/custom-class-template.rst +0 -0
  51. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/_templates/custom-module-template.rst +0 -0
  52. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/api.md +0 -0
  53. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/conf.py +0 -0
  54. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/contributing.md +0 -0
  55. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/animations.md +0 -0
  56. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/histograms/plot_hist_ke.py +0 -0
  57. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/histograms/plot_hist_ke_probe.py +0 -0
  58. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/histograms/plot_hist_px.py +0 -0
  59. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/histograms.md +0 -0
  60. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/epoch_workshop_2026/plots.md +0 -0
  61. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/installation.md +0 -0
  62. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/known_issues.md +0 -0
  63. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/loading_data.md +0 -0
  64. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/docs/make.bat +0 -0
  65. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/src/sdf_xarray/__init__.py +0 -0
  66. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/src/sdf_xarray/csdf.pxd +0 -0
  67. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/src/sdf_xarray/download.py +0 -0
  68. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/src/sdf_xarray/sdf_interface.pyx +0 -0
  69. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/tests/test_cython.py +0 -0
  70. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/tests/test_dataset.py +0 -0
  71. {sdf_xarray-0.7.4 → sdf_xarray-0.9.0}/tests/test_datatree.py +0 -0
@@ -20,7 +20,7 @@ jobs:
20
20
  submodules: "recursive"
21
21
 
22
22
  - name: Cache Zenodo datasets
23
- uses: actions/cache@v4
23
+ uses: actions/cache@v6
24
24
  with:
25
25
  enableCrossOsArchive: true
26
26
  path: ~/.cache/sdf_datasets
@@ -31,7 +31,7 @@ jobs:
31
31
  uv sync --python ${{ matrix.python-version }} --frozen
32
32
 
33
33
  - name: Cache Zenodo datasets
34
- uses: actions/cache@v4
34
+ uses: actions/cache@v6
35
35
  with:
36
36
  path: ~/.cache/sdf_datasets
37
37
  key: sdf-datasets-17991042
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sdf-xarray
3
- Version: 0.7.4
3
+ Version: 0.9.0
4
4
  Summary: Provides a backend for xarray to read SDF files as created by the EPOCH plasma PIC code.
5
5
  Author-Email: Peter Hill <peter.hill@york.ac.uk>, Joel Adams <joel.adams@york.ac.uk>, Shaun Doherty <shaun.doherty@york.ac.uk>, Chris Herdman <chris.herdman@york.ac.uk>, Liam Pattinson <liam.pattinson@york.ac.uk>, Sviatoslav Shekhanov <sviatoslav.shekhanov@york.ac.uk>
6
6
  License-Expression: BSD-3-Clause
@@ -35,9 +35,10 @@ resolved data has 2 dimensions.
35
35
 
36
36
  | Dimensions | Plotting function | Notes |
37
37
  | ---------- | ----------------------------- | --------------------- |
38
- | `2` | <inv:#xarray.plot.line> | |
39
- | `3` | <inv:#xarray.plot.pcolormesh> | |
40
- | `>3` | <inv:#xarray.plot.hist> | Not fully implemented |
38
+ | 2 | <inv:#xarray.plot.line> | |
39
+ | 3 | <inv:#xarray.plot.pcolormesh> | |
40
+ | 4 | <inv:#mpl_toolkits.mplot3d.axes3d.Axes3D.voxels>| WIP |
41
+ | >4 | <inv:#xarray.plot.hist> | Not fully implemented |
41
42
 
42
43
 
43
44
  ### 1D simulation
@@ -103,6 +104,10 @@ anim.show()
103
104
 
104
105
  ### 3D simulation
105
106
 
107
+ ```{warning}
108
+ [Voxel](./plotting.md#voxel-plots) animations are not currently implemented.
109
+ ```
110
+
106
111
  Opening a 3D simulation as a multi-file dataset and plotting it will
107
112
  return a <inv:#xarray.plot.hist>. However, this may not be
108
113
  desirable. We can plot a 3D simulation along a certain plane in the
@@ -170,8 +175,8 @@ Some functionality such as `aspect` and `size` are not fully implemented yet.
170
175
  ds = sdfxr.open_mfdataset("tutorial_dataset_2d/*.sdf")
171
176
 
172
177
  # Change the units of the coordinates
173
- ds = ds.epoch.rescale_coords(1e6, "µm", ["X_Grid_mid", "Y_Grid_mid"])
174
- ds = ds.epoch.rescale_coords(1e15, "fs", ["time"])
178
+ ds = ds.epoch.rescale_coords("µm", ["X_Grid_mid", "Y_Grid_mid"])
179
+ ds = ds.epoch.rescale_coords("fs", ["time"])
175
180
  ds["time"].attrs["long_name"] = "t"
176
181
 
177
182
  # Change units and name of the variable
@@ -6,9 +6,9 @@ input_dir = Path("datasets/1_1_drifting_bunch")
6
6
  ds = sdfxr.open_mfdataset(input_dir)
7
7
 
8
8
  # Convert the time to femtoseconds
9
- ds = ds.epoch.rescale_coords(1e15, "fs", "time")
9
+ ds = ds.epoch.rescale_coords("fs", "time", 1e15)
10
10
  # Convert the x and y coords to microns
11
- ds = ds.epoch.rescale_coords(1e6, "µm", ["X_Grid_mid"])
11
+ ds = ds.epoch.rescale_coords("µm", ["X_Grid_mid"], 1e6)
12
12
 
13
13
  anim = ds["Derived_Number_Density"].epoch.animate()
14
14
 
@@ -8,9 +8,9 @@ input_dir = Path("datasets/3_3_Gaussian_1d_laser")
8
8
  ds = sdfxr.open_mfdataset(input_dir)
9
9
 
10
10
  # Convert the time to femtoseconds
11
- ds = ds.epoch.rescale_coords(1e15, "fs", "time")
11
+ ds = ds.epoch.rescale_coords("fs", "time", 1e15)
12
12
  # Convert the x and y coords to microns
13
- ds = ds.epoch.rescale_coords(1e6, "µm", ["X_Grid_mid"])
13
+ ds = ds.epoch.rescale_coords("µm", ["X_Grid_mid"], 1e6)
14
14
 
15
15
  # Calculate Poynting flux magnitude
16
16
  flux_magnitude = np.sqrt(
@@ -8,7 +8,7 @@ ds = sdfxr.open_mfdataset(
8
8
  )
9
9
 
10
10
  # Rescale coords to account for kilometers
11
- ds = ds.epoch.rescale_coords(1e-3, "km", ["X_x_px_Left"])
11
+ ds = ds.epoch.rescale_coords("km", ["X_x_px_Left"], 1e-3)
12
12
 
13
13
  # Sum phase-space of species "Left" and "Right" in "x_px" distribution function
14
14
  # NOTE: We only use the values from the right distribution function as if we inherit
@@ -11,7 +11,7 @@ ds = sdfxr.open_mfdataset(
11
11
  )
12
12
 
13
13
  # Rescale coords to account for kilometers
14
- ds = ds.epoch.rescale_coords(1e-3, "km", ["X_x_px_Left"])
14
+ ds = ds.epoch.rescale_coords("km", ["X_x_px_Left"], 1e-3)
15
15
 
16
16
  # Sum phase-space of species "Left" and "Right" in "x_px" distribution function
17
17
  # NOTE: We only use the values from the right distribution function as if we inherit
@@ -8,9 +8,9 @@ input_dir = Path("datasets/3_5_Gaussian_beam")
8
8
  ds = sdfxr.open_mfdataset(input_dir)
9
9
 
10
10
  # Convert the time to femtoseconds
11
- ds = ds.epoch.rescale_coords(1e15, "fs", "time")
11
+ ds = ds.epoch.rescale_coords("fs", "time", 1e15)
12
12
  # Convert the x and y coords to microns
13
- ds = ds.epoch.rescale_coords(1e6, "µm", ["X_Grid_mid", "Y_Grid_mid"])
13
+ ds = ds.epoch.rescale_coords("µm", ["X_Grid_mid", "Y_Grid_mid"], 1e6)
14
14
 
15
15
  # Calculate Poynting flux magnitude
16
16
  flux_magnitude = np.sqrt(
@@ -3800,7 +3800,7 @@
3800
3800
  },
3801
3801
  {
3802
3802
  "cell_type": "code",
3803
- "execution_count": 10,
3803
+ "execution_count": null,
3804
3804
  "id": "2ef27498",
3805
3805
  "metadata": {
3806
3806
  "colab": {
@@ -3833,7 +3833,7 @@
3833
3833
  }
3834
3834
  ],
3835
3835
  "source": [
3836
- "ds = ds.epoch.rescale_coords(1e6, \"µm\", [\"X_Grid_mid\", \"Y_Grid_mid\"])\n",
3836
+ "ds = ds.epoch.rescale_coords(\"µm\", [\"X_Grid_mid\", \"Y_Grid_mid\"], 1e6)\n",
3837
3837
  "ds[\"Derived_Number_Density_Electron\"].isel(time=0).epoch.plot()"
3838
3838
  ]
3839
3839
  },
@@ -8,7 +8,7 @@ import sdf_xarray as sdfxr
8
8
  input_dir = Path("datasets/1_1_drifting_bunch")
9
9
 
10
10
  ds = sdfxr.open_dataset(input_dir / "0000.sdf")
11
- ds = ds.epoch.rescale_coords(1e6, "µm", ["X_Grid_mid"])
11
+ ds = ds.epoch.rescale_coords("µm", ["X_Grid_mid"], 1e6)
12
12
 
13
13
  ds["Derived_Number_Density"].epoch.plot()
14
14
  plt.tight_layout()
@@ -10,7 +10,7 @@ input_dir = Path("datasets/3_3_Gaussian_1d_laser")
10
10
  ds = sdfxr.open_dataset(input_dir / "0020.sdf")
11
11
 
12
12
  # Convert the x and y coords to microns
13
- ds = ds.epoch.rescale_coords(1e6, "µm", ["X_Grid_mid"])
13
+ ds = ds.epoch.rescale_coords("µm", ["X_Grid_mid"], 1e6)
14
14
 
15
15
  # Calculate Poynting flux magnitude
16
16
  flux_magnitude = np.sqrt(
@@ -8,7 +8,7 @@ import sdf_xarray as sdfxr
8
8
  input_dir = Path("datasets/4_3_basic_target")
9
9
 
10
10
  ds = sdfxr.open_dataset(input_dir / "0000.sdf")
11
- ds = ds.epoch.rescale_coords(1e6, "µm", ["X_Grid_mid", "Y_Grid_mid"])
11
+ ds = ds.epoch.rescale_coords("µm", ["X_Grid_mid", "Y_Grid_mid"], 1e6)
12
12
 
13
13
  ds["Derived_Number_Density"].epoch.plot()
14
14
  plt.tight_layout()
@@ -8,7 +8,7 @@ import sdf_xarray as sdfxr
8
8
  input_dir = Path("datasets/2_1_two_stream_instability")
9
9
  ds = sdfxr.open_dataset(input_dir / "0000.sdf")
10
10
 
11
- ds = ds.epoch.rescale_coords(1e-3, "km", ["X_x_px_Left"])
11
+ ds = ds.epoch.rescale_coords("km", ["X_x_px_Left"], 1e-3)
12
12
 
13
13
  # Sum phase-space of species "Left" and "Right" in "x_px" distribution function
14
14
  # NOTE: We only use the values from the right distribution function as if we inherit
@@ -10,7 +10,7 @@ input_dir = Path("datasets/3_5_Gaussian_beam")
10
10
  ds = sdfxr.open_dataset(input_dir / "0001.sdf")
11
11
 
12
12
  # Convert the x and y coords to microns
13
- ds = ds.epoch.rescale_coords(1e6, "µm", ["X_Grid_mid", "Y_Grid_mid"])
13
+ ds = ds.epoch.rescale_coords("µm", ["X_Grid_mid", "Y_Grid_mid"], 1e6)
14
14
 
15
15
  # Calculate Poynting flux magnitude
16
16
  flux_magnitude = np.sqrt(
@@ -13,7 +13,7 @@ input_dir = Path("datasets/4_2_self_heating")
13
13
  ds = sdfxr.open_mfdataset(input_dir)
14
14
 
15
15
  # Convert the time to femtoseconds
16
- ds = ds.epoch.rescale_coords(1e15, "fs", "time")
16
+ ds = ds.epoch.rescale_coords("fs", "time", 1e15)
17
17
 
18
18
  # Averate temperature over all spatial cells at each time-step
19
19
  kB = 1.380649e-23
@@ -9,7 +9,7 @@ input_dir = Path("datasets/5_2_subsets")
9
9
  ds = sdfxr.open_dataset(input_dir / "0000.sdf", keep_particles=True)
10
10
 
11
11
  ds = ds.epoch.rescale_coords(
12
- 1e6, "µm", ["X_Particles_subset_Refluxers_Electron", "Y_Target_mid"]
12
+ "µm", ["X_Particles_subset_Refluxers_Electron", "Y_Target_mid"], 1e6
13
13
  )
14
14
 
15
15
  x = ds["X_Particles_subset_Refluxers_Electron"]
@@ -0,0 +1,7 @@
1
+ # Workshop Details
2
+
3
+ The workshop consisted of a series of talks and practical sessions delivered at the University of York over the course of 2 days (23-24 April). It covered setting up both `EPOCH` and `sdf-xarray` along with delving into the details of how PIC codes work. The timetable is located [here](https://epochpic.github.io/quickstart/epoch_workshop_2026.html) and recordings of the presentations can be found on [YouTube](https://youtube.com/playlist?list=PLXfw-OhAIheRtwRqrGZvMqFuQ2GrIBLVl).
4
+
5
+ ## Live Demo
6
+
7
+ As part of the start of the workshop a live demo covering the key features of `sdf-xarray` was performed. You can download this jupyter notebook in order to follow along <path:live_demo.ipynb>. Alternatively, if you have a Google account you can use the online [Google Colab notebook](https://colab.research.google.com/drive/1FTKj6gUizKjcL1ZSK4sNKlWKs5mzrD2g?usp=sharing).
@@ -21,6 +21,7 @@ why_sdf_xarray.md
21
21
  loading_data.md
22
22
  understanding_datasets.md
23
23
  unit_conversion.md
24
+ plotting.md
24
25
  animation.md
25
26
  ```
26
27
 
@@ -0,0 +1,95 @@
1
+ ---
2
+ file_format: mystnb
3
+ kernelspec:
4
+ name: python3
5
+ ---
6
+
7
+ # Plotting
8
+
9
+ You can plot datasets using
10
+ [`xarray.DataArray.epoch.plot`](project:#sdf_xarray.dataarray_accessor.EpochAccessor.plot).
11
+ This is a custom <project:#sdf_xarray> plotting routine that builds on top of
12
+ <inv:#xarray.DataArray.plot>, so you keep the familiar <inv:#xarray> plotting
13
+ behaviour while using <project:#sdf_xarray> conveniences (see
14
+ [here](project:#sdf_xarray.dataarray_accessor.EpochAccessor.plot) for details).
15
+ Under the hood, plotting is still handled by <inv:#matplotlib>, which means you
16
+ can use the full <inv:#matplotlib> API to customise your figure.
17
+
18
+ | Dimensions | Base plotting function | Notes |
19
+ | ---------- | ----------------------------- | --------------------- |
20
+ | 1 | <inv:#xarray.plot.line> | |
21
+ | 2 | <inv:#xarray.plot.pcolormesh> | |
22
+ | 3 | <inv:#mpl_toolkits.mplot3d.axes3d.Axes3D.voxels>| Custom functionality built for <project:#sdf_xarray> |
23
+ | >3 | <inv:#xarray.plot.hist> | Not fully implemented |
24
+
25
+ ## Line plots
26
+
27
+ One dimensional data will be plotted as a line. Multiple lines can be easily
28
+ plotted at the same time.
29
+
30
+ ```{code-cell} ipython3
31
+ import sdf_xarray as sdfxr
32
+ import matplotlib.pyplot as plt
33
+ ds = sdfxr.open_dataset("tutorial_dataset_1d/0010.sdf")
34
+ da_1 = ds["Derived_Number_Density_Electron"]
35
+ da_2 = ds["Derived_Number_Density_Ion"]
36
+ da_1.epoch.plot(label = "Electron")
37
+ da_2.epoch.plot(label = "Ion")
38
+ plt.legend()
39
+ plt.show()
40
+ ```
41
+
42
+ ## Mesh plots
43
+
44
+ Two dimensional data will be plotted as a mesh.
45
+
46
+ ```{code-cell} ipython3
47
+ ds = sdfxr.open_dataset("tutorial_dataset_2d/0010.sdf")
48
+ da = ds["Derived_Number_Density_Electron"]
49
+ da.epoch.plot()
50
+ plt.show()
51
+ ```
52
+
53
+ ## Voxel plots
54
+
55
+ Three dimensional data will be plotted using voxels. This behaviour is not native
56
+ to <inv:#xarray>, it has been custom built specifically for this package.
57
+
58
+ ```python
59
+ ds = sdfxr.open_dataset("tutorial_dataset_3d/0000.sdf")
60
+ da = ds["Derived_Number_Density"]
61
+ da.epoch.plot(vmin = 1e27)
62
+ plt.show()
63
+ ```
64
+
65
+ ![voxel_plot_high_res](./figures/voxel_plot_high_res.png)
66
+
67
+ ```{warning}
68
+ Voxel plots can be extremely computationally expensive and may take longer than
69
+ expected to plot.
70
+ ```
71
+
72
+ Because voxel plots are very expensive, even with relatively small data arrays,
73
+ plotting can be sped up by using [`xarray.DataArray.epoch.resize`](project:#sdf_xarray.dataarray_accessor.EpochAccessor.resize),
74
+ which uses interpolation to reduce the resolution.
75
+
76
+ ```{code-cell} ipython3
77
+ ds = sdfxr.open_dataset("tutorial_dataset_3d/0005.sdf")
78
+ da = ds["Derived_Number_Density"]
79
+ da_resized = da.epoch.resize((20, 20, 20))
80
+ da_resized.epoch.plot(vmin = 1e27)
81
+ plt.show()
82
+ ```
83
+
84
+ ## Histograms
85
+
86
+ When the data array has four or more dimensions (or is specified by the user), it will
87
+ be plotted as a histogram.
88
+
89
+ ```{code-cell} ipython3
90
+ ds = sdfxr.open_dataset("tutorial_dataset_3d/0005.sdf")
91
+ da = ds["Derived_Number_Density"]
92
+
93
+ da.epoch.plot(hist = True)
94
+ plt.show()
95
+ ```
@@ -29,23 +29,10 @@ ds = sdfxr.open_mfdataset("tutorial_dataset_1d/*.sdf")
29
29
  ds["Electric_Field_Ex"]
30
30
  ```
31
31
 
32
- ## Plotting
32
+ ## Visualisation
33
33
 
34
- You can plot datasets using
35
- [`xarray.DataArray.epoch.plot`](project:#sdf_xarray.dataarray_accessor.EpochAccessor.plot).
36
- This is a custom <project:#sdf_xarray> plotting routine that builds on top of
37
- <inv:#xarray.DataArray.plot>, so you keep the familiar <inv:#xarray> plotting
38
- behaviour while using <project:#sdf_xarray> conveniences (see
39
- [here](project:#sdf_xarray.dataarray_accessor.EpochAccessor.plot) for details).
40
- Under the hood, plotting is still handled by <inv:#matplotlib>, which means you
41
- can use the full <inv:#matplotlib> API to customise your figure.
42
-
43
- ```{code-cell} ipython3
44
- # This is discretized in both space and time
45
- ds["Electric_Field_Ex"].epoch.plot()
46
- plt.title("Electric field along the x-axis")
47
- plt.show()
48
- ```
34
+ `sdf-xarray` has built-in plotting and animation functionality, more details can
35
+ be found on [](./plotting.md) and [](./animation.md).
49
36
 
50
37
  ## Dimension slicing
51
38
 
@@ -56,6 +43,7 @@ for easy indexing. To quickly determine the number of time steps available,
56
43
  you can check the size of the time dimension.
57
44
 
58
45
  ```{code-cell} ipython3
46
+ ds = sdfxr.open_mfdataset("tutorial_dataset_1d/*.sdf")
59
47
  # This corresponds to the number of individual SDF files loaded
60
48
  print(f"There are a total of {ds['time'].size} time steps")
61
49
 
@@ -66,7 +54,7 @@ print(f"The time at the 20th simulation step is {sim_time:.2e} s")
66
54
 
67
55
  You can select and extract a single simulation snapshot using the integer
68
56
  index of the time step with the <inv:#xarray.Dataset.isel> function. This can be
69
- done by passsing the index to the `time` parameter (e.g., `time=0` for
57
+ done by passing the index to the `time` parameter (e.g., `time=0` for
70
58
  the first snapshot).
71
59
 
72
60
  ```{code-cell} ipython3
@@ -74,7 +62,7 @@ ds["Electric_Field_Ex"].isel(time=20)
74
62
  ```
75
63
 
76
64
  We can also use the <inv:#xarray.Dataset.sel> function if you wish to pass a
77
- value intead of an index.
65
+ value instead of an index.
78
66
 
79
67
  ```{tip}
80
68
  If you know roughly what time you wish to select but not the exact value
@@ -122,6 +110,51 @@ print(f"Total particle energy absorbed: {ds["Total_Particle_Energy_in_Simulation
122
110
  print(f"The laser absorption fraction: {ds["Laser_Absorption_Fraction_in_Simulation"][-1].values:.1f} %")
123
111
  ```
124
112
 
113
+ ## Limit
114
+
115
+ The `.epoch` accessor has the ability to "limit" data arrays. This is a helper
116
+ function which applies <inv:#xarray.DataArray.where> to the upper and lower bounds
117
+ of each dimension. You can use `None` to preserve the existing limit.
118
+
119
+ ```{code-cell} ipython3
120
+ ds = sdfxr.open_dataset("tutorial_dataset_2d/0020.sdf")
121
+ da = ds["Derived_Number_Density_Electron"]
122
+ da.epoch.plot()
123
+ print(f"Orignal shape: {da.shape}")
124
+ plt.show()
125
+ ```
126
+
127
+ ```{code-cell} ipython3
128
+ da_limit = da.epoch.limit(((-2e-6, 2e-6), (None, 0)))
129
+ da_limit.epoch.plot()
130
+ print(f"New shape: {da_limit.shape}")
131
+ plt.show()
132
+ ```
133
+
134
+ ## Resize
135
+
136
+ The data arrays can be interpolated with <project:#sdf_xarray.dataarray_accessor.EpochAccessor.resize>
137
+ to either increase or decrease the resolution while mantaining the general structure.
138
+ Decreasing the size may be useful to download large data from HPCs to local machines
139
+ or ploting with [](./plotting.md#voxel-plots). Be aware that the original
140
+ data will not be preserved.
141
+
142
+ ```{code-cell} ipython3
143
+ ds = sdfxr.open_dataset("tutorial_dataset_2d/0020.sdf")
144
+ da = ds["Derived_Number_Density_Electron"]
145
+
146
+ da.epoch.plot()
147
+ print(f"Orignal shape: {da.shape}")
148
+ plt.show()
149
+ ```
150
+
151
+ ```{code-cell} ipython3
152
+ da_resized = da.epoch.resize((50, 50))
153
+ da_resized.epoch.plot()
154
+ print(f"New shape: {da_resized.shape}")
155
+ plt.show()
156
+ ```
157
+
125
158
  ## Visualisation on HPC Machines
126
159
 
127
160
  In many cases you will be running EPOCH simulations via a HPC cluster and your
@@ -30,7 +30,7 @@ plt.rcParams.update({
30
30
  For simple scaling and unit relabelling of coordinates (e.g., converting meters to microns),
31
31
  the most straightforward approach is to use the [`xarray.Dataset.epoch.rescale_coords`](project:#sdf_xarray.dataset_accessor.EpochAccessor.rescale_coords) dataset accessor.
32
32
  This function scales the coordinate values by a given multiplier and updates the
33
- `"units"` attribute in one step.
33
+ `"units"` attribute in one step. If the multiplier is not specified then the conversion parameter is inferred from the units and converted automatically using `pint` (see [](#unit-conversion-with-pint-xarray) for details).
34
34
 
35
35
  ### Rescaling grid coordinates
36
36
 
@@ -41,7 +41,7 @@ We can use the [`xarray.Dataset.epoch.rescale_coords`](project:#sdf_xarray.datas
41
41
  fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))
42
42
 
43
43
  ds = sdfxr.open_mfdataset("tutorial_dataset_2d/*.sdf")
44
- ds_in_microns = ds.epoch.rescale_coords(1e6, "µm", ["X_Grid_mid", "Y_Grid_mid"])
44
+ ds_in_microns = ds.epoch.rescale_coords("µm", ["X_Grid_mid", "Y_Grid_mid"], 1e6)
45
45
 
46
46
  ds["Derived_Number_Density_Electron"].isel(time=0).epoch.plot(ax=ax1)
47
47
  ax1.set_title("Original X Coordinate (m)")
@@ -55,7 +55,7 @@ fig.tight_layout()
55
55
  ### Rescaling time coordinate
56
56
 
57
57
  We can also use the [`xarray.Dataset.epoch.rescale_coords`](project:#sdf_xarray.dataset_accessor.EpochAccessor.rescale_coords) method to convert the time coordinate from
58
- seconds (`s`) to femto-seconds (`fs`) by applying a multiplier of `1e15`.
58
+ seconds (`s`) to femto-seconds (`fs`).
59
59
 
60
60
  ```{code-cell} ipython3
61
61
  ds = sdfxr.open_mfdataset("tutorial_dataset_2d/*.sdf")
@@ -63,7 +63,7 @@ ds["time"]
63
63
  ```
64
64
 
65
65
  ```{code-cell} ipython3
66
- ds = ds.epoch.rescale_coords(1e15, "fs", "time")
66
+ ds = ds.epoch.rescale_coords("fs", "time")
67
67
  ds["time"]
68
68
  ```
69
69
 
@@ -7,7 +7,7 @@ There are several benefits to using this package over the [`sdf_helper`](https:/
7
7
  - [data to numpy and pandas](https://docs.xarray.dev/en/stable/user-guide/pandas.html) - Data can be easily converted to [numpy](https://www.numpy.org/) or [pandas](https://pandas.pydata.org/) if you prefer to work with raw data.
8
8
  - [data labelling](project:understanding_datasets.md) - All SDF files come with a bunch of information about them such as the `dimensions`, `units` and `name` of the variable. In <inv:#xarray> these are added to each variable making it much easier to read.
9
9
  - [lazy/partial loading](https://docs.xarray.dev/en/stable/internals/internal-design.html#lazy-loading) - This reduces the RAM requirements when loading large SDF files as we only load the actual array values when they are needed.
10
- - [plotting](project:understanding_datasets.md#plotting) - You can easily plot variables across several dimensions including time using built in <inv:#matplotlib> support.
10
+ - [plotting](project:plotting.md) - You can easily plot variables across several dimensions including time using built in <inv:#matplotlib> support.
11
11
  - [animating](project:animation.md) - Visualise your data across time or slice through another dimension and make beautiful GIFs for your presentations.
12
12
  - [deck loading](loading-input-deck) - <project:#sdf_xarray> automatically loads in the associated `input.deck` utilised when creating the simulation so that you can access setup variables.
13
13
  - [easier unit conversion](project:unit_conversion.md) - Convert dimensions and variable units to other types with the help of [`pint`](https://pint.readthedocs.io/en/stable).
@@ -69,6 +69,7 @@ docs = [
69
69
  "sphinx-design>=0.7.0",
70
70
  "pooch>=1.8.2",
71
71
  "tqdm",
72
+ "scipy",
72
73
  ]
73
74
  build = ["cibuildwheel[uv]"]
74
75
  lint = ["ruff"]
@@ -78,6 +79,9 @@ test = [
78
79
  "matplotlib",
79
80
  "pooch>=1.8.2",
80
81
  "tqdm",
82
+ "pint",
83
+ "pint-xarray",
84
+ "scipy",
81
85
  ]
82
86
 
83
87
  [project.entry-points."xarray.backends"]
@@ -131,6 +135,10 @@ ignore = [
131
135
  "PLR2004", # magic-comparison
132
136
  "B9", # flake8-bugbear opinionated warnings
133
137
  "PLR0913", # remove maximum number of arguments in a function
138
+ "PLR0917", # remove maximum number of positional arguments in a function
139
+ "BLE001", # allow capturing of base exception
134
140
  ]
135
- exclude = ["**/_version.py"]
136
- # Auto-generated file
141
+ exclude = ["**/_version.py"] # Auto-generated file
142
+
143
+ [tool.pytest.ini_options]
144
+ filterwarnings = ['ignore::UserWarning']
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.7.4'
22
- __version_tuple__ = version_tuple = (0, 7, 4)
21
+ __version__ = version = '0.9.0'
22
+ __version_tuple__ = version_tuple = (0, 9, 0)
23
23
 
24
- __commit_id__ = commit_id = 'gc521760ee'
24
+ __commit_id__ = commit_id = 'g65bb865da'