From ed2af593255984385302b0252067462c54573dc3 Mon Sep 17 00:00:00 2001 From: idalindegaard Date: Fri, 1 Mar 2024 16:01:53 +0100 Subject: [PATCH 1/5] new script calculate average concentration and cv --- cg_lims/EPPs/udf/calculate/base.py | 2 + .../calculate_saphyr_concentration.py | 63 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py diff --git a/cg_lims/EPPs/udf/calculate/base.py b/cg_lims/EPPs/udf/calculate/base.py index 84f08253..71c031b6 100644 --- a/cg_lims/EPPs/udf/calculate/base.py +++ b/cg_lims/EPPs/udf/calculate/base.py @@ -24,6 +24,7 @@ from cg_lims.EPPs.udf.calculate.twist_aliquot_amount import twist_aliquot_amount from cg_lims.EPPs.udf.calculate.twist_aliquot_volume import twist_aliquot_volume from cg_lims.EPPs.udf.calculate.twist_get_volumes_from_buffer import get_volumes_from_buffer +from cg_lims.EPPs.udf.calculate.calculate_saphyr_concentration import calculate_saphyr_concentration # commands from cg_lims.EPPs.udf.calculate.twist_pool import twist_pool @@ -56,3 +57,4 @@ def calculate(ctx): calculate.add_command(novaseq_x_volumes) calculate.add_command(pool_normalization) calculate.add_command(novaseq_x_denaturation) +calculate.add_command(calculate_saphyr_concentration) diff --git a/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py b/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py new file mode 100644 index 00000000..7bd0ae11 --- /dev/null +++ b/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py @@ -0,0 +1,63 @@ +import logging +import sys +from typing import List + +import click +import numpy as np +from cg_lims import options +from cg_lims.exceptions import LimsError, MissingUDFsError +from cg_lims.get.artifacts import get_artifacts +from genologics.entities import Artifact + +LOG = logging.getLogger(__name__) + +def get_concentration(artifact: Artifact) -> List[float]: + """Returns a list of all concentration replicates of an artifact.""" + + udf_names = ["Concentration 1 (ng/ul)", "Concentration 2 (ng/ul)", "Concentration 3 (ng/ul)"] + concentrations = [] + for name in udf_names: + concentrations.append(artifact.udf.get(name)) + return concentrations + +def calculate_average_concentration(concentrations: List) -> float: + """Returns the average concentration of the list concentrations""" + return np.mean(concentrations) + +def calculate_cv(concentrations: List) -> float: + """Calculates the coefficient of variance of the concentrations with the average concentration + that was retrieved from calculate_average_concentration""" + + average_concentration = np.mean(concentrations) + std_deviation = np.std(concentrations) + coefficient_variation = std_deviation / average_concentration + return coefficient_variation + +def set_average_and_cv(artifact: Artifact) -> None: + + concentrations = get_concentration(artifact=artifact) + average_concentration = calculate_average_concentration(concentrations=concentrations) + coefficient_variation = calculate_cv(concentrations=concentrations) + + artifact.udf["Average concentration (ng/ul)"] = average_concentration + artifact.udf["Coefficient of variation (CV)"] = coefficient_variation + artifact.put() + +@click.command() +@click.pass_context +def calculate_saphyr_concentration(ctx) -> None: + + LOG.info(f"Running {ctx.command_path} with params: {ctx.params}") + process = ctx.obj["process"] + + try: + artifacts: List[Artifact] = get_artifacts(process=process, measurement=True) + for artifact in artifacts: + set_average_and_cv(artifact=artifact) + message = "The average concentration and coefficient of variance have been calculated." + LOG.info(message) + click.echo(message) + except LimsError as e: + LOG.error(e.message) + sys.exit(e.message) + \ No newline at end of file From 9f9a892eedba856a80d63a84e00d9fe79880e407 Mon Sep 17 00:00:00 2001 From: idalindegaard Date: Tue, 19 Mar 2024 15:03:28 +0100 Subject: [PATCH 2/5] added exceptions to calc saphyr conc --- .../calculate_saphyr_concentration.py | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py b/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py index 7bd0ae11..30270005 100644 --- a/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py +++ b/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py @@ -12,8 +12,8 @@ LOG = logging.getLogger(__name__) def get_concentration(artifact: Artifact) -> List[float]: - """Returns a list of all concentration replicates of an artifact.""" - + """Returns a list of all concentration replicates called + Concentration 1 (ng/ul), Concentration 2 (ng/ul) and Concentration 3 (ng/ul) of an artifact.""" udf_names = ["Concentration 1 (ng/ul)", "Concentration 2 (ng/ul)", "Concentration 3 (ng/ul)"] concentrations = [] for name in udf_names: @@ -34,30 +34,50 @@ def calculate_cv(concentrations: List) -> float: return coefficient_variation def set_average_and_cv(artifact: Artifact) -> None: - + """Calls on the previous functions get_concentration, calculate_average_concentration and calculate_cv + and updates the udfs Average concentration (ng/ul) and Coefficient of variation (CV) with the calculated values""" concentrations = get_concentration(artifact=artifact) average_concentration = calculate_average_concentration(concentrations=concentrations) coefficient_variation = calculate_cv(concentrations=concentrations) artifact.udf["Average concentration (ng/ul)"] = average_concentration artifact.udf["Coefficient of variation (CV)"] = coefficient_variation + print(coefficient_variation) artifact.put() +def validate_udf_values(artifact: Artifact) -> bool: + """Write something""" + udf_names = ["Concentration 1 (ng/ul)", "Concentration 2 (ng/ul)", "Concentration 3 (ng/ul)"] + output = True + for name in udf_names: + if not artifact.udf.get(name) or artifact.udf.get(name) < 0: + output = False + LOG.info(f"Sample {artifact.samples[0].id} has an invalid concentration value for {name}. Skipping.") + return output + + @click.command() @click.pass_context def calculate_saphyr_concentration(ctx) -> None: + """Calculates and sets the average concentration and coefficient of variance based on three given concentrations. + Returns a message if this worked well""" LOG.info(f"Running {ctx.command_path} with params: {ctx.params}") process = ctx.obj["process"] try: artifacts: List[Artifact] = get_artifacts(process=process, measurement=True) + failed_samples = 0 for artifact in artifacts: + if validate_udf_values(artifact=artifact) == False: + failed_samples += 1 + continue set_average_and_cv(artifact=artifact) + if failed_samples: + raise MissingUDFsError(f"{failed_samples} samples have invalid concentration values (<= 0). See log for more information.") message = "The average concentration and coefficient of variance have been calculated." LOG.info(message) click.echo(message) except LimsError as e: LOG.error(e.message) sys.exit(e.message) - \ No newline at end of file From 9004f47782a1789e7aaf9be198e1eba8db1dd14c Mon Sep 17 00:00:00 2001 From: Ida Lindegaard <82438141+idalindegaard@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:02:24 +0100 Subject: [PATCH 3/5] updated information for some functions --- cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py b/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py index 30270005..697130b0 100644 --- a/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py +++ b/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py @@ -46,7 +46,8 @@ def set_average_and_cv(artifact: Artifact) -> None: artifact.put() def validate_udf_values(artifact: Artifact) -> bool: - """Write something""" + """A function checking whether a concentration in the list of concentrations for each artifact has a negative/no/zero value. + Then the function returns the output as 'False' and logs all those sample IDs in the EPP log""" udf_names = ["Concentration 1 (ng/ul)", "Concentration 2 (ng/ul)", "Concentration 3 (ng/ul)"] output = True for name in udf_names: @@ -60,7 +61,7 @@ def validate_udf_values(artifact: Artifact) -> bool: @click.pass_context def calculate_saphyr_concentration(ctx) -> None: """Calculates and sets the average concentration and coefficient of variance based on three given concentrations. - Returns a message if this worked well""" + Returns a message if this worked well, and if there were negative/no/zero concentration values, there's an error message for this""" LOG.info(f"Running {ctx.command_path} with params: {ctx.params}") process = ctx.obj["process"] From d545e7b560c0a896f3519b748c42903c62b744a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Sv=C3=A4rd?= Date: Tue, 26 Mar 2024 15:33:57 +0100 Subject: [PATCH 4/5] black and isort --- cg_lims/EPPs/udf/calculate/base.py | 2 +- .../calculate_saphyr_concentration.py | 31 +++++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/cg_lims/EPPs/udf/calculate/base.py b/cg_lims/EPPs/udf/calculate/base.py index 71c031b6..d7f1f2ec 100644 --- a/cg_lims/EPPs/udf/calculate/base.py +++ b/cg_lims/EPPs/udf/calculate/base.py @@ -12,6 +12,7 @@ from cg_lims.EPPs.udf.calculate.calculate_resuspension_buffer_volumes import ( calculate_resuspension_buffer_volume, ) +from cg_lims.EPPs.udf.calculate.calculate_saphyr_concentration import calculate_saphyr_concentration from cg_lims.EPPs.udf.calculate.calculate_water import volume_water from cg_lims.EPPs.udf.calculate.calculate_water_volume_rna import calculate_water_volume_rna from cg_lims.EPPs.udf.calculate.get_missing_reads import get_missing_reads @@ -24,7 +25,6 @@ from cg_lims.EPPs.udf.calculate.twist_aliquot_amount import twist_aliquot_amount from cg_lims.EPPs.udf.calculate.twist_aliquot_volume import twist_aliquot_volume from cg_lims.EPPs.udf.calculate.twist_get_volumes_from_buffer import get_volumes_from_buffer -from cg_lims.EPPs.udf.calculate.calculate_saphyr_concentration import calculate_saphyr_concentration # commands from cg_lims.EPPs.udf.calculate.twist_pool import twist_pool diff --git a/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py b/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py index 697130b0..c947bf42 100644 --- a/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py +++ b/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py @@ -11,8 +11,9 @@ LOG = logging.getLogger(__name__) -def get_concentration(artifact: Artifact) -> List[float]: - """Returns a list of all concentration replicates called + +def get_concentration(artifact: Artifact) -> List[float]: + """Returns a list of all concentration replicates called Concentration 1 (ng/ul), Concentration 2 (ng/ul) and Concentration 3 (ng/ul) of an artifact.""" udf_names = ["Concentration 1 (ng/ul)", "Concentration 2 (ng/ul)", "Concentration 3 (ng/ul)"] concentrations = [] @@ -20,31 +21,36 @@ def get_concentration(artifact: Artifact) -> List[float]: concentrations.append(artifact.udf.get(name)) return concentrations + def calculate_average_concentration(concentrations: List) -> float: """Returns the average concentration of the list concentrations""" return np.mean(concentrations) + def calculate_cv(concentrations: List) -> float: - """Calculates the coefficient of variance of the concentrations with the average concentration + """Calculates the coefficient of variance of the concentrations with the average concentration that was retrieved from calculate_average_concentration""" - + average_concentration = np.mean(concentrations) std_deviation = np.std(concentrations) coefficient_variation = std_deviation / average_concentration return coefficient_variation + def set_average_and_cv(artifact: Artifact) -> None: - """Calls on the previous functions get_concentration, calculate_average_concentration and calculate_cv - and updates the udfs Average concentration (ng/ul) and Coefficient of variation (CV) with the calculated values""" + """Calls on the previous functions get_concentration, calculate_average_concentration and calculate_cv + and updates the udfs Average concentration (ng/ul) and Coefficient of variation (CV) with the calculated values + """ concentrations = get_concentration(artifact=artifact) average_concentration = calculate_average_concentration(concentrations=concentrations) coefficient_variation = calculate_cv(concentrations=concentrations) - + artifact.udf["Average concentration (ng/ul)"] = average_concentration artifact.udf["Coefficient of variation (CV)"] = coefficient_variation print(coefficient_variation) artifact.put() + def validate_udf_values(artifact: Artifact) -> bool: """A function checking whether a concentration in the list of concentrations for each artifact has a negative/no/zero value. Then the function returns the output as 'False' and logs all those sample IDs in the EPP log""" @@ -53,7 +59,9 @@ def validate_udf_values(artifact: Artifact) -> bool: for name in udf_names: if not artifact.udf.get(name) or artifact.udf.get(name) < 0: output = False - LOG.info(f"Sample {artifact.samples[0].id} has an invalid concentration value for {name}. Skipping.") + LOG.info( + f"Sample {artifact.samples[0].id} has an invalid concentration value for {name}. Skipping." + ) return output @@ -61,7 +69,8 @@ def validate_udf_values(artifact: Artifact) -> bool: @click.pass_context def calculate_saphyr_concentration(ctx) -> None: """Calculates and sets the average concentration and coefficient of variance based on three given concentrations. - Returns a message if this worked well, and if there were negative/no/zero concentration values, there's an error message for this""" + Returns a message if this worked well, and if there were negative/no/zero concentration values, there's an error message for this + """ LOG.info(f"Running {ctx.command_path} with params: {ctx.params}") process = ctx.obj["process"] @@ -75,7 +84,9 @@ def calculate_saphyr_concentration(ctx) -> None: continue set_average_and_cv(artifact=artifact) if failed_samples: - raise MissingUDFsError(f"{failed_samples} samples have invalid concentration values (<= 0). See log for more information.") + raise MissingUDFsError( + f"{failed_samples} samples have invalid concentration values (<= 0). See log for more information." + ) message = "The average concentration and coefficient of variance have been calculated." LOG.info(message) click.echo(message) From 6646e5280aa02c4cf509cc79445cb33721ce8a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Sv=C3=A4rd?= Date: Tue, 26 Mar 2024 15:47:13 +0100 Subject: [PATCH 5/5] small changes --- .../calculate_saphyr_concentration.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py b/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py index c947bf42..ae5ae106 100644 --- a/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py +++ b/cg_lims/EPPs/udf/calculate/calculate_saphyr_concentration.py @@ -4,7 +4,6 @@ import click import numpy as np -from cg_lims import options from cg_lims.exceptions import LimsError, MissingUDFsError from cg_lims.get.artifacts import get_artifacts from genologics.entities import Artifact @@ -12,7 +11,7 @@ LOG = logging.getLogger(__name__) -def get_concentration(artifact: Artifact) -> List[float]: +def get_concentrations(artifact: Artifact) -> List[float]: """Returns a list of all concentration replicates called Concentration 1 (ng/ul), Concentration 2 (ng/ul) and Concentration 3 (ng/ul) of an artifact.""" udf_names = ["Concentration 1 (ng/ul)", "Concentration 2 (ng/ul)", "Concentration 3 (ng/ul)"] @@ -22,15 +21,14 @@ def get_concentration(artifact: Artifact) -> List[float]: return concentrations -def calculate_average_concentration(concentrations: List) -> float: +def calculate_average_concentration(concentrations: List[float]) -> float: """Returns the average concentration of the list concentrations""" - return np.mean(concentrations) + return float(np.mean(concentrations)) -def calculate_cv(concentrations: List) -> float: +def calculate_cv(concentrations: List[float]) -> float: """Calculates the coefficient of variance of the concentrations with the average concentration that was retrieved from calculate_average_concentration""" - average_concentration = np.mean(concentrations) std_deviation = np.std(concentrations) coefficient_variation = std_deviation / average_concentration @@ -39,15 +37,14 @@ def calculate_cv(concentrations: List) -> float: def set_average_and_cv(artifact: Artifact) -> None: """Calls on the previous functions get_concentration, calculate_average_concentration and calculate_cv - and updates the udfs Average concentration (ng/ul) and Coefficient of variation (CV) with the calculated values + and updates the UDFs Average concentration (ng/ul) and Coefficient of variation (CV) with the calculated values """ - concentrations = get_concentration(artifact=artifact) + concentrations = get_concentrations(artifact=artifact) average_concentration = calculate_average_concentration(concentrations=concentrations) coefficient_variation = calculate_cv(concentrations=concentrations) artifact.udf["Average concentration (ng/ul)"] = average_concentration artifact.udf["Coefficient of variation (CV)"] = coefficient_variation - print(coefficient_variation) artifact.put() @@ -79,7 +76,7 @@ def calculate_saphyr_concentration(ctx) -> None: artifacts: List[Artifact] = get_artifacts(process=process, measurement=True) failed_samples = 0 for artifact in artifacts: - if validate_udf_values(artifact=artifact) == False: + if not validate_udf_values(artifact=artifact): failed_samples += 1 continue set_average_and_cv(artifact=artifact) @@ -87,7 +84,7 @@ def calculate_saphyr_concentration(ctx) -> None: raise MissingUDFsError( f"{failed_samples} samples have invalid concentration values (<= 0). See log for more information." ) - message = "The average concentration and coefficient of variance have been calculated." + message = "The average concentration and coefficient of variance have been calculated for all samples." LOG.info(message) click.echo(message) except LimsError as e: