Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
2000 commits
Select commit Hold shift + click to select a range
8f10e97
First draft of SingleDataSetView
summerhenson Mar 10, 2025
5c6c24a
First draft for DataSetUsersView
summerhenson Mar 10, 2025
6eee3df
Add filter based on username in get request body
summerhenson Mar 10, 2025
fcf4a7c
Nested metadata serialization
summerhenson Mar 10, 2025
47cbd8d
Fix error in paths
summerhenson Mar 10, 2025
5fdd051
Structure for dataset tests
summerhenson Mar 11, 2025
390e68d
Fix filtering by username
summerhenson Mar 11, 2025
b1b7678
Tests for listing datasets
summerhenson Mar 11, 2025
7bd43c6
Tests for loading a dataset
summerhenson Mar 11, 2025
51b8d0f
Test for deleting a dataset
summerhenson Mar 11, 2025
4b0e5d0
Fix error in permissions check
summerhenson Mar 11, 2025
bd9fcee
Tests for updating a dataset
summerhenson Mar 11, 2025
c8826cb
Only allow data owner to view/manage access
summerhenson Mar 11, 2025
eee6f0d
Tests for listing users with access to a dataset
summerhenson Mar 11, 2025
7ec9592
Test granting access to dataset
summerhenson Mar 11, 2025
5c88067
Fix dataset creation
summerhenson Mar 12, 2025
1cbf256
Set owner when data is created
summerhenson Mar 12, 2025
af98488
Disallow creating private data without an owner
summerhenson Mar 12, 2025
5736653
Finish tests for DataSetView
summerhenson Mar 12, 2025
2387679
Fix error in accessing request user from serializer
summerhenson Mar 12, 2025
b0e8ff0
Modify existing SingleDataSet tests
summerhenson Mar 12, 2025
65a156d
Tests for unauthorized deletes
summerhenson Mar 12, 2025
b275cf1
Finish DataSetAccessManagement tests
summerhenson Mar 12, 2025
832dac1
Allow private data owner to change, not just public
summerhenson Mar 13, 2025
ac3079f
Document dataset tests + one more test
summerhenson Mar 13, 2025
1fc96de
Documentation for datafile tests
summerhenson Mar 13, 2025
189c216
Tests to make sure a user can't specify a data object id
summerhenson Mar 13, 2025
253393e
Add operation/parameters fields to OperationTree model
summerhenson Mar 14, 2025
711cb7a
Change response status to 401 for unauthenticated
summerhenson Mar 14, 2025
8c16660
Change tests to reflect status code change
summerhenson Mar 14, 2025
f326cc1
Skeleton of reformatted data file API
summerhenson Mar 17, 2025
1f584e1
Fill out DataFileView methods
summerhenson Mar 17, 2025
3b863b9
Change serializer validation to raise exception
summerhenson Mar 17, 2025
54ba8f2
SingleDataFileView methods
summerhenson Mar 17, 2025
21b4f29
DataFileUsersView methods
summerhenson Mar 17, 2025
d800735
Update urls for DataFile
summerhenson Mar 17, 2025
8b7f771
Fix error in get method for file download
summerhenson Mar 17, 2025
080456e
Fix error in datafile post
summerhenson Mar 17, 2025
8128355
Update tests for url changes
summerhenson Mar 17, 2025
f8c57cf
Updates for changes to SasData class
summerhenson Mar 18, 2025
b5b6566
Add published state to session model
summerhenson Mar 18, 2025
3cd9e59
Update metadata serializers for latest changes
summerhenson Mar 19, 2025
44f04b5
Update metadata model for recent changes
summerhenson Mar 19, 2025
3269b76
Account for metadata changes in test
summerhenson Mar 19, 2025
22235fd
Changes to OperationTree model
summerhenson Mar 19, 2025
d65e5af
Change metadata serialization in SasData serialization method
summerhenson Mar 20, 2025
93d940f
Change defaults and designate allowed operations for metadata/operati…
summerhenson Mar 20, 2025
e165a6d
Customize creation in OperationTreeSerializer
summerhenson Mar 20, 2025
319269d
Quantity model
summerhenson Mar 20, 2025
9748c12
Change SasData serializer to facilitate database deserialization
summerhenson Mar 20, 2025
11ca9a7
Nested quantity serialization in DataSetSerializer
summerhenson Mar 20, 2025
6c619ca
Add nested quantities to tests
summerhenson Mar 20, 2025
326760c
Comment out failing sasdata tests until they get fixed
summerhenson Mar 21, 2025
e6125d0
Edits to github actions/yml files
summerhenson Mar 24, 2025
0af7d7b
Clarify logic in permissions
summerhenson Mar 24, 2025
8e04f09
Test tokens valid on multiple login
summerhenson Mar 24, 2025
7e9f367
Remove mysterious extra spaces
summerhenson Mar 24, 2025
b88437b
Change operations model to refer to quantity
summerhenson Mar 25, 2025
bc8e54c
Add nested serialization for operation tree in quantity
summerhenson Mar 25, 2025
00e5246
Make operations tree optional for a quantity
summerhenson Mar 25, 2025
f0fbca3
Rename api clients in tests for clarity
summerhenson Mar 27, 2025
4603bf4
Restrict Django test runner to database tests
summerhenson Mar 27, 2025
d6eeeac
String representation of units for serialization
summerhenson Apr 1, 2025
5877827
Change and test response for changing access to a DataFile
summerhenson Apr 3, 2025
dd6ae8b
Add hash value to quantity serialization
summerhenson Apr 3, 2025
fbe04e0
Delete old method-based views
summerhenson Apr 3, 2025
e12b789
Change and test response for DataSet access management
summerhenson Apr 3, 2025
d2a5bf8
Serialization for QuantityType
summerhenson Apr 4, 2025
d875813
Empty class for operation testing
summerhenson Apr 4, 2025
0c36841
PublishedState and Session models
summerhenson Apr 4, 2025
e673116
Empty classes for session views
summerhenson Apr 4, 2025
fb4be4e
Basic serializer for session
summerhenson Apr 4, 2025
8e33187
Nested serializers in SessionSerializer
summerhenson Apr 4, 2025
0f9e4f7
session post method
summerhenson Apr 4, 2025
9027991
Session access management views
summerhenson Apr 4, 2025
bca9d5e
urls for sessions
summerhenson Apr 4, 2025
545e17c
methods for SingleSessionView - might need to revise later
summerhenson Apr 4, 2025
1728648
Switch key from OperationTree to Quantity
summerhenson Apr 7, 2025
ad108da
Add nested OperationTree to Quantity serializer
summerhenson Apr 7, 2025
5e7e8c8
Add title to Session
summerhenson Apr 7, 2025
4d344ba
Use numerical_encoding in sasdata for QuantityType serialization/dese…
summerhenson Apr 8, 2025
9aaa583
Change some comments in models
summerhenson Apr 8, 2025
a5591ee
Fix some bugs in operation tree deserialization
summerhenson Apr 8, 2025
3f3d8e7
Test creation of operation trees
summerhenson Apr 8, 2025
98e89f8
Test creating a quantity with no operations performed on it
summerhenson Apr 8, 2025
e4493ef
Test creating an operation tree with an invalid operation
summerhenson Apr 8, 2025
d354c50
Store quantity label as part of quantity
summerhenson Apr 8, 2025
c09bd4b
Customize OperationTree serialization from database representation
summerhenson Apr 8, 2025
5cfa223
Test GET with unary operation
summerhenson Apr 8, 2025
1a48b71
More tests for GET with operation trees
summerhenson Apr 8, 2025
41d9b18
Fix minor bug in OperationTree tests
summerhenson Apr 8, 2025
bde881f
Comments and planning for OperationTree testing
summerhenson Apr 9, 2025
d5b11da
Reorganize OperationTree tests and move to dedicated file
summerhenson Apr 9, 2025
71cb994
Tests for tensor product operation
summerhenson Apr 9, 2025
1889498
Validate nested operations and check parameters based on type
summerhenson Apr 9, 2025
9c8485d
Test creating invalid non-top-level operation fails
summerhenson Apr 9, 2025
5641b34
Separate class for invalid operation tree testing
summerhenson Apr 10, 2025
afcc0a5
Check operation trees only in operation tree get tests
summerhenson Apr 10, 2025
3272253
Test creating operations with missing parameters fails
summerhenson Apr 10, 2025
d37c38f
Test creating a quantity with no history
summerhenson Apr 10, 2025
a21e1ae
Check whether deleting a dataset deletes its quantities (it doesn't) …
summerhenson Apr 10, 2025
13ea044
Test whether deleting a dataset/its quantities deletes operations (it…
summerhenson Apr 10, 2025
cd626bb
Try switching from many-to-many to one-to-many relationship for DataS…
summerhenson Apr 10, 2025
015ae99
Change operations test setup to account for altered model relationship
summerhenson Apr 10, 2025
5e6b1ef
Remove dataset id from serialized quantity
summerhenson Apr 10, 2025
c6d8d67
Prevent deleting parent operations instead of cascading
summerhenson Apr 10, 2025
a9d7d6c
Automatically delete OperationTrees when quantities are deleted
summerhenson Apr 10, 2025
02c44be
Test nested OperationTree instances are deleted
summerhenson Apr 10, 2025
47d8006
Change direction of DataSet/MetaData relationship for automatic deletion
summerhenson Apr 11, 2025
8605d8f
Change direction of Quantity/OperationTree relationship for automatic…
summerhenson Apr 11, 2025
1a4c28e
Change direction of Session/DataSet relationship for automatic deletion
summerhenson Apr 11, 2025
542d489
Change direction of Session/PublishedState relationship for automatic…
summerhenson Apr 11, 2025
b174b3f
Change direction of OperationTree parent-child links for automatic de…
summerhenson Apr 11, 2025
2718c4b
Serializer for session
summerhenson Apr 11, 2025
ab5ad16
Get method for Sessions
summerhenson Apr 11, 2025
3fd6091
Return is_public in access management GET requests
summerhenson Apr 14, 2025
1ea1c9e
Remove dataset id from MetaData instance serialization
summerhenson Apr 14, 2025
9d1a925
Test GET dataset with metadata
summerhenson Apr 14, 2025
5569a32
Add comments to serializer classes
summerhenson Apr 14, 2025
afb2a3b
Fix serialization of DataSet with files
summerhenson Apr 14, 2025
b695602
Check access to files in a dataset
summerhenson Apr 14, 2025
0b6a5e4
Test DataSet creation with files
summerhenson Apr 14, 2025
5964cdf
Filter files in dataset by access
summerhenson Apr 14, 2025
5730ec9
Test loading dataset with files
summerhenson Apr 14, 2025
2e5b3e1
Start session tests
summerhenson Apr 14, 2025
281bd45
Copy session is_public value to composing datasets
summerhenson Apr 14, 2025
75c64fb
Test listing sessions
summerhenson Apr 14, 2025
3d24ec1
Fix bugs in DataSet creation nested in a Session
summerhenson Apr 15, 2025
954ec48
Include username and authentication status in all post responses
summerhenson Apr 15, 2025
9244550
Disallow creating private sessions without an owner
summerhenson Apr 15, 2025
58cbc1a
Test Session post method
summerhenson Apr 15, 2025
0789f1b
Use the right serializer for sessions and return id with get
summerhenson Apr 15, 2025
0cfa6ea
Test get method for individual sessions
summerhenson Apr 15, 2025
a1a4a67
Test put method for individual sessions
summerhenson Apr 15, 2025
7f5a6e3
Test Session delete method
summerhenson Apr 15, 2025
62a7b2c
Propagate access changes from session to composing datasets
summerhenson Apr 15, 2025
b29913c
Test Session access management
summerhenson Apr 15, 2025
66d4e78
Return current_user as username not id
summerhenson Apr 16, 2025
756cf59
Comments of session testing
summerhenson Apr 16, 2025
ccbb2ae
Add field for history references to Quantity
summerhenson Apr 16, 2025
6a63374
Serialization for Quantity variable references
summerhenson Apr 16, 2025
3ee37ab
Change serialization of QuantityHistory references to match API
summerhenson Apr 16, 2025
bfdaad3
Serialize Quantity operation_tree and references as history
summerhenson Apr 16, 2025
5bae9a1
Remove infinite serialization loop of quantities and histories
summerhenson Apr 16, 2025
c6eaecc
Separate model for history reference quantities
summerhenson Apr 16, 2025
7860fd5
Test references in quantity history
summerhenson Apr 16, 2025
66be25a
Add tests to test updating a DataSet
summerhenson Apr 16, 2025
9569b17
Propagate update to session is_public to datasets
summerhenson Apr 16, 2025
8223a4a
PublishedState serialization and minor serializer create method simpl…
summerhenson Apr 17, 2025
d406a43
Outline of PublishedState views
summerhenson Apr 17, 2025
cb8447c
PublishedState list method
summerhenson Apr 17, 2025
dd8e493
Serializer to restrict PublishedState update to published field
summerhenson Apr 17, 2025
db6de1f
Post method for PublishedState
summerhenson Apr 17, 2025
fef2ef1
Get method for single PublishedState
summerhenson Apr 17, 2025
75da757
Update method for PublishedState
summerhenson Apr 17, 2025
8e3407e
Delete method for PublishedState
summerhenson Apr 17, 2025
54ad406
Planning for PublishedState testing
summerhenson Apr 17, 2025
f84cd11
PublishedState urls
summerhenson Apr 17, 2025
c104d0a
Test listing published states
summerhenson Apr 17, 2025
b8b71bb
Fix bugs in PublishedState creation
summerhenson Apr 17, 2025
9cc8ef0
Check that session doesn't already have a published state
summerhenson Apr 17, 2025
fec53f6
Test creating a published state
summerhenson Apr 17, 2025
aae2793
Add fields to PublishedState get response
summerhenson Apr 17, 2025
3b90189
Test individual PublishedState get method
summerhenson Apr 17, 2025
2a648f4
Test PublishedState update method
summerhenson Apr 17, 2025
517c889
Test PublishedState delete method
summerhenson Apr 17, 2025
ec735ca
Session creation example script
summerhenson Apr 21, 2025
24cacd6
Add models to admin interface
summerhenson Apr 21, 2025
a56c55e
Account for json strings in post requests
summerhenson Apr 21, 2025
dfc415a
Enable session-based authentication
summerhenson Apr 21, 2025
bf9b3bf
Comments for PublishedState tests
summerhenson Apr 21, 2025
b06e244
Test that metadata is required for dataset creation
summerhenson Apr 21, 2025
dc84d8d
Minor changes suggested by Jeff
summerhenson Apr 21, 2025
8b03812
Nested PublishedState update in Session
summerhenson Apr 21, 2025
3f314b3
Test nested PublishedState
summerhenson Apr 21, 2025
e0c810f
Test listing published states by username
summerhenson Apr 22, 2025
b0a8a0d
Deserialization methods for sasdata structures
summerhenson Apr 22, 2025
11b203d
ruff formatting changes
krzywon Jun 3, 2026
38ebaad
merge refactor_24 into sasdata-database-cherry-pick-merge and resolve…
krzywon Jun 3, 2026
58f703e
ruff fixes
krzywon Jun 3, 2026
a933ba2
ruff fixes
krzywon Jun 3, 2026
4e9db5a
merge refactor_24 into sasdata-database-merge and resolve conflicts
krzywon Jun 3, 2026
e0a2bd1
Update fair-database package to make it match the head for the sasvie…
krzywon Jun 4, 2026
e9814ba
Bring refactoring work up-to-date in database branch manually
krzywon Jun 4, 2026
acc4a6f
Keep whitespace in test file to ensure testing succeeds
krzywon Jun 4, 2026
d6aeda2
Refactors Quantity to have a standard error property (#215)
DrPaulSharp Jun 15, 2026
0d5dde8
Refactor averaging.py and manipulations.py to use quantities (#207)
DrPaulSharp Jun 29, 2026
d22b23d
Update refactor roadmap
DrPaulSharp Jul 20, 2026
ed77cda
Merge refactor_24 into sasdata-database-merged and resolve conflicts
krzywon Jul 24, 2026
f8cefbc
Merge pull request #213 from SasView/sasdata-database-merged
krzywon Jul 27, 2026
dc51023
Add Abscissa class (#220)
DrPaulSharp Aug 20, 2026
80b0e96
Adds new tests for the Trend class and addresses review comments from…
gonzalezma Jun 11, 2026
ef38d6b
Restore old behaviour.
jamescrake-merani Sep 4, 2026
2d8b091
[pre-commit.ci lite] apply automatic fixes for ruff linting errors
pre-commit-ci-lite[bot] Sep 4, 2026
a56acd6
Merge pull request #216 from SasView/refactor_24_trend_new
krzywon Sep 4, 2026
251bf84
Get the trend value for individual data.
jamescrake-merani Sep 4, 2026
0893a69
Some docstrings for functions.
jamescrake-merani Sep 4, 2026
abf349b
If there's only zero, or one data, return true
jamescrake-merani Sep 4, 2026
32d91b0
Create data IO project structure
krzywon Sep 15, 2026
06b5459
Create base import and export files that will act as the basis for fi…
krzywon Sep 15, 2026
6d3928b
Add the base Import class that all importers will inherit from
krzywon Sep 15, 2026
c8584e9
Move all 'temp' readers into the data_io/import package
krzywon Sep 15, 2026
29200d4
Rename all 'temp' readers to the format 'import_<filetype>'
krzywon Sep 15, 2026
35c0fde
Rename packages from import and export to importers and exporters to …
krzywon Sep 15, 2026
2b0878e
Update references to importers so all unit tests pass
krzywon Sep 15, 2026
f80f036
Move named trend into sasdata.
jamescrake-merani Sep 16, 2026
4f1cb5c
Move this to the bottom.
jamescrake-merani Sep 16, 2026
b6d9683
Move all test data files into a single, discoverable directory to mim…
krzywon Sep 16, 2026
c741f9b
Add the test directory to the python path when running pytest
krzywon Sep 16, 2026
143a5e9
Update all unit tests to import files from the test.test_files path
krzywon Sep 16, 2026
cf29b4e
import -> importer and Import -> Importer
krzywon Sep 16, 2026
786a9c6
export -> exporter and Export -> Exporter
krzywon Sep 16, 2026
7dcc406
Rename exporter package to exporters
krzywon Sep 16, 2026
9a45ce6
Define __all__ for data_io.importers package
krzywon Sep 16, 2026
56586fa
Create base import method in Importer class
krzywon Sep 16, 2026
017d472
Update type hints for importers to allow pathlib.Path objects
krzywon Sep 17, 2026
067a1cb
Remove TODO from ascii
krzywon Sep 17, 2026
cf656a3
Guess the file importer based on the file mime type, defaulting to th…
krzywon Sep 17, 2026
2647396
Ensure zip_longest parameter fillvalue has a logical value
krzywon Sep 17, 2026
f9cdd8f
Create a basic unit test for the base importer class that imports dat…
krzywon Sep 17, 2026
eb73561
Default unit for Phi to be in degrees.
jamescrake-merani Sep 18, 2026
8c655c0
Add phi to unit kinds as well.
jamescrake-merani Sep 18, 2026
14f99a2
Fixed expected order of SESANS.
jamescrake-merani Sep 18, 2026
1bd190d
Fixes to importer class to ensure sasmeasurements and errors are sepa…
krzywon Sep 18, 2026
32eed9b
Create a basic unit test for the generic importer module - failing on…
krzywon Sep 18, 2026
b18b487
Remove duplicate test files from test_files/data and trend_test_data,…
krzywon Sep 18, 2026
3daafd8
Find moved data in correct location
krzywon Sep 18, 2026
ac82f0a
Remove duplicate line for loading data
krzywon Sep 18, 2026
ccd1b50
Update utest_trend.py to use new data locations for test data files
krzywon Sep 18, 2026
159d8cb
Move test data files from fileconverter and manipulations test direct…
krzywon Sep 18, 2026
d66607e
Update fileconverter tests to use new test_files data directory
krzywon Sep 18, 2026
8750fad
update manipulations tests to use local_data_finder instead of the pr…
krzywon Sep 18, 2026
1d7042d
Add a deprecation warning to Importer class
krzywon Sep 18, 2026
1b98a6c
Add file errors to the errors list on import
krzywon Sep 18, 2026
f5f0371
Merge pull request #227 from SasView/refactor_24_trend_improvements
krzywon Sep 21, 2026
82bfa2b
Merge pull request #236 from SasView/refactor_24_angle_default_unit
jamescrake-merani Sep 21, 2026
55b353e
Add a class for magnetic.
jamescrake-merani Sep 22, 2026
a3a6c44
Implemented single_line_desc.
jamescrake-merani Sep 23, 2026
9ea75f1
More specific type hints.
jamescrake-merani Sep 23, 2026
7ec7230
Implement summary.
jamescrake-merani Sep 23, 2026
1527270
Make these fields optional.
jamescrake-merani Sep 23, 2026
3fbc324
Implement from_json.
jamescrake-merani Sep 23, 2026
5c60e3a
Implement as h5 function.
jamescrake-merani Sep 23, 2026
e8a0a36
Fix some metadata instantiation that broke.
jamescrake-merani Sep 23, 2026
f1fe3e6
More fixes to stop the tests from breaking.
jamescrake-merani Sep 23, 2026
d6b9c7b
Merge pull request #245 from SasView/refactor_24_magnetic_metadata
jamescrake-merani Sep 28, 2026
a0a0bf9
Merge branch 'refactor_24' into refactor_24_231_io_reorg
krzywon Oct 7, 2026
3bf1801
Merge branch 'refactor_24_231_io_reorg' into refactor_24_central_io_c…
krzywon Oct 7, 2026
28b453d
Merge pull request #237 from SasView/refactor_24_central_io_classes
krzywon Oct 15, 2026
ce48485
Allow SasData, and SasMeasurement to be instantiated without metadata…
jamescrake-merani Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add Abscissa class (#220)
* Adds the "Abscissa" class

* Implements new SasData structure and fixes tests

* Implements abscissa object

* Refactors "deduce_qz" routine

* Reformatting files

* Adds test cases for SasMeasurement class

---------

Co-authored-by: lucas-wilkins <lucas.wilkins@stfc.ac.uk>
  • Loading branch information
Paul Sharp and lucas-wilkins authored Aug 20, 2026
commit dc510234638dd2b2fb8fe62178b7d1397fcc9338
28 changes: 25 additions & 3 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
import pytest

from sasdata.metadata import Instrument, Metadata, Source
from sasdata.quantities.quantity import Quantity
from sasdata.quantities.units import angstroms


def pytest_addoption(parser):
parser.addoption(
"--show_plots", action="store_true", default=False, help="Display diagnostic plots during tests"
)
parser.addoption("--show_plots", action="store_true", default=False, help="Display diagnostic plots during tests")


@pytest.fixture
def show_plots(request):
return request.config.getoption("--show_plots")


@pytest.fixture
def basic_metadata():
"""A minimal metadata object."""
wavelength = Quantity(1.0, angstroms)
source = Source(
radiation=None,
beam_shape=None,
beam_size=None,
wavelength=wavelength,
wavelength_max=None,
wavelength_min=None,
wavelength_spread=None,
)
instrument = Instrument(collimations=[], source=source, detector=[])
metadata = Metadata(title=None, run=[], definition=None, process=[], sample=None, instrument=instrument, raw=None)

return metadata
121 changes: 121 additions & 0 deletions sasdata/abscissa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
from abc import ABC, abstractmethod

import numpy as np
from numpy._typing import ArrayLike

from sasdata.exceptions import InterpretationError
from sasdata.quantities.quantity import Quantity
from sasdata.util import is_increasing


class Abscissa(ABC):
def __init__(self, axes: list[Quantity]):
self._axes = axes
self._dimensionality = len(axes)

@property
def dimensionality(self) -> int:
"""Dimensionality of this data"""
return self._dimensionality

@property
@abstractmethod
def is_grid(self) -> bool:
"""Are these coordinates using a grid representation
(as opposed to a general list representation)

is_grid = True: implies that the corresponding ordinate is n-dimensional tensor
is_grid = False: implies that the corresponding ordinate is a 1D list

If the data is one dimensional, is_grid=True
"""

@property
def axes(self) -> list[Quantity]:
"""Axes of the data:

If it's an (n1-by-n2-by-n3...) grid (is_grid=True): give the values for each axis, returning a list like
[Quantity(length n1), Quantity(length n2), Quantity(length n3) ... ]

If it is not grid data (is_grid=False), but n points on a general mesh, give one array for each dimension
[Quantity(length n), Quantity(length n), Quantity(length n) ... ]
"""
return self._axes

@staticmethod
def _determine_error_message(axis_arrays: list[np.ndarray], ordinate_shape: tuple):
"""Error message for the `.determine` function"""

shape_string = ", ".join([str(axis.shape) for axis in axis_arrays])

return f"Cannot interpret array shapes axis: [{shape_string}], ordinate: {ordinate_shape}"

@staticmethod
def determine(axis_data: list[Quantity[ArrayLike]], ordinate_data: Quantity[ArrayLike]) -> "Abscissa":
"""Get an Abscissa object that fits the combination of axes and data"""

# Different posibilites:
# 1: axes_data[i].shape == axes_data[j].shape == ordinate_data.shape
# 1a: axis_data[i] is 1D =>
# 1a-i: len(axes_data) == 1 => Grid type or Scatter type depending on sortedness
# 1a-ii: len(axes_data) != 1 => Scatter type
# 1b: axis_data[i] dimensionality matches len(axis_data) => Meshgrid type
# 1c: other => Error
# 2: (len(axes_data[0]), len(axes_data[1])... ) == ordinate_data.shape => Grid type
# 3: None of the above => Error

ordinate_shape = np.array(ordinate_data.value).shape
axis_arrays = [np.array(axis.value) for axis in axis_data]

# 1:
if all([axis.shape == ordinate_shape for axis in axis_arrays]):
# 1a:
if all([len(axis.shape) == 1 for axis in axis_arrays]):
# 1a-i:
if len(axis_arrays) == 1:
# Is it sorted
if is_increasing(axis_arrays[0]):
return GridAbscissa(axis_data)
else:
return ScatterAbscissa(axis_data)
# 1a-ii
else:
return ScatterAbscissa(axis_data)
# 1b
elif all([len(axis.shape) == len(axis_arrays) for axis in axis_arrays]):
return MeshgridAbscissa(axis_data)

else:
raise InterpretationError(Abscissa._determine_error_message(axis_arrays, ordinate_shape))

elif (
all([len(axis.shape) == 1 for axis in axis_arrays])
and tuple([axis.shape[0] for axis in axis_arrays]) == ordinate_shape
):
# Require that they are sorted
if all([is_increasing(axis) for axis in axis_arrays]):
return GridAbscissa(axis_data)

else:
raise InterpretationError("Grid axes are not sorted")

else:
raise InterpretationError(Abscissa._determine_error_message(axis_arrays, ordinate_shape))


class GridAbscissa(Abscissa):
@property
def is_grid(self):
return True


class MeshgridAbscissa(Abscissa):
@property
def is_grid(self):
return True


class ScatterAbscissa(Abscissa):
@property
def is_grid(self):
return False
112 changes: 75 additions & 37 deletions sasdata/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,66 @@
from h5py._hl.group import Group as HDF5Group

from sasdata import dataset_types
from sasdata.abscissa import Abscissa
from sasdata.dataset_types import DatasetType
from sasdata.metadata import Metadata, MetadataEncoder
from sasdata.metadata import DerivedMetadata, Metadata, MetadataEncoder
from sasdata.quantities.quantity import Quantity


class SasData:
"""General object containing data in the SasView ecosystem"""

def __init__(
self,
name: str,
ordinate: Quantity,
abscissae: Abscissa,
mask: Quantity,
dependents: list["SasData"],
metadata: Metadata,
):
self.name = name
self._ordinate = ordinate
self._abscissae = abscissae
self._mask = mask
self.dependents = dependents
self.metadata = metadata

@property
def ordinate(self) -> Quantity:
return self._ordinate

@property
def abscissae(self) -> Abscissa:
return self._abscissae

@property
def mask(self) -> Quantity:
return self._mask

def scatter_data(self):
"""Return data in the coordinate/value form [(x1, x2, x3, y)...]"""


class SasDerivedMeasurement(SasData):
"""General object sas measurement that has not come directly from a file,
for example, the difference between two datasets"""

def __init__(
self,
name: str,
ordinate: Quantity,
abscissae: Abscissa,
mask: Quantity,
dependents: list["SasData"],
metadata: DerivedMetadata,
):
super().__init__(
name=name, ordinate=ordinate, abscissae=abscissae, mask=mask, dependents=dependents, metadata=metadata
)


class SasMeasurement(SasData):
def __init__(
self,
name: str,
Expand All @@ -34,52 +88,37 @@ def __init__(
self.dataset_type: DatasetType = dataset_type

# Components that need to be organised after creation
self.mask = None # TODO: fill out
self._mask = None # TODO: fill out
self.model_requirements = None # TODO: fill out

# TODO: Handle the other data types.
@property
def ordinate(self) -> Quantity:
match self.dataset_type:
case (dataset_types.one_dim |
dataset_types.two_dim |
dataset_types.angle_dim):
case dataset_types.one_dim | dataset_types.two_dim | dataset_types.three_dim | dataset_types.angle_dim:
return self._data_contents["I"]
case dataset_types.sesans:
return self._data_contents["Depolarisation"]
case _:
return None

@property
def abscissae(self) -> Quantity:
def abscissae(self) -> Abscissa:
match self.dataset_type:
case dataset_types.one_dim:
return self._data_contents["Q"]
return Abscissa.determine([self._data_contents["Q"]], self.ordinate)
case dataset_types.two_dim:
# Type hinting is a bit lacking. Assume each part of the zip is a scalar value.
data_contents = np.array(
list(
zip(
self._data_contents["Qx"].value,
self._data_contents["Qy"].value,
)
)
)
# Use this value to extract units etc. Assume they will be the same for Qy.
reference_data_content = self._data_contents["Qx"]
# TODO: If this is a derived quantity then we are going to lose that
# information.
#
# TODO: Won't work when there's errors involved. On reflection, we
# probably want to avoid creating a new Quantity but at the moment I
# can't see a way around it.
return Quantity(data_contents, reference_data_content.units, name=self._data_contents["Qx"].name, id_header=self._data_contents["Qx"]._id_header)
return Abscissa.determine([self._data_contents["Qx"], self._data_contents["Qy"]], self.ordinate)
case dataset_types.angle_dim:
return self._data_contents["Phi"]
return Abscissa.determine([self._data_contents["Phi"]], self.ordinate)
case dataset_types.three_dim:
return Abscissa.determine(
[self._data_contents["Qx"], self._data_contents["Qy"], self._data_contents["Qz"]], self.ordinate
)
case dataset_types.sesans:
return self._data_contents["SpinEchoLength"]
return Abscissa.determine([self._data_contents["SpinEchoLength"]], self.ordinate)
case _:
None
return None

def __getitem__(self, item: str):
return self._data_contents[item]
Expand All @@ -98,7 +137,7 @@ def summary(self, indent=" "):

@staticmethod
def from_json(obj):
return SasData(
return SasMeasurement(
name=obj["name"],
dataset_type=DatasetType(
name=obj["type"]["name"],
Expand All @@ -121,12 +160,11 @@ def _save_h5(self, sasentry: HDF5Group):
for idx, (key, sasdata) in enumerate(self._data_contents.items()):
sasdata.as_h5(group, key)


@staticmethod
def save_h5(data: dict[str, typing.Self], path: str | typing.BinaryIO):
with h5py.File(path, "w") as f:
for idx, (key, data) in enumerate(data.items()):
sasentry = f.create_group(f"sasentry{idx+1:02d}")
sasentry = f.create_group(f"sasentry{idx + 1:02d}")
if not key.startswith("sasentry"):
sasentry.attrs["sasview_key"] = key
data._save_h5(sasentry)
Expand All @@ -140,7 +178,7 @@ def deserialise(data: str) -> "SasData":
def deserialise_json(json_data: dict) -> "SasData":
name = json_data["name"]
data_contents = {}
dataset_type = json_data["dataset_type"] # TODO: update when DatasetType is more finalized
dataset_type = json_data["dataset_type"] # TODO: update when DatasetType is more finalized
metadata = json_data["metadata"].deserialise_json()
for quantity in json_data["data_contents"]:
data_contents[quantity["label"]] = Quantity.deserialise_json(quantity)
Expand All @@ -159,11 +197,11 @@ def _serialise_json(self) -> dict[str, Any]:
return {
"name": self.name,
"data_contents": data,
"dataset_type": None, # TODO: update when DatasetType is more finalized
"dataset_type": None, # TODO: update when DatasetType is more finalized
"verbose": self._verbose,
"metadata": self.metadata.serialise_json(),
"mask": {},
"model_requirements": {}
"model_requirements": {},
}


Expand Down Expand Up @@ -210,16 +248,16 @@ def sasdata_reader2D_converter(data2d: SasData | None = None) -> SasData:
qx_data = new_x.flatten()
qy_data = new_y.flatten()
err_data = np.sqrt(data2d._data_contents["I"].variance.value)
if not data2d._data_contents["I"].has_variance or np.any(err_data <= 0):
if not data2d._data_contents["I"].has_error or np.any(err_data <= 0):
new_err_data = np.sqrt(np.abs(new_data))
else:
new_err_data = err_data.flatten()
mask = np.ones(len(new_data), dtype=bool)

data2d._data_contents["I"].value = new_data
data2d._data_contents["I"].variance.value = new_err_data ** 2
data2d._data_contents["I"].variance.value = new_err_data**2
data2d._data_contents["Qx"].value = qx_data
data2d._data_contents["Qy"].value = qy_data
data2d.mask = mask
data2d._mask = mask

return data2d
Loading
Loading