KarrLab/datanator_frontend

View on GitHub
src/scenes/Stats/Stats.js

Summary

Maintainability
F
6 days
Test Coverage
C
79%
import React, { Component } from "react";
import { HashLink } from "react-router-hash-link";
import { scrollTo } from "~/utils/utils";
import BarPlot from "./Plot/BarPlot";
import FrequencyPlot from "./Plot/FrequencyPlot";
import axios from "axios";
import { getDataFromApi, genApiErrorHandler } from "~/services/RestApi";

import "./Stats.scss";

class Stats extends Component {
  constructor() {
    super();
    this.state = {
      dataType: {
        labels: [],
        values: [],
      },
      dataSource: {
        labels: [],
        values: [],
      },
      journalByDataType: {
        labels: [],
        values: [],
      },
      taxonomy: {
        labels: [],
        values: [],
      },
      temperatureFrequency: {
        labels: [],
        values: [],
      },
      phFrequency: {
        labels: [],
        values: [],
      },
    };

    this.setBarChart = this.setBarChart.bind(this);
  }

  componentDidMount() {
    // number of observations of each data type
    const dataTypeData = [];
    dataTypeData.push({
      label: ["Met. concs."],
      urls: ["metabolites/summary/concentration_count/"],
    });
    dataTypeData.push({
      label: ["RNA modifications"],
      urls: ["rna/summary/get_total_modifications/"],
    });
    dataTypeData.push({
      label: ["RNA half-lives"],
      urls: ["rna/summary/get_total_halflife_obs/"],
    });
    dataTypeData.push({
      label: ["Prot. abundances"],
      urls: ["proteins/summary/num_obs_abundances/"],
    });
    dataTypeData.push({
      label: ["Prot. modifications"],
      urls: ["proteins/summary/num_obs_modifications/"],
    });
    dataTypeData.push({
      label: ["Reaction kcat"],
      urls: ["reactions/summary/num_parameter_kcat/"],
    });
    dataTypeData.push({
      label: ["Reaction Km"],
      urls: ["reactions/summary/num_parameter_km/"],
    });
    this.setBarChart("dataType", dataTypeData);

    // number of observations from each source
    const dataSourceData = [];
    dataSourceData.push({
      label: ["Articles"],
      urls: ["rna/summary/get_distinct/?_input=halflives.reference.doi"],
    });
    // TODO: BRENDA Kis
    /*
    dataSourceData.push({
      label: ["BRENDA"],
      urls: [
        "reactions/summary/get_brenda_obs/?parameter=k_cats",
        "reactions/summary/get_brenda_obs/?parameter=k_ms", //,
        // "reactions/summary/get_brenda_obs/?parameter=k_is"
      ],
    });
    */
    dataSourceData.push({
      label: ["ECMDB"],
      urls: ["metabolites/summary/ecmdb_conc_count/"],
    });
    dataSourceData.push({
      label: ["MODOMICS"],
      urls: ["rna/summary/get_total_modifications/"],
    });
    dataSourceData.push({
      label: ["PAXdb"],
      urls: ["proteins/summary/num_obs_abundances/"],
    });
    dataSourceData.push({
      label: ["PRO"],
      urls: ["proteins/summary/num_obs_abundances/"],
    });
    dataSourceData.push({
      label: ["SABIO-RK"],
      urls: [
        "reactions/summary/get_sabio_obs/?parameter=k_cats",
        "reactions/summary/get_sabio_obs/?parameter=k_ms",
        "reactions/summary/get_sabio_obs/?parameter=k_is",
      ],
    });
    dataSourceData.push({
      label: ["YMDB"],
      urls: ["metabolites/summary/ymdb_conc_count/"],
    });
    this.setBarChart("dataSource", dataSourceData);

    // number of articles behind each type of data
    const journalByDataTypeData = [];
    journalByDataTypeData.push({
      label: ["Met. concs."],
      urls: [
        "metabolites/summary/ecmdb_ref_count/",
        "metabolites/summary/ymdb_ref_count/",
        "metabolites/summary/curated_ref_count/",
      ],
    });
    journalByDataTypeData.push({
      label: ["Prot. abund."],
      urls: ["proteins/summary/num_publications/"],
    });
    journalByDataTypeData.push({
      label: ["Rxn kinetics"],
      urls: ["reactions/summary/num_refs/"],
    });
    journalByDataTypeData.push({
      label: ["RNA half-lives"],
      urls: ["rna/summary/get_distinct/?_input=halflives.reference.doi"],
    });
    this.setBarChart("journalByDataType", journalByDataTypeData);

    // taxonomic distribution of measurements
    const taxonomicUrl =
      "https://raw.githubusercontent.com/KarrLab/datanator_query_python/testapi/docs/taxon_distribution_frontend.json";
    getDataFromApi(taxonomicUrl)
      .then((response) => {
        const organismCountsDict = {};
        for (const organismLong in response.data) {
          if (organismLong !== "others") {
            const organismParts = organismLong.split(" ");
            const organismShort =
              organismParts[0].substr(0, 1) + ". " + organismParts[1];

            if (!(organismShort in organismCountsDict)) {
              organismCountsDict[organismShort] = 0;
            }
            organismCountsDict[organismShort] += response.data[organismLong];
          }
        }

        const organismCountsArr = [];
        for (const organism in organismCountsDict) {
          organismCountsArr.push({
            organism: organism,
            count: organismCountsDict[organism],
          });
        }
        organismCountsArr.sort((a, b) => {
          if (a.count < b.count) {
            return 1;
          } else if (a.count > b.count) {
            return -1;
          } else {
            return 0;
          }
        });

        const labels = [];
        const values = [];
        for (const organismCount of organismCountsArr) {
          labels.push(organismCount.organism);
          values.push(organismCount.count);
        }
        labels.push("Other");
        values.push(response.data["others"]);

        this.setState({
          taxonomy: {
            labels: labels,
            values: values,
          },
        });
      })
      .catch(
        genApiErrorHandler.bind(
          null,
          taxonomicUrl,
          "Unable to get taxonomic distribution of measurements."
        )
      );

    // temperature distribution of measurements
    this.setFrequencyChart(
      "temperatureFrequency",
      "reactions/summary/get_frequency/?field=temperature"
    );

    // pH distribution of measurements
    this.setFrequencyChart(
      "phFrequency",
      "reactions/summary/get_frequency/?field=ph"
    );
  }

  setBarChart(name, data) {
    const requests = [];
    const labels = [];
    const values = [];

    for (const bar of data) {
      for (const url of bar.urls) {
        requests.push(getDataFromApi(url));
      }
    }

    axios.all(requests).then(
      axios.spread((...responses) => {
        let iResponse = 0;
        for (const bar of data) {
          let value = 0;
          for (let iUrl = 0; iUrl < bar.urls.length; iUrl++) {
            value += responses[iResponse].data;
            iResponse++;
          }
          values.push(value);
          labels.push(bar.label);
        }
        this.setState({ [name]: { labels: labels, values: values } });
      })
    );
  }

  setFrequencyChart(name, dataUrl) {
    const labels = [];
    const values = [];
    getDataFromApi(dataUrl).then((response) => {
      let data = response.data.sort(function (a, b) {
        return a["_id"] - b["_id"];
      });
      for (var n = 0; n < data.length; n++) {
        if (data[n]["_id"]) {
          labels.push(data[n]["_id"]);
          values.push(data[n]["count"]);
        }
      }
      this.setState({
        [name]: { labels: labels, values: values },
      });
    });
  }

  render() {
    return (
      <div className="content-container content-container-stats-scene">
        <h1 className="page-title">
          Statistics:{" "}
          <span className="highlight-accent">
            Distribution of the measurements in the <i>Datanator</i> database
          </span>
        </h1>
        <div className="content-container-columns">
          <div className="overview-column">
            <div className="content-block table-of-contents">
              <h2 className="content-block-heading">Contents</h2>
              <div className="content-block-content">
                <ul>
                  <li>
                    <HashLink scroll={scrollTo} to="#data-type">
                      Data types
                    </HashLink>
                  </li>
                  <li>
                    <HashLink scroll={scrollTo} to="#taxa">
                      Taxa
                    </HashLink>
                  </li>
                  <li>
                    <HashLink scroll={scrollTo} to="#temperature">
                      Env. conditions
                    </HashLink>
                    <ul>
                      <li>
                        <HashLink scroll={scrollTo} to="#temperature">
                          Temperature
                        </HashLink>
                      </li>
                      <li>
                        <HashLink scroll={scrollTo} to="#ph">
                          pH
                        </HashLink>
                      </li>
                    </ul>
                  </li>
                  <li>
                    <HashLink scroll={scrollTo} to="#immediate-source">
                      Sources
                    </HashLink>
                    <ul>
                      <li>
                        <HashLink scroll={scrollTo} to="#immediate-source">
                          Immediate
                        </HashLink>
                      </li>
                      <li>
                        <HashLink scroll={scrollTo} to="#primary-source">
                          Primary
                        </HashLink>
                      </li>
                    </ul>
                  </li>
                </ul>
              </div>
            </div>
          </div>

          <div className="content-column">
            <div className="section-columns section-2-columns">
              <div className="section section-column" id="data-type">
                <h2 className="content-block-heading">
                  Distribution of the types of the measurements
                </h2>
                <div className="content-block-content">
                  <BarPlot
                    data={this.state.dataType}
                    yAxisLabel="Measurements"
                  />
                </div>
              </div>

              <div className="section section-column" id="taxa">
                <h2 className="content-block-heading">
                  Taxonomic distribution of the measurements
                </h2>
                <div className="content-block-content">
                  <BarPlot
                    data={this.state.taxonomy}
                    yAxisLabel="Measurements"
                  />
                </div>
              </div>
            </div>

            <div className="section-columns section-2-columns">
              <div className="section section-column" id="temperature">
                <h2 className="content-block-heading">
                  Temperature distribution of the measurements
                </h2>
                <div className="content-block-content">
                  <FrequencyPlot
                    data={this.state.temperatureFrequency}
                    xAxisLabel={"Temperature (˚C)"}
                    xMin={10}
                    xMax={80}
                    yAxisLabel="Measurements"
                    kernelBandwidth={0.5}
                  />
                </div>
              </div>

              <div className="section section-column" id="ph">
                <h2 className="content-block-heading">
                  pH distribution of the measurements
                </h2>
                <div className="content-block-content">
                  <FrequencyPlot
                    data={this.state.phFrequency}
                    xAxisLabel={"pH"}
                    xMin={1}
                    xMax={14}
                    yAxisLabel="Measurements"
                    kernelBandwidth={0.5}
                  />
                </div>
              </div>
            </div>

            <div className="section-columns section-2-columns">
              <div className="section section-column" id="immediate-source">
                <h2 className="content-block-heading">
                  Immediate sources of the measurements
                </h2>
                <div className="content-block-content">
                  <BarPlot
                    data={this.state.dataSource}
                    yAxisLabel="Measurements"
                  />
                </div>
              </div>

              <div className="section section-column" id="primary-source">
                <h2 className="content-block-heading">
                  Number of primary sources for each type of data
                </h2>
                <div className="content-block-content">
                  <BarPlot
                    data={this.state.journalByDataType}
                    yAxisLabel="Articles"
                  />
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default Stats;