sdf-xarray 0.4.0__tar.gz → 0.5.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 (45) hide show
  1. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/.github/workflows/build_publish.yml +7 -0
  2. sdf_xarray-0.5.0/.github/workflows/lint.yml +30 -0
  3. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/.github/workflows/tests.yml +7 -1
  4. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/.gitignore +48 -0
  5. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/CONTRIBUTING.md +18 -10
  6. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/PKG-INFO +4 -5
  7. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/README.md +2 -2
  8. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/animation.rst +64 -66
  9. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/getting_started.rst +20 -0
  10. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/key_functionality.rst +55 -2
  11. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/pyproject.toml +10 -10
  12. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/src/sdf_xarray/__init__.py +273 -13
  13. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/src/sdf_xarray/_version.py +3 -3
  14. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/src/sdf_xarray/dataset_accessor.py +53 -0
  15. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/src/sdf_xarray/download.py +3 -2
  16. sdf_xarray-0.5.0/src/sdf_xarray/plotting.py +567 -0
  17. sdf_xarray-0.4.0/tests/test_basic.py → sdf_xarray-0.5.0/tests/test_dataset.py +6 -0
  18. sdf_xarray-0.5.0/tests/test_datatree.py +313 -0
  19. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/tests/test_epoch_dataset_accessor.py +107 -7
  20. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/uv.lock +114 -711
  21. sdf_xarray-0.4.0/.github/workflows/black.yml +0 -40
  22. sdf_xarray-0.4.0/.github/workflows/lint.yml +0 -11
  23. sdf_xarray-0.4.0/src/sdf_xarray/plotting.py +0 -293
  24. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/.gitmodules +0 -0
  25. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/.readthedocs.yaml +0 -0
  26. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/BEAM.png +0 -0
  27. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/CITATION.cff +0 -0
  28. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/CMakeLists.txt +0 -0
  29. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/LICENCE +0 -0
  30. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/PlasmaFAIR.svg +0 -0
  31. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/.gitignore +0 -0
  32. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/_static/force_render_dark_xarray_objects.css +0 -0
  33. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/_templates/custom-class-template.rst +0 -0
  34. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/_templates/custom-module-template.rst +0 -0
  35. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/api.rst +0 -0
  36. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/conf.py +0 -0
  37. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/contributing.rst +0 -0
  38. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/index.rst +0 -0
  39. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/known_issues.rst +0 -0
  40. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/make.bat +0 -0
  41. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/docs/unit_conversion.rst +0 -0
  42. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/src/sdf_xarray/csdf.pxd +0 -0
  43. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/src/sdf_xarray/sdf_interface.pyx +0 -0
  44. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/tests/test_cython.py +0 -0
  45. {sdf_xarray-0.4.0 → sdf_xarray-0.5.0}/tests/test_epoch_dataarray_accessor.py +0 -0
@@ -19,6 +19,13 @@ jobs:
19
19
  fetch-depth: 0
20
20
  submodules: "recursive"
21
21
 
22
+ - name: Cache Zenodo datasets
23
+ uses: actions/cache@v4
24
+ with:
25
+ enableCrossOsArchive: true
26
+ path: ~/.cache/sdf_datasets
27
+ key: sdf-datasets-17991042
28
+
22
29
  - name: Setup uv
23
30
  id: setup-uv
24
31
  uses: astral-sh/setup-uv@v3
@@ -0,0 +1,30 @@
1
+ name: lint
2
+
3
+ on:
4
+ push:
5
+ paths:
6
+ - '**.py'
7
+ pull_request:
8
+ paths:
9
+ - '**.py'
10
+
11
+ jobs:
12
+ lint:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ with:
17
+ fetch-depth: 0
18
+
19
+ # Providing 'args' prevents the action from running 'ruff check .'
20
+ # immediately after installing ruff.
21
+ - name: Install Ruff
22
+ uses: astral-sh/ruff-action@v3
23
+ with:
24
+ args: "--version"
25
+
26
+ - name: Check
27
+ run: ruff check --output-format=github src tests
28
+
29
+ - name: Format
30
+ run: ruff format --check --diff src tests
@@ -8,7 +8,7 @@ jobs:
8
8
  strategy:
9
9
  fail-fast: false
10
10
  matrix:
11
- python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
11
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
12
12
 
13
13
  steps:
14
14
  - uses: actions/checkout@v4
@@ -30,5 +30,11 @@ jobs:
30
30
  uv python install ${{ matrix.python-version }}
31
31
  uv sync --python ${{ matrix.python-version }} --frozen
32
32
 
33
+ - name: Cache Zenodo datasets
34
+ uses: actions/cache@v4
35
+ with:
36
+ path: ~/.cache/sdf_datasets
37
+ key: sdf-datasets-17991042
38
+
33
39
  - name: Test with pytest
34
40
  run: uv run pytest
@@ -1,4 +1,6 @@
1
1
  # -*- mode: gitignore; -*-
2
+ # https://github.com/github/gitignore/blob/main/Global/Emacs.gitignore
3
+ # --------------------------------------------------------------------
2
4
  *~
3
5
  \#*\#
4
6
  /.emacs.desktop
@@ -47,6 +49,9 @@ flycheck_*.el
47
49
  # network security
48
50
  /network-security.data
49
51
 
52
+ # https://github.com/github/gitignore/blob/main/Global/Linux.gitignore
53
+ # --------------------------------------------------------------------
54
+
50
55
  *~
51
56
 
52
57
  # temporary files which can be created if a process still has a handle open of a deleted file
@@ -60,6 +65,10 @@ flycheck_*.el
60
65
 
61
66
  # .nfs files are created when an open file is removed but is still being accessed
62
67
  .nfs*
68
+
69
+ # https://github.com/github/gitignore/blob/main/Python.gitignore
70
+ # --------------------------------------------------------------
71
+
63
72
  # Byte-compiled / optimized / DLL files
64
73
  __pycache__/
65
74
  *.py[cod]
@@ -222,6 +231,37 @@ cython_debug/
222
231
  # and can be added to the global gitignore or merged into this file. For a more nuclear
223
232
  # option (not recommended) you can uncomment the following to ignore the entire idea folder.
224
233
  #.idea/
234
+
235
+ # Abstra
236
+ # Abstra is an AI-powered process automation framework.
237
+ # Ignore directories containing user credentials, local state, and settings.
238
+ # Learn more at https://abstra.io/docs
239
+ .abstra/
240
+
241
+ # Visual Studio Code
242
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
243
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
244
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
245
+ # you could uncomment the following to ignore the entire vscode folder
246
+ .vscode/
247
+
248
+ # Ruff stuff:
249
+ .ruff_cache/
250
+
251
+ # PyPI configuration file
252
+ .pypirc
253
+
254
+ # Marimo
255
+ marimo/_static/
256
+ marimo/_lsp/
257
+ __marimo__/
258
+
259
+ # Streamlit
260
+ .streamlit/secrets.toml
261
+
262
+ # https://github.com/github/gitignore/blob/main/CMake.gitignore
263
+ # ------------------------------------------------------------
264
+
225
265
  CMakeLists.txt.user
226
266
  CMakeCache.txt
227
267
  CMakeFiles
@@ -233,6 +273,11 @@ install_manifest.txt
233
273
  compile_commands.json
234
274
  CTestTestfile.cmake
235
275
  _deps
276
+ CMakeUserPresets.json
277
+
278
+ # https://github.com/github/gitignore/blob/main/C.gitignore
279
+ # ---------------------------------------------------------
280
+
236
281
  # Prerequisites
237
282
  *.d
238
283
 
@@ -286,6 +331,9 @@ Module.symvers
286
331
  Mkfile.old
287
332
  dkms.conf
288
333
 
334
+ # sdf-xarray specific ignores
335
+ # ---------------------------
336
+
289
337
  # Generated version file
290
338
  src/sdf_xarray/_version.py
291
339
 
@@ -28,14 +28,8 @@ pip install .
28
28
 
29
29
  ### Style
30
30
 
31
- We follow [PEP 8](https://peps.python.org/pep-0008/) and use the
32
- following tools:
33
-
34
- - [ruff](https://github.com/astral-sh/ruff) for linting
35
- - [black](https://black.readthedocs.io/en/stable/) for formatting
36
- - [isort](https://pycqa.github.io/isort/) for sorting imports
37
-
38
- To run these tools locally, install the `lint` dependency group:
31
+ We use [Ruff](https://docs.astral.sh/ruff/) to maintain code quality and
32
+ formatting. This can be installed locally via the `lint` dependency group:
39
33
 
40
34
  ```bash
41
35
  pip install --group lint
@@ -53,6 +47,20 @@ Alternatively, `uv` users can do this in one step with `uv run`:
53
47
  uv run ruff check src tests
54
48
  ```
55
49
 
50
+ Many of the issues raised by Ruff can be fixed automatically:
51
+
52
+ ```bash
53
+ ruff check --fix src tests
54
+ ```
55
+
56
+ Ruff may also be used to format the code to a style similar to that enforced by
57
+ [Black](https://black.readthedocs.io/en/stable/), which (almost) matches the
58
+ [PEP-8 standard](https://peps.python.org/pep-0008/):
59
+
60
+ ```bash
61
+ ruff format src tests
62
+ ```
63
+
56
64
  ### Running and adding tests
57
65
 
58
66
  We use [pytest](https://docs.pytest.org/en/stable/) to run tests.
@@ -130,8 +138,8 @@ Then open http://localhost:8000 in your browser to view the documentation.
130
138
 
131
139
  All pull requests are automatically checked using GitHub Actions for:
132
140
 
133
- - Linting (`ruff`)
134
- - Formatting (`black` and `isort`)
141
+ - Linting and formatting (`ruff`)
135
142
  - Testing (`pytest`)
143
+ - Cross-platform building (`cibuildwheel`)
136
144
 
137
145
  These checks must pass before a pull request can be merged.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sdf-xarray
3
- Version: 0.4.0
3
+ Version: 0.5.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>
6
6
  License-Expression: BSD-3-Clause
@@ -10,12 +10,11 @@ Classifier: Topic :: Scientific/Engineering
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.10
14
13
  Classifier: Programming Language :: Python :: 3.11
15
14
  Classifier: Programming Language :: Python :: 3.12
16
15
  Classifier: Programming Language :: Python :: 3.13
17
16
  Classifier: Programming Language :: Python :: 3.14
18
- Requires-Python: <3.15,>=3.10
17
+ Requires-Python: <3.15,>=3.11
19
18
  Requires-Dist: numpy>=2.0.0
20
19
  Requires-Dist: xarray>=2024.1.0
21
20
  Requires-Dist: dask>=2024.7.1
@@ -35,7 +34,7 @@ Description-Content-Type: text/markdown
35
34
  ![Build/Publish](https://github.com/epochpic/sdf-xarray/actions/workflows/build_publish.yml/badge.svg)
36
35
  ![Tests](https://github.com/epochpic/sdf-xarray/actions/workflows/tests.yml/badge.svg)
37
36
  [![Read the Docs](https://img.shields.io/readthedocs/sdf-xarray?logo=readthedocs&link=https%3A%2F%2Fsdf-xarray.readthedocs.io%2F)](https://sdf-xarray.readthedocs.io)
38
- [![Formatted with black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)
37
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
39
38
 
40
39
 
41
40
  sdf-xarray provides a backend for [xarray](https://xarray.dev) to read SDF files as created by
@@ -148,4 +147,4 @@ To run checks locally before opening a pull request, see [CONTRIBUTING.md](CONTR
148
147
 
149
148
  ![PlasmaFAIR logo](PlasmaFAIR.svg)
150
149
 
151
- Originally developed by [PlasmaFAIR](https://plasmafair.github.io), EPSRC Grant EP/V051822/1
150
+ Originally developed by [PlasmaFAIR](https://plasmafair.github.io), EPSRC Grant EP/V051822/1
@@ -6,7 +6,7 @@
6
6
  ![Build/Publish](https://github.com/epochpic/sdf-xarray/actions/workflows/build_publish.yml/badge.svg)
7
7
  ![Tests](https://github.com/epochpic/sdf-xarray/actions/workflows/tests.yml/badge.svg)
8
8
  [![Read the Docs](https://img.shields.io/readthedocs/sdf-xarray?logo=readthedocs&link=https%3A%2F%2Fsdf-xarray.readthedocs.io%2F)](https://sdf-xarray.readthedocs.io)
9
- [![Formatted with black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)
9
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
10
10
 
11
11
 
12
12
  sdf-xarray provides a backend for [xarray](https://xarray.dev) to read SDF files as created by
@@ -119,4 +119,4 @@ To run checks locally before opening a pull request, see [CONTRIBUTING.md](CONTR
119
119
 
120
120
  ![PlasmaFAIR logo](PlasmaFAIR.svg)
121
121
 
122
- Originally developed by [PlasmaFAIR](https://plasmafair.github.io), EPSRC Grant EP/V051822/1
122
+ Originally developed by [PlasmaFAIR](https://plasmafair.github.io), EPSRC Grant EP/V051822/1
@@ -3,6 +3,9 @@
3
3
  .. |animate_accessor| replace:: `xarray.DataArray.epoch.animate
4
4
  <sdf_xarray.plotting.animate>`
5
5
 
6
+ .. |animate_multiple_accessor| replace:: `xarray.Dataset.epoch.animate_multiple
7
+ <sdf_xarray.plotting.animate_multiple>`
8
+
6
9
  ==========
7
10
  Animations
8
11
  ==========
@@ -131,10 +134,8 @@ Moving window
131
134
  -------------
132
135
 
133
136
  EPOCH allows for simulations that have a moving simulation window
134
- (changing x-axis over time). |animate_accessor| will
135
- automatically detect when a simulation has a moving window by searching
136
- for NaNs in the `xarray.DataArray` and change the x-axis limits
137
- accordingly.
137
+ (changing x-axis over time). |animate_accessor| can accept the boolean parameter
138
+ ``move_window`` and change the x-axis limits accordingly.
138
139
 
139
140
  .. warning::
140
141
  `sdf_xarray.open_mfdataset` does not currently function with moving window data.
@@ -152,7 +153,7 @@ accordingly.
152
153
  )
153
154
 
154
155
  da = ds["Derived_Number_Density_Beam_Electrons"]
155
- anim = da.epoch.animate(fps = 5)
156
+ anim = da.epoch.animate(move_window=True, fps = 5)
156
157
  anim.show()
157
158
 
158
159
  .. warning::
@@ -191,73 +192,70 @@ before plotting as in :ref:`sec-unit-conversion`. Some functionality such as
191
192
  )
192
193
  anim.show()
193
194
 
194
- Advanced usage
195
- --------------
195
+ Combining multiple animations
196
+ -----------------------------
196
197
 
197
- Multiple plots on the same axes
198
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
198
+ |animate_multiple_accessor| creates a `matplotlib.animation.FuncAnimation`
199
+ that contains multiple plots layered on top of each other.
200
+
201
+ 1D simulation
202
+ ~~~~~~~~~~~~~
199
203
 
200
204
  What follows is an example of how to combine multiple animations on the
201
- same axis. This may be implemented in a more user-friendly function in
202
- a future update.
205
+ same axis.
203
206
 
204
207
  .. jupyter-execute::
205
208
 
206
- # Open the SDF files
207
209
  ds = sdfxr.open_mfdataset("tutorial_dataset_1d/*.sdf")
208
210
 
209
- # Create figure and axes
210
- fig, ax = plt.subplots()
211
- plt.close(fig)
212
-
213
- # Generate the animations independently
214
- anim_1 = ds["Derived_Number_Density_Electron"].epoch.animate()
215
- anim_2 = ds["Derived_Number_Density_Ion"].epoch.animate()
216
-
217
- # Extract the update functions from the animations
218
- update_1 = anim_1._func
219
- update_2 = anim_2._func
220
-
221
- # Create axes details for new animation
222
- x_min, x_max = update_1(0)[0].axes.get_xlim()
223
- y_min_1, y_max_1 = update_1(0)[0].axes.get_ylim()
224
- y_min_2, y_max_2 = update_2(0)[0].axes.get_ylim()
225
- y_min = min(y_min_1, y_min_2)
226
- y_max = max(y_max_1, y_max_2)
227
- x_label = update_1(0)[0].axes.get_xlabel()
228
- y_label = "Number Density [m$^{-3}$]"
229
- label_1 = "Electron"
230
- label_2 = "Ion"
231
-
232
- # Create new update function
233
- def update_combined(frame):
234
- anim_1_fig = update_1(frame)[0]
235
- anim_2_fig = update_2(frame)[0]
236
-
237
- title = anim_1_fig.axes.title._text
238
-
239
- ax.clear()
240
- plot = ax.plot(anim_1_fig._x, anim_1_fig._y, label = label_1)
241
- ax.plot(anim_2_fig._x, anim_2_fig._y, label = label_2)
242
- ax.set_title(title)
243
- ax.set_xlim(x_min, x_max)
244
- ax.set_ylim(y_min, y_max)
245
- ax.set_xlabel(x_label)
246
- ax.set_ylabel(y_label)
247
- ax.legend(loc = "upper left")
248
- return plot
249
-
250
- N_frames = anim_1._save_count
251
- interval = anim_1._interval
252
-
253
- # Create combined animation
254
- anim_combined = FuncAnimation(
255
- fig,
256
- update_combined,
257
- frames=range(N_frames),
258
- interval = interval,
259
- repeat=True,
260
- )
211
+ anim = ds.epoch.animate_multiple(
212
+ ds["Derived_Number_Density_Electron"],
213
+ ds["Derived_Number_Density_Ion"],
214
+ datasets_kwargs=[{"label": "Electron"}, {"label": "Ion"}],
215
+ ylim=(0e27,4e27),
216
+ ylabel="Derived Number Density [1/m$^3$]"
217
+ )
261
218
 
262
- # Display animation as jshtml
263
- HTML(anim_combined.to_jshtml())
219
+ anim.show()
220
+
221
+ 2D simulation
222
+ ~~~~~~~~~~~~~
223
+
224
+ .. tip::
225
+ To correctly display 2D data on top of one another you need to specify
226
+ the ``alpha`` value which sets the opacity of the plot.
227
+
228
+ This also works with 2 dimensional data.
229
+
230
+ .. jupyter-execute::
231
+
232
+ import numpy as np
233
+ from matplotlib.colors import LogNorm
234
+
235
+ ds = sdfxr.open_mfdataset("tutorial_dataset_2d/*.sdf")
236
+
237
+ flux_magnitude = np.sqrt(
238
+ ds["Derived_Poynting_Flux_x"]**2 +
239
+ ds["Derived_Poynting_Flux_y"]**2 +
240
+ ds["Derived_Poynting_Flux_z"]**2
241
+ )
242
+ flux_magnitude.attrs["long_name"] = "Poynting Flux Magnitude"
243
+ flux_magnitude.attrs["units"] = "W/m$^2$"
244
+
245
+ # Cut-off low energy values so that they will be rendered as transparent
246
+ # in the plot as they've been set to NaN
247
+ flux_masked = flux_magnitude.where(flux_magnitude > 0.2e23)
248
+ flux_norm = LogNorm(
249
+ vmin=float(flux_masked.min()),
250
+ vmax=float(flux_masked.max())
251
+ )
252
+
253
+ anim = ds.epoch.animate_multiple(
254
+ ds["Derived_Number_Density_Electron"],
255
+ flux_masked,
256
+ datasets_kwargs=[
257
+ {"alpha": 1.0},
258
+ {"cmap": "hot", "norm": flux_norm, "alpha": 0.9},
259
+ ],
260
+ )
261
+ anim.show()
@@ -64,6 +64,16 @@ Loading single files
64
64
 
65
65
  xr.open_dataset("tutorial_dataset_1d/0010.sdf")
66
66
 
67
+ Alternatively, you can load the data in as a `xarray.DataTree`, which organises the data
68
+ hierarchically into ``groups`` (for example grouping related quantities such as the individual
69
+ components of the electric and magnetic fields) while keeping each item as a `xarray.Dataset`.
70
+
71
+ .. jupyter-execute::
72
+
73
+ import sdf_xarray as sdfxr
74
+
75
+ sdfxr.open_datatree("tutorial_dataset_1d/0010.sdf")
76
+
67
77
  Loading multiple files
68
78
  ----------------------
69
79
 
@@ -73,6 +83,16 @@ Loading multiple files
73
83
 
74
84
  sdfxr.open_mfdataset("tutorial_dataset_1d/*.sdf")
75
85
 
86
+ Alternatively, you can load the data in as a `xarray.DataTree`, which organises the data
87
+ hierarchically into ``groups`` (for example grouping related quantities such as the individual
88
+ components of the electric and magnetic fields) while keeping each item as a `xarray.Dataset`.
89
+
90
+ .. jupyter-execute::
91
+
92
+ import sdf_xarray as sdfxr
93
+
94
+ sdfxr.open_mfdatatree("tutorial_dataset_1d/*.sdf")
95
+
76
96
  .. _loading-raw-files-getting-started:
77
97
 
78
98
  Loading raw files
@@ -15,8 +15,8 @@ Loading SDF files
15
15
  -----------------
16
16
  There are several ways to load SDF files:
17
17
 
18
- - To load a single file, use `xarray.open_dataset`.
19
- - To load multiple files, use `sdf_xarray.open_mfdataset` or `xarray.open_mfdataset`.
18
+ - To load a single file, use `xarray.open_dataset`, `sdf_xarray.open_datatree` or `xarray.open_datatree`
19
+ - To load multiple files, use `sdf_xarray.open_mfdataset`, `xarray.open_mfdataset` or `sdf_xarray.open_mfdatatree`.
20
20
  - To access the raw contents of a single SDF file, use `sdf_xarray.sdf_interface.SDFFile`.
21
21
 
22
22
  .. note::
@@ -41,6 +41,13 @@ Loading single files
41
41
 
42
42
  xr.open_dataset("tutorial_dataset_1d/0010.sdf")
43
43
 
44
+ Alternatively, you can load the data in as a `xarray.DataTree`, which organises the data
45
+ hierarchically into ``groups`` (for example grouping related quantities such as the individual
46
+ components of the electric and magnetic fields) while keeping each item as a `xarray.Dataset`.
47
+
48
+ .. jupyter-execute::
49
+
50
+ sdfxr.open_datatree("tutorial_dataset_1d/0010.sdf")
44
51
 
45
52
  .. _loading-raw-files:
46
53
 
@@ -72,6 +79,14 @@ is by using the `sdf_xarray.open_mfdataset`.
72
79
 
73
80
  sdfxr.open_mfdataset("tutorial_dataset_1d/*.sdf")
74
81
 
82
+ Alternatively, you can load the data in as a `xarray.DataTree`, which organises the data
83
+ hierarchically into ``groups`` (for example grouping related quantities such as the individual
84
+ components of the electric and magnetic fields) while keeping each item as a `xarray.Dataset`.
85
+
86
+ .. jupyter-execute::
87
+
88
+ sdfxr.open_mfdatatree("tutorial_dataset_1d/*.sdf")
89
+
75
90
  Alternatively files can be loaded using `xarray.open_mfdataset` however when loading in
76
91
  all the files we have do some processing of the data so that we can correctly align it along
77
92
  the time dimension; This is done via the ``preprocess`` parameter utilising the
@@ -219,6 +234,44 @@ value intead of an index.
219
234
 
220
235
  ds["Electric_Field_Ex"].sel(time=sim_time)
221
236
 
237
+ Visualisation on HPCs
238
+ ---------------------
239
+
240
+ In many cases you will be running EPOCH simulations via a HPC cluster and your
241
+ subsequent SDF files will probably be rather large and cumbersome to interact with
242
+ via traditional Jupyter notebooks. In some cases your HPC may outright block the
243
+ use of Jupyter notebooks entirely. To circumvent this issue you can use a Terminal
244
+ User Interface (TUI) which renders the contents of SDF files directly in a Terminal
245
+ and allows for you to do some simple data analysis and visualisation. To do this we
246
+ shall leverage the `xr-tui <https://github.com/samueljackson92/xr-tui>`_ package
247
+ which can be installed to either a venv or globally using:
248
+
249
+ .. code-block:: bash
250
+
251
+ pip install xr-tui sdf-xarray
252
+
253
+ or if you are using ``uv``
254
+
255
+ .. code-block:: bash
256
+
257
+ uv tool install xr-tui --with sdf-xarray
258
+
259
+ Once installed you can visualise SDF files by simply writing in the command line
260
+
261
+ .. code-block:: bash
262
+
263
+ xr path/to/simulation/0000.sdf
264
+ # OR
265
+ xr path/to/simulation/*.sdf
266
+
267
+
268
+ Below is an example gif of how this interfacing looks as seen on
269
+ `xr-tui <https://github.com/samueljackson92/xr-tui>`_ ``README.md``:
270
+
271
+ .. image:: https://raw.githubusercontent.com/samueljackson92/xr-tui/main/demo.gif
272
+ :alt: xr-tui interfacing gif
273
+ :align: center
274
+
222
275
  Manipulating data
223
276
  -----------------
224
277
 
@@ -19,7 +19,7 @@ authors = [
19
19
  { name = "Chris Herdman", email = "chris.herdman@york.ac.uk" },
20
20
  { name = "Liam Pattinson", email = "liam.pattinson@york.ac.uk" },
21
21
  ]
22
- requires-python = ">=3.10,<3.15"
22
+ requires-python = ">=3.11,<3.15"
23
23
  dependencies = ["numpy>=2.0.0", "xarray>=2024.1.0", "dask>=2024.7.1"]
24
24
  description = "Provides a backend for xarray to read SDF files as created by the EPOCH plasma PIC code."
25
25
  classifiers = [
@@ -29,7 +29,6 @@ classifiers = [
29
29
  "Operating System :: OS Independent",
30
30
  "Programming Language :: Python",
31
31
  "Programming Language :: Python :: 3",
32
- "Programming Language :: Python :: 3.10",
33
32
  "Programming Language :: Python :: 3.11",
34
33
  "Programming Language :: Python :: 3.12",
35
34
  "Programming Language :: Python :: 3.13",
@@ -42,10 +41,10 @@ pint = ["pint", "pint-xarray"]
42
41
 
43
42
  [dependency-groups]
44
43
  dev = [
45
- {include-group = "build"},
46
- {include-group = "docs"},
47
- {include-group = "lint"},
48
- {include-group = "test"},
44
+ { include-group = "build" },
45
+ { include-group = "docs" },
46
+ { include-group = "lint" },
47
+ { include-group = "test" },
49
48
  ]
50
49
  docs = [
51
50
  "sphinx>=5.3",
@@ -76,6 +75,9 @@ test = [
76
75
  [project.entry-points."xarray.backends"]
77
76
  sdf_engine = "sdf_xarray:SDFEntrypoint"
78
77
 
78
+ [project.entry-points."xr_tui.backends"]
79
+ "*.sdf" = "sdf_xarray:XrTUIEntrpoint"
80
+
79
81
  [tool.scikit-build]
80
82
  metadata.version.provider = "scikit_build_core.metadata.setuptools_scm"
81
83
  sdist.include = ["src/sdf_xarray/_version.py"]
@@ -94,7 +96,6 @@ cache-keys = [{ file = "pyproject.toml" }, { git = true }]
94
96
 
95
97
  [tool.ruff]
96
98
  line-length = 88
97
- target-version = "py310"
98
99
 
99
100
  [tool.ruff.lint]
100
101
  extend-select = [
@@ -123,6 +124,5 @@ ignore = [
123
124
  "B9", # flake8-bugbear opinionated warnings
124
125
  "PLR0913", # remove maximum number of arguments in a function
125
126
  ]
126
- exclude = [
127
- "**/_version.py", # Auto-generated file
128
- ]
127
+ exclude = ["**/_version.py"]
128
+ # Auto-generated file