about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-10-10 16:18:52 -0500
committerFrederick Muriuki Muriithi2024-10-10 16:30:43 -0500
commit4f994b79ecee851ea1cd0fa0699ee822c8884bc4 (patch)
tree5250f3a9b9b4a0b7fab8ae919167562b5048d654
parent71b79a670cf59a517f9c0bc4f6f11894c2a5d44d (diff)
downloadgn-uploader-4f994b79ecee851ea1cd0fa0699ee822c8884bc4.tar.gz
Build UI to add new phenotypes.
Build the UI and set up styling. This is not working currently.
-rw-r--r--uploader/phenotypes/views.py22
-rw-r--r--uploader/static/css/styles.css20
-rw-r--r--uploader/templates/phenotypes/add-phenotypes.html222
-rw-r--r--uploader/templates/phenotypes/macro-display-pheno-dataset-card.html23
-rw-r--r--uploader/templates/phenotypes/view-dataset.html14
5 files changed, 297 insertions, 4 deletions
diff --git a/uploader/phenotypes/views.py b/uploader/phenotypes/views.py
index ddf6908..eb0b460 100644
--- a/uploader/phenotypes/views.py
+++ b/uploader/phenotypes/views.py
@@ -286,3 +286,25 @@ def create_dataset(species: dict, population: dict, **kwargs):# pylint: disable=
         return redirect(url_for("species.populations.phenotypes.list_datasets",
                                 species_id=species["SpeciesId"],
                                 population_id=population["Id"]))
+
+
+@phenotypesbp.route(
+    "<int:species_id>/populations/<int:population_id>/phenotypes/datasets"
+    "/<int:dataset_id>/add-phenotypes",
+    methods=["GET", "POST"])
+@require_login
+@with_dataset(
+    species_redirect_uri="species.populations.phenotypes.index",
+    population_redirect_uri="species.populations.phenotypes.select_population",
+    redirect_uri="species.populations.phenotypes.list_datasets")
+def add_phenotypes(species: dict, population: dict, dataset: dict, **kwargs):
+    """Add one or more phenotypes to the dataset."""
+    with (database_connection(app.config["SQL_URI"]) as conn,
+          conn.cursor(cursorclass=DictCursor) as cursor):
+        if request.method == "GET":
+            return render_template("phenotypes/add-phenotypes.html",
+                                   species=species,
+                                   population=population,
+                                   dataset=dataset,
+                                   activelink="add-phenotypes")
+    raise NotImplementedError("Please implement this...")
diff --git a/uploader/static/css/styles.css b/uploader/static/css/styles.css
index 0e9a029..5161169 100644
--- a/uploader/static/css/styles.css
+++ b/uploader/static/css/styles.css
@@ -131,3 +131,23 @@ input[type="submit"], .btn {
     border-color: #DCA7A7;
     background-color: #F2DEDE;
 }
+
+.heading {
+    border-bottom: solid #EEBB88;
+}
+
+.subheading {
+    padding: 1em 0 0.1em 0.5em;
+    border-bottom: solid #88BBEE;
+}
+
+form {
+    margin-top: 0.3em;
+    background: #E5E5FF;
+    padding: 0.5em;
+    border-radius:0.5em;
+}
+
+form .form-control {
+    background-color: #EAEAFF;
+}
diff --git a/uploader/templates/phenotypes/add-phenotypes.html b/uploader/templates/phenotypes/add-phenotypes.html
new file mode 100644
index 0000000..20f8087
--- /dev/null
+++ b/uploader/templates/phenotypes/add-phenotypes.html
@@ -0,0 +1,222 @@
+{%extends "phenotypes/base.html"%}
+{%from "flash_messages.html" import flash_all_messages%}
+{%from "macro-table-pagination.html" import table_pagination%}
+{%from "phenotypes/macro-display-pheno-dataset-card.html" import display_pheno_dataset_card%}
+
+{%block title%}Phenotypes{%endblock%}
+
+{%block pagetitle%}Phenotypes{%endblock%}
+
+{%block lvl4_breadcrumbs%}
+<li {%if activelink=="add-phenotypes"%}
+    class="breadcrumb-item active"
+    {%else%}
+    class="breadcrumb-item"
+    {%endif%}>
+  <a href="{{url_for('species.populations.phenotypes.add_phenotypes',
+           species_id=species.SpeciesId,
+           population_id=population.Id,
+           dataset_id=dataset.Id)}}">View Datasets</a>
+</li>
+{%endblock%}
+
+{%block contents%}
+{{flash_all_messages()}}
+
+<div class="row">
+  <form id="frm-add-phenotypes"
+        method="POST"
+        enctype="multipart/form-data"
+        action="{{url_for('species.populations.phenotypes.add_phenotypes',
+                species_id=species.SpeciesId,
+                population_id=population.Id,
+                dataset_id=dataset.Id)}}">
+    <legend>Add New Phenotypes</legend>
+
+    <div class="form-text help-block">
+      <p>Select the zip file bundle containing information on the phenotypes you
+        wish to upload, then click the "Upload Phenotypes" button below to
+        upload the data.</p>
+      <p>See the <a href="#section-file-formats">File Formats</a> section below
+        to get an understanding of what is expected of the bundle files you
+        upload.</p>
+      <p><strong>This will not update any existing phenotypes!</strong></p>
+    </div>
+
+    <div class="form-group">
+      <label for="finput-phenotypes-bundle" class="form-label">
+        Phenotypes Bundle</label>
+      <input type="file"
+             id="finput-phenotypes-bundle"
+             name="phenotypes-bundle"
+             accept="application/zip, .zip"
+	     required="required"
+             class="form-control" />
+    </div>
+
+    <div class="form-group">
+      <input type="submit"
+             value="upload phenotypes"
+             class="not-implemented btn btn-primary" />
+    </div>
+  </form>
+</div>
+
+<div class="row">
+  <h2 class="heading" id="section-file-formats">File Formats</h2>
+  <p>We accept an extended form of the
+    <a href="https://kbroman.org/qtl2/assets/vignettes/input_files.html#format-of-the-data-files"
+       title="R/qtl2 software input file format documentation">
+      input files' format used with the R/qtl2 software</a> as a single ZIP
+    file</p>
+  <p>The following section will detail the expectations for each of the
+    different file types within the uploaded ZIP file bundle for phenotypes:</p>
+
+  <h3 class="subheading">Control File</h3>
+  <p>There <strong>MUST be <em>one, and only one</em></strong> file that acts
+    as the control file. This file can be:
+    <ul>
+      <li>a <em>JSON</em> file, or</li>
+      <li>a <em>YAML</em> file.</li>
+    </ul>
+  </p>
+
+  <p>The control file is useful for defining things about the bundle such as:</p>
+  <ul>
+    <li>The field separator value (default: <code>sep: ','</code>). There can
+      only ever be one field separator and it <strong>MUST</strong> be the same
+      one for <strong>ALL</strong> files in the bundle.</li>
+    <li>The comment character (default: <code>comment.char: '#'</code>). Any
+      line that starts with this character will be considered a comment line and
+      be ignored in its entirety.</li>
+    <li>Code for missing values (default: <code>na.strings: 'NA'</code>). You
+      can specify more than one code to indicate missing values, e.g.
+      <code>{…, "na.strings": ["NA", "N/A", "-"], …}</code></li>
+  </ul>
+
+  <h3 class="subheading"><em>pheno</em> File(s)</h3>
+  <p>These files are the main data files. You must have at least one of these
+    files in your bundle for it to be valid for this step.</p>
+  <p>The data is a matrix of <em>individuals × phenotypes</em> by default, as
+    below:<br />
+    <code>
+      id,10001,10002,10003,10004,…<br />
+      BXD1,61.400002,54.099998,483,49.799999,…<br />
+      BXD2,49,50.099998,403,45.5,…<br />
+      BXD5,62.5,53.299999,501,62.900002,…<br />
+      BXD6,53.099998,55.099998,403,NA,…<br />
+      ⋮<br /></code>
+  </p>
+  <p>If the <code>pheno_transposed</code> value is set to <code>True</code>,
+    then the data will be a <em>phenotypes × individuals</em> matrix as in the
+    example below:<br />
+    <code>
+      id,BXD1,BXD2,BXD5,BXD6,…<br />
+      10001,61.400002,49,62.5,53.099998,…<br />
+      10002,54.099998,50.099998,53.299999,55.099998,…<br />
+      10003,483,403,501,403,…<br />
+      10004,49.799999,45.5,62.900002,NA,…<br />
+      ⋮
+    </code>
+  </p>
+
+
+  <h3 class="subheading"><em>phenocovar</em> File(s)</h3>
+  <p>At least one phenotypes metadata file with the metadata values such as
+    descriptions, PubMed Identifier, publication titles (if present), etc.</p>
+  <p>The data in this/these file(s) is a matrix of
+    <em>phenotypes × phenotypes-covariates</em>. The first column is always the
+    phenotype names/identifiers — same as in the R/qtl2 format.</p>
+  <p><em>phenocovar</em> files <strong>should never be transposed</strong>!</p>
+  <p>This file <strong>MUST</strong> be present in the bundle, and have data for
+    the bundle to be considered valid by our system for this step.<br />
+    In addition to that, the following are the fields that <strong>must be
+      present</strong>, and
+    have values, in the file before the file is considered valid:
+    <ul>
+      <li><em>description</em>: A description for each phenotype. Useful
+        for users to know what the phenotype is about.</li>
+      <li><em>units</em>: The units of measurement for the phenotype,
+        e.g. milligrams for brain weight, centimetres/millimetres for
+        tail-length, etc.</li>
+  </ul></p>
+
+  <p>The following <em>optional</em> fields can also be provided:
+    <ul>
+      <li><em>pubmedid</em>: A PubMed Identifier for the publication where
+        the phenotype is published. If this field is not provided, the system will
+        assume your phenotype is not published.</li>
+    </ul>
+  </p>
+  <p>These files will be marked up in the control file with the
+    <code>phenocovar</code> key, as in the examples below:
+    <ol>
+      <li>JSON: single file<br />
+        <code>{<br />
+          &nbsp;&nbsp;⋮,<br />
+          &nbsp;&nbsp;"phenocovar": "your_covariates_file.csv",<br />
+          &nbsp;&nbsp;⋮<br />
+          }
+        </code>
+      </li>
+      <li>JSON: multiple files<br />
+        <code>{<br />
+          &nbsp;&nbsp;⋮,<br />
+          &nbsp;&nbsp;"phenocovar": [<br />
+          &nbsp;&nbsp;&nbsp;&nbsp;"covariates_file_01.csv",<br />
+          &nbsp;&nbsp;&nbsp;&nbsp;"covariates_file_01.csv",<br />
+          &nbsp;&nbsp;&nbsp;&nbsp;⋮<br />
+          &nbsp;&nbsp;],<br />
+          &nbsp;&nbsp;⋮<br />
+          }
+        </code>
+      </li>
+      <li>YAML: single file or<br />
+        <code>
+          ⋮<br />
+          phenocovar: your_covariates_file.csv<br />
+          ⋮
+        </code>
+      </li>
+      <li>YAML: multiple files<br />
+        <code>
+          ⋮<br />
+          phenocovar:<br />
+          - covariates_file_01.csv<br />
+          - covariates_file_02.csv<br />
+          - covariates_file_03.csv<br />
+          …<br />
+          ⋮
+        </code>
+      </li>
+    </ol>
+  </p>
+
+  <h3 class="subheading"><em>phenose</em> and <em>phenonum</em> File(s)</h3>
+  <p>These are extensions to the R/qtl2 standard, i.e. these types ofs file are
+    not supported by the original R/qtl2 file format</p>
+  <p>We use these files to upload the standard errors (<em>phenose</em>) when
+    the data file (<em>pheno</em>) is average data. In that case, the
+    <em>phenonum</em> file(s) contains the number of individuals that were
+    involved when computing the averages.</p>
+  <p>Both types of files are matrices of <em>individuals × phenotypes</em> by
+    default. Like the related <em>pheno</em> files, if
+    <code>pheno_transposed: True</code>, then the file will be a matrix of
+    <em>phenotypes × individuals</em>.</p>
+</div>
+
+<div class="row text-warning">
+  <h3 class="subheading">Notes for Devs (well… Fred, really.)</h3>
+  <p>Use the following resources for automated retrieval of certain data</p>
+  <ul>
+    <li><a href="https://www.ncbi.nlm.nih.gov/pmc/tools/developers/"
+           title="NCBI APIs: Retrieve articles' metadata etc.">
+        NCBI APIS</a></li>
+  </ul>
+</div>
+
+{%endblock%}
+
+{%block sidebarcontents%}
+{{display_pheno_dataset_card(species, population, dataset)}}
+{%endblock%}
diff --git a/uploader/templates/phenotypes/macro-display-pheno-dataset-card.html b/uploader/templates/phenotypes/macro-display-pheno-dataset-card.html
new file mode 100644
index 0000000..1121443
--- /dev/null
+++ b/uploader/templates/phenotypes/macro-display-pheno-dataset-card.html
@@ -0,0 +1,23 @@
+{%from "populations/macro-display-population-card.html" import display_population_card%}
+
+{%macro display_pheno_dataset_card(species, population, dataset)%}
+{{display_population_card(species, population)}}
+
+<div class="card">
+  <div class="card-body">
+    <h5 class="card-title">Phenotypes' Dataset</h5>
+    <div class="card-text">
+      <dl>
+        <dt>Name</dt>
+        <dd>{{dataset.Name}}</dd>
+
+        <dt>Full Name</dt>
+        <dd>{{dataset.FullName}}</dd>
+
+        <dt>Short Name</dt>
+        <dd>{{dataset.ShortName}}</dd>
+      </dl>
+    </div>
+  </div>
+</div>
+{%endmacro%}
diff --git a/uploader/templates/phenotypes/view-dataset.html b/uploader/templates/phenotypes/view-dataset.html
index 5a17755..b136bb6 100644
--- a/uploader/templates/phenotypes/view-dataset.html
+++ b/uploader/templates/phenotypes/view-dataset.html
@@ -37,10 +37,7 @@
 
     <tbody>
       <tr>
-        <td><a href="{{url_for('species.populations.phenotypes.view_dataset',
-                     species_id=species.SpeciesId,
-                     population_id=population.Id,
-                     dataset_id=dataset.Id)}}">{{dataset.Name}}</a></td>
+        <td>{{dataset.Name}}</td>
         <td>{{dataset.FullName}}</td>
         <td>{{dataset.ShortName}}</td>
       </tr>
@@ -49,6 +46,15 @@
 </div>
 
 <div class="row">
+  <p><a href="{{url_for('species.populations.phenotypes.add_phenotypes',
+              species_id=species.SpeciesId,
+              population_id=population.Id,
+              dataset_id=dataset.Id)}}"
+        title="Add a bunch of phenotypes"
+        class="btn btn-primary">Add phenotypes</a></p>
+</div>
+
+<div class="row">
   <h2>Phenotype Data</h2>
 
   <p>This dataset has a total of {{phenotype_count}} phenotypes.</p>