-
Notifications
You must be signed in to change notification settings - Fork 1
Allow low frequency waveform data into parquet #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
aaee72c
Document current Emap-Interchange ingress behaviour + link to HL7 replay
jeremyestein 3532927
Update fake data to be more realistic, check the happy path a bit more
jeremyestein accde07
Understand the different types of incoming waveform interchange message.
jeremyestein 6b3aed8
Check the CSV file contents. Implement writing low- or high- freq CSVs.
jeremyestein 124d37f
Simplify the CSV output format so that it's the same between LF and HF,
jeremyestein 8b9496b
Use JSON arrays in CSV
jeremyestein 4043060
Extend LF data into parquet
jeremyestein 5912b4f
Be consistent on line endings (LF everywhere)
jeremyestein 6ab262c
Sort parquets by timestamp and enable more stats to hopefully speed up
jeremyestein 7d89e46
Make some timestamps fractional so we can be sure there's no rounding
jeremyestein b50d167
Merge branch 'dev' into jeremy/low-freq
jeremyestein 6d67734
Upgrade uv in the Docker image
jeremyestein a6995cd
Reject messages with both string and numeric values
jeremyestein 0f66a8c
Allow small drops in coverage (which is an artifact of the way we run
jeremyestein File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| coverage: | ||
| status: | ||
| project: | ||
| default: | ||
| target: auto | ||
| threshold: 5% |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # Reading from the rabbitmq queue | ||
|
|
||
| The waveform-controller container will process messages on a rabbitmq queue that | ||
| are JSON representations of the Emap-Interchange message types | ||
| `WaveformMessage` and, imminently, `WaveformLowFreqMessage`. | ||
|
|
||
| As you can see from `test_controller.test_controller_callback`, the following actions are | ||
| expected in various error cases: | ||
|
|
||
| * **Bad data (eg. missing column)**: REJECT without requeue, because it's assumed the message will never work. | ||
| * **Postgress connection failed**: REJECT with requeue, because failure is assumed to be unrelated to the received message. | ||
| * **Patient has research opt-out set** REJECT without requeue |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| # Python version of interchange messages | ||
| # Ideally this would be generated automatically by the Java | ||
| # code as part of its build process, but for now it's just copied | ||
| # and modified | ||
| import json | ||
|
|
||
|
|
||
| class WaveformBaseMessage: | ||
| def __init__(self, data): | ||
| self.data = data | ||
|
|
||
| @staticmethod | ||
| def from_json(json_data) -> "WaveformBaseMessage": | ||
| data = json.loads(json_data) | ||
| message_type = data.get("@class") | ||
| message_cls: type | ||
| if ( | ||
| message_type | ||
| == "uk.ac.ucl.rits.inform.interchange.visit_observations.WaveformHighFreqMessage" | ||
| ): | ||
| message_cls = WaveformHighFreqMessage | ||
| elif ( | ||
| message_type | ||
| == "uk.ac.ucl.rits.inform.interchange.visit_observations.WaveformLowFreqMessage" | ||
| ): | ||
| message_cls = WaveformLowFreqMessage | ||
| else: | ||
| raise TypeError("Unknown message type {}".format(message_type)) | ||
|
|
||
| return message_cls(data) | ||
|
|
||
| def get_observation_time(self): | ||
| """Time of the observation.""" | ||
| return self.data["observationTime"] | ||
|
|
||
| def get_source_location_string(self): | ||
| """Location string according to the original data source.""" | ||
| return self.data["sourceLocationString"] | ||
|
|
||
| def get_mapped_location_string(self): | ||
| """Location string, mapped by the data source to the canonical Emap format, | ||
| which matches what we get from the main HL7 ADT feed.""" | ||
| return self.data["mappedLocationString"] | ||
|
|
||
| def get_source_observation_type(self): | ||
| """Do we want to be more specific here? | ||
|
|
||
| Eg. carescape, etc Eg. get from the CSV metadata and prefix with "waveform-" | ||
| """ | ||
| return self.data["sourceObservationType"] | ||
|
|
||
| def get_source_variable_id(self): | ||
| """Variable ID according to the source system. | ||
|
|
||
| Has previously been referred to as stream ID, so you may see that in some | ||
| places. | ||
| """ | ||
| return self.data["sourceVariableId"] | ||
|
|
||
| def get_mapped_variable_description(self): | ||
| """Variable (aka stream) description mapped by the data source.""" | ||
| return self.data["mappedVariableDescription"] | ||
|
|
||
| def get_unit(self): | ||
| """Unit of the measurement.""" | ||
| return self.data["unit"] | ||
|
|
||
|
|
||
| class WaveformHighFreqMessage(WaveformBaseMessage): | ||
| def get_source_channel_id(self): | ||
| """Channel ID according to the source system.""" | ||
| return self.data["sourceChannelId"] | ||
|
|
||
| def get_sampling_rate(self): | ||
| """Sampling rate in Hz.""" | ||
| return self.data["samplingRate"] | ||
|
|
||
| def get_numeric_values(self) -> list[float]: | ||
| """Numeric array as a list of floats.""" | ||
| return self.data["numericValues"]["value"] | ||
|
|
||
|
|
||
| class WaveformLowFreqMessage(WaveformBaseMessage): | ||
| def get_source_value(self): | ||
| """Unmapped value.""" | ||
| return self.data["sourceValue"]["value"] | ||
|
|
||
| def get_numeric_value(self) -> float: | ||
| """Mapped value, if it's a numerical value.""" | ||
| return self.data["numericValue"]["value"] | ||
|
|
||
| def get_string_value(self): | ||
| """Mapped value, if it's a string. | ||
|
|
||
| Also use for categorical, eg. "Flow Trig" | ||
| """ | ||
| return self.data["stringValue"]["value"] |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.