Skip to content

Add re-flagging based on multiple filters#30

Merged
emmleroy merged 23 commits into
emmleroy-v1.0.0from
emmleroy-sc-20242-reflagging-v2
Jul 8, 2026
Merged

Add re-flagging based on multiple filters#30
emmleroy merged 23 commits into
emmleroy-v1.0.0from
emmleroy-sc-20242-reflagging-v2

Conversation

@emmleroy

@emmleroy emmleroy commented Jun 26, 2026

Copy link
Copy Markdown

Summary

This PR adds re-flagging of QuantAQ data based on multiple flag criteria (filters)

Changes

  • Remove arisense flagging functionality
  • Define FLAG_DEFINITIONS (flag names, flag bitmask values, and columns to nan) as a generic list of namedtuples common across all QuantAQ products
  • Define FLAG_CRITERIA as a nested dict that permits different flag criteria/logic for different data sources (rawSD, cloudAPI, database) and data models (modulair, modulair-pm, modulair-x, modulair-x-pm)
  • Infer data source from the dataframe timestamp frequency
  • Infer data model from the dataframe 'sn' column (added to rawSD dataframes at load)
  • Modify expunge.py and ports echo_flag_table() and flag_summary() from Isoprene
  • Add additional tests

Testing

  • Added additional tests in test_expunge.py
  • poetry run pytest --cov=./ --cov-report=xml -rP passes

Other notes

  • Re-flagging of rawSD card can be easily implemented, but the flag criteria/logic are not yet defined in variables.py (this will raise a NotImplementedError if attempting to re-flag rawSD card data for now)
  • Planning to remove support for feather files in favor of parquet in sc-20240
  • Planning to overhaul logging and convert to flatter file structure / library-first approach in sc-20240

@emmleroy emmleroy marked this pull request as draft June 26, 2026 16:07
@emmleroy emmleroy marked this pull request as ready for review June 26, 2026 16:08
@emmleroy emmleroy marked this pull request as draft June 26, 2026 16:08
@emmleroy emmleroy force-pushed the emmleroy-sc-20242-reflagging-v2 branch from cb24699 to 003d5ad Compare June 30, 2026 13:44
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.13305% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.49%. Comparing base (8b95643) to head (9e729a7).
⚠️ Report is 1 commits behind head on emmleroy-v1.0.0.

Files with missing lines Patch % Lines
quantaq_cli/console/commands/flag.py 90.00% 7 Missing ⚠️
quantaq_cli/utilities.py 84.44% 7 Missing ⚠️
quantaq_cli/variables.py 92.00% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@                 Coverage Diff                 @@
##           emmleroy-v1.0.0      #30      +/-   ##
===================================================
- Coverage            96.57%   95.49%   -1.08%     
===================================================
  Files                   17       18       +1     
  Lines                  846      932      +86     
===================================================
+ Hits                   817      890      +73     
- Misses                  29       42      +13     
Flag Coverage Δ
unittests 95.49% <93.13%> (-1.08%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
quantaq_cli/console/__init__.py 98.55% <100.00%> (-0.14%) ⬇️
quantaq_cli/console/commands/expunge.py 95.65% <100.00%> (-0.58%) ⬇️
quantaq_cli/console/commands/resample.py 94.93% <100.00%> (-1.27%) ⬇️
tests/test_expunge.py 100.00% <100.00%> (ø)
tests/test_flag.py 100.00% <ø> (ø)
tests/test_merge.py 100.00% <ø> (ø)
tests/test_resample.py 100.00% <ø> (ø)
tests/test_utilities.py 100.00% <100.00%> (ø)
quantaq_cli/variables.py 92.00% <92.00%> (-8.00%) ⬇️
quantaq_cli/console/commands/flag.py 90.69% <90.00%> (+2.60%) ⬆️
... and 1 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@emmleroy emmleroy marked this pull request as ready for review June 30, 2026 19:08
Comment thread quantaq_cli/variables.py Outdated
# i.e. are flag names and values different for database vs rawSD data?
FLAGS = {}

FLAGS["v100"] = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove all references to ARISense

@emmleroy emmleroy Jul 2, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this, as well as all tests for arisense data in 8162df4 (in PR #32)

df["flag"] = df["flag"].astype(int, errors='ignore')

# Drop NaNs
df = df.dropna(how='any', subset=["flag"])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely want to log this, as it should never occur (for future PR)

@emmleroy emmleroy Jul 2, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it! Added a logger.warning in 349b388 (in PR #32)

for item in data:
click.echo(item)

echo_flag_table(df)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be removed once we have logging implemented

from quantaq_cli.exceptions import InvalidFileExtension, InvalidArgument, InvalidDeviceModel


def add_flag(df, flag_name, flag_value, criterion):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make sure we add docstrings that describe types and what the purpose of the function is.

@emmleroy emmleroy Jul 2, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added google-style docstrings with types in 349b388 (in PR #32) but let me know if you'd like type hints as well!

tscol = determine_timestamp_column(df)

# Force timestamp type
df[tscol] = df[tscol].map(pd.to_datetime)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should check the type first and only do this if it's not already a datetime

@emmleroy emmleroy Jul 2, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, added helper function fix_timestamps() in 349b388 (in PR #32) which only forces the timestamp type if not already a datetime

Comment thread quantaq_cli/utilities.py
def infer_data_source(df):
# Determine the best timestamp column and sort
tscol = determine_timestamp_column(df)
df[tscol] = pd.to_datetime(df[tscol])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should only do this if needed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also have this in several places, so probably a good idea to create a helper function

@emmleroy emmleroy Jul 2, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added helper function fix_timestamps() in 349b388 (in PR #32) which only forces the timestamp type if not already a datetime

Comment thread quantaq_cli/utilities.py
has_1min = 60.0 in tdiffs
has_5sec = 5.0 in tdiffs

if has_1min and has_5sec:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, it's highly, highly likely that you're always going to have some sort of mixed tdiffs. It is likely rarer for you to encounter both 1min and 5s exactly, but it's definitely within the realm of possibility. We way want to be a bit more lenient and just look at the frequency of tdiffs? Similarly, the UFP data is 10s on the SD card, not 1min.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed this to most common tdiff in d838aaa (in PR#32) and added logging

Comment thread quantaq_cli/utilities.py
MOD-X-00993 -> modulair-x
MOD-X-PM-01685 -> modulair-x-pm
"""
prefix, _, _ = device_sn.rpartition("-")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this catch MOD-UFP-XXXXX? We should probably add to the docstring at minimum.

@emmleroy emmleroy Jul 2, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will! Added to docstring and tests in 2ca1564(PR#32)

Comment thread quantaq_cli/variables.py
Flag("FLAG_BAT", 2048, ["bat_voltage", "soc", "vbat"]),
]

SUPPORTED_MODELS = ("modulair", "modulair-x", "modulair-pm", "modulair-x-pm")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add modulair-ufp

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, will hold off for now until I add modulair-ufp flagging logic (at least for database/api data)

Comment thread quantaq_cli/variables.py
Range = namedtuple("Range", ["column", "lo", "hi"])
Gap = namedtuple("Gap", ["gap_in_seconds", "post_gap_flag_length_seconds"])

FLAG_CRITERIA = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be easiest to just go over the criteria before dumping too much time into this part. The SD and db sides are fairly different and the logic may be difficult to capture in this way, though I could be wrong.

@emmleroy emmleroy merged commit 9e729a7 into emmleroy-v1.0.0 Jul 8, 2026
6 of 8 checks passed
@emmleroy emmleroy deleted the emmleroy-sc-20242-reflagging-v2 branch July 9, 2026 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants