|
7 | 7 | import re |
8 | 8 | import warnings |
9 | 9 | import xml.etree.ElementTree |
10 | | -from xml.etree.ElementTree import Element |
11 | 10 |
|
12 | 11 | import numpy |
13 | 12 | import pandas |
@@ -409,28 +408,41 @@ def transform_into_filtertimeseries( |
409 | 408 | values = None |
410 | 409 | # test if any filterset is not available in measurements due to invalid data #issue24 |
411 | 410 | if filter_number not in measurements.index.get_level_values("filterset"): |
412 | | - logger.warn( |
| 411 | + logger.warning( |
413 | 412 | 'Skipped channel %s with name "%s" because no valid measurements are available.', |
414 | 413 | fs.filter_type, |
415 | 414 | fs.filter_name, |
416 | 415 | ) |
417 | 416 | continue |
418 | | - elif fs.filter_type == "Intensity" and ("Biomass" in fs.filter_name or "BS" in fs.filter_name): |
| 417 | + |
| 418 | + dfm = measurements.xs(filter_number, level="filterset") |
| 419 | + # De-duplicate based on the index because in long-running experiments |
| 420 | + # the BioLector sometimes duplicates parts of the data. |
| 421 | + mask = dfm.index.duplicated(keep="first") |
| 422 | + if any(mask): |
| 423 | + logger.warning( |
| 424 | + "Duplicate filter %s measurements for (cycles, wells) %s.", |
| 425 | + filter_number, |
| 426 | + dfm[mask].index.to_list(), |
| 427 | + ) |
| 428 | + dfm = dfm[~mask] |
| 429 | + |
| 430 | + if fs.filter_type == "Intensity" and ("Biomass" in fs.filter_name or "BS" in fs.filter_name): |
419 | 431 | key = f"BS{int(fs.gain_1)}" |
420 | | - times = measurements.xs(filter_number, level="filterset")["time"].unstack() |
421 | | - values = measurements.xs(filter_number, level="filterset")["amp_ref_1"].unstack() |
| 432 | + times = dfm["time"].unstack() |
| 433 | + values = dfm["amp_ref_1"].unstack() |
422 | 434 | elif fs.filter_type in {"pH", "DO"} and not return_uncalibrated_optode_data: |
423 | 435 | key = fs.filter_type |
424 | | - times = measurements.xs(filter_number, level="filterset")["time"].unstack() |
425 | | - values = measurements.xs(filter_number, level="filterset")["cal"].unstack() |
| 436 | + times = dfm["time"].unstack() |
| 437 | + values = dfm["cal"].unstack() |
426 | 438 | elif fs.filter_type in {"pH", "DO"} and return_uncalibrated_optode_data: |
427 | 439 | key = fs.filter_type |
428 | | - times = measurements.xs(filter_number, level="filterset")["time"].unstack() |
429 | | - values = measurements.xs(filter_number, level="filterset")["phase"].unstack() |
| 440 | + times = dfm["time"].unstack() |
| 441 | + values = dfm["phase"].unstack() |
430 | 442 | elif fs.filter_type == "Intensity": |
431 | 443 | key = fs.filter_name |
432 | | - times = measurements.xs(filter_number, level="filterset")["time"].unstack() |
433 | | - values = measurements.xs(filter_number, level="filterset")["amp_ref_1"].unstack() |
| 444 | + times = dfm["time"].unstack() |
| 445 | + values = dfm["amp_ref_1"].unstack() |
434 | 446 | else: |
435 | 447 | logger.warn( |
436 | 448 | f'Skipped {fs.filter_type} channel with name "{fs.filter_name}" because no processing routine is implemented.' |
|
0 commit comments