diff --git a/src/modules/db_operations/module.env b/src/modules/db_operations/module.env index 777dbc07..24bb821e 100644 --- a/src/modules/db_operations/module.env +++ b/src/modules/db_operations/module.env @@ -1,2 +1,2 @@ MODULE_NAME=caendr-db-operations -MODULE_VERSION=v1.0.41 +MODULE_VERSION=v1.0.42 diff --git a/src/modules/db_operations/requirements.txt b/src/modules/db_operations/requirements.txt index a6d363ce..716b003c 100644 --- a/src/modules/db_operations/requirements.txt +++ b/src/modules/db_operations/requirements.txt @@ -1,4 +1,5 @@ backoff==2.2.1 +bleach==4.1.0 Flask==1.1.2 Flask_SQLAlchemy==2.5.1 SQLAlchemy==1.3.18 diff --git a/src/modules/site-v2/base/static/js/plot.js b/src/modules/site-v2/base/static/js/plot.js index e73f5c67..45e64942 100644 --- a/src/modules/site-v2/base/static/js/plot.js +++ b/src/modules/site-v2/base/static/js/plot.js @@ -411,6 +411,12 @@ function render_ranked_barplot(container_selector, data, config={}) { // Read values from config, filling in default values when not supplied const fill_color = config['fill_color'] || 'black'; + // Create a template function for the tooltip + // By default, show label & value for each axis + const tooltip_id = config['tooltip_id'] || null; + const tooltip_template = config['tooltip_template'] || ((d) => ` +
${d[0]}: ${d[1]}
+ `); // Sort data data.sort(function(b, a) { diff --git a/src/modules/site-v2/module.env b/src/modules/site-v2/module.env index 1ebc7449..0a5149f3 100755 --- a/src/modules/site-v2/module.env +++ b/src/modules/site-v2/module.env @@ -1,5 +1,5 @@ MODULE_NAME=caendr-site-v2 -MODULE_VERSION=v2.0.95 +MODULE_VERSION=v2.0.96 PORT=8080 FLASK_APP=main:app diff --git a/src/modules/site-v2/templates/_includes/phenotype-database-table.html b/src/modules/site-v2/templates/_includes/phenotype-database-table.html index 69bc7140..7220be63 100644 --- a/src/modules/site-v2/templates/_includes/phenotype-database-table.html +++ b/src/modules/site-v2/templates/_includes/phenotype-database-table.html @@ -191,7 +191,7 @@ $('#{{ offcanvas_id }} .btn-close').click() flashErrorResponse(error.responseJSON, 'There was a problem retrieving this trait. Please try again later.') }) - }) + }) // Filter table by tag links diff --git a/src/modules/site-v2/templates/_scripts/trait_utils.js b/src/modules/site-v2/templates/_scripts/trait_utils.js index 0f350a62..d810d5c5 100644 --- a/src/modules/site-v2/templates/_scripts/trait_utils.js +++ b/src/modules/site-v2/templates/_scripts/trait_utils.js @@ -32,7 +32,7 @@ function queryTraitByName(trait_id, csrf_token=null) { // Construct the data object, using the optional CSRF token if provided let data = {trait_id}; if (csrf_token !== null) data['csrf_token'] = csrf_token; - + // Return the AJAX request as a Promise object return $.ajax({ type: "POST", diff --git a/src/modules/site-v2/templates/tools/phenotype_database/report.html b/src/modules/site-v2/templates/tools/phenotype_database/report.html index c594cf1f..9c9d7c38 100644 --- a/src/modules/site-v2/templates/tools/phenotype_database/report.html +++ b/src/modules/site-v2/templates/tools/phenotype_database/report.html @@ -228,6 +228,11 @@Strain: ${d[0]}
+${labels[0]}: ${d[1]}
+ `, }); } catch (err) { console.error(`Could not construct histogram. ${err}`) @@ -238,6 +243,11 @@${d[0]}
+Value = ${d[1].toFixed(4)}
+ `, }); } catch (err) { console.error(`Could not construct ranked bar plot. ${err}`) @@ -262,6 +272,12 @@${d[0]}
+x = ${d[1].toFixed(4)}
+y = ${d[2].toFixed(4)}
+ `, }); } catch (err) { console.error(`Could not construct scatterplot. ${err}`) diff --git a/src/pkg/caendr/caendr/models/datastore/phenotype_report.py b/src/pkg/caendr/caendr/models/datastore/phenotype_report.py index f2cd1924..870baa95 100644 --- a/src/pkg/caendr/caendr/models/datastore/phenotype_report.py +++ b/src/pkg/caendr/caendr/models/datastore/phenotype_report.py @@ -286,7 +286,7 @@ def compute_display_name(cls, trait: Union[Trait, TraitFile], trait_name: Option raise ValueError() # Use the Trait object to compute the display name - return list(trait.display_name) + return [trait.name,] if trait.dataset == 'zhang' else list(trait.display_name) @classmethod diff --git a/src/pkg/caendr/caendr/models/trait.py b/src/pkg/caendr/caendr/models/trait.py index 8d819f9d..a1ca207e 100644 --- a/src/pkg/caendr/caendr/models/trait.py +++ b/src/pkg/caendr/caendr/models/trait.py @@ -3,7 +3,9 @@ from caendr.models.datastore import TraitFile from caendr.models.sql import PhenotypeMetadata, PhenotypeDatabase +from caendr.models.error import NotFoundError from caendr.utils.data import dataframe_cols_to_dict +from caendr.api.phenotype import get_trait from caendr.services.cloud.postgresql import db @@ -57,9 +59,11 @@ def __init__(self, dataset = None, trait_name = None, trait_file_id = None, trai raise ValueError('Could not identify a unique trait from the given information') # Store the dataset value of the trait file - if dataset and self.file['dataset'] and dataset != self.file['dataset']: - raise ValueError('Mismatched dataset values') - self.dataset = self.file['dataset'] + # if dataset and self.file['dataset'].value and dataset != self.file['dataset'].value: + # raise ValueError('Mismatched dataset values') + self.dataset = self.file['dataset'].value + + self.sql_row = PhenotypeMetadata.query.filter_by(trait_name_caendr = self.name, dataset = self.dataset).one() # @@ -104,6 +108,24 @@ def from_sql(sql_row: PhenotypeMetadata) -> 'Trait': dataset = sql_row.dataset, trait_name = sql_row.trait_name_caendr, ) + + @classmethod + def from_id(cls, trait_id: str) -> 'Trait': + ''' + Instantiate a `Trait` object from a unique trait ID. + The given ID must exist in the PhenotypeMetadata SQL table, otherwise a `ValueError` will be raised. + ''' + + # Get the SQL row with the given trait ID + sql_row = PhenotypeMetadata.query.get(trait_id) + if sql_row is None: + raise NotFoundError(PhenotypeMetadata, {'id': trait_id}) + + # Construct a Trait object using the data in the SQL row + return cls( + trait_name = sql_row.trait_name_caendr, + dataset = sql_row.dataset, + ) # @@ -145,4 +167,4 @@ def display_name(self): ''' # For bulk files, store the single trait name, otherwise convert the display_name fields to a list - return (self.name,) if self.file['is_bulk_file'] else self.file.display_name \ No newline at end of file + return (self.sql_row.trait_name_caendr,) if self.file['is_bulk_file'] else self.file.display_name \ No newline at end of file diff --git a/src/pkg/caendr/caendr/services/sql/etl/phenotype_metadata.py b/src/pkg/caendr/caendr/services/sql/etl/phenotype_metadata.py index 79be5888..04377aaa 100644 --- a/src/pkg/caendr/caendr/services/sql/etl/phenotype_metadata.py +++ b/src/pkg/caendr/caendr/services/sql/etl/phenotype_metadata.py @@ -58,7 +58,7 @@ def parse_phenotype_metadata(species: Species, **files: LocalDatastoreFile): 'capture_date': md['capture_date'], 'created_on': md.created_on, 'modified_on': md.modified_on, - 'dataset': md['dataset'], + 'dataset': md['dataset'].value, 'is_bulk_file': md['is_bulk_file'], } else: @@ -83,6 +83,6 @@ def parse_phenotype_metadata(species: Species, **files: LocalDatastoreFile): 'capture_date': md['capture_date'], 'created_on': md.created_on, 'modified_on': md.modified_on, - 'dataset': md['dataset'], + 'dataset': md['dataset'].value, 'is_bulk_file': md['is_bulk_file'], }