pacificclimate/climate-explorer-frontend

View on GitHub
src/components/graphs/SingleTimeSliceGraph.js

Summary

Maintainability
B
5 hrs
Test Coverage
/*****************************************************************
 * SingleTimeSliceGraph.js - shows model results at a single point
 *   in time, variable and emissions scenario, with one model
 *   highlighted.
 *
 * Produced from the same data as SingleContextGraph, but shows a
 * single timestamp rather than comparing multiple long term
 * averages. While this graph shows a strict subset of the data
 * available in a Model Context Graph, its simplicity and narrowness
 * makes it possible to use it as a sidebar or popup for
 * providing context.
 *****************************************************************/
import React from "react";

import _ from "lodash";

import { dataToLongTermAverageGraph } from "../../core/chart-generators";
import { makeTimeSliceGraph } from "../../core/chart-transformers";
import ContextGraph from "./ContextGraph";
import { emphasizeSeries } from "./graph-helpers";

export default function SingleTimeSliceGraph(props) {
  //TODO: this is 100% identical to SingleContextGraph.getMetadata(),
  //as this graph uses a subset of that one's data. Combine if possible for
  //https://github.com/pacificclimate/climate-explorer-frontend/issues/139.
  function getMetadata() {
    const {
      ensemble_name,
      experiment,
      variable_id,
      area,
      contextMeta,
      model_id,
    } = props;

    //we prefer the lowest possible time resolution for this graph, since it's
    //used to provide broad context, not detailed data. But if the
    //selected dataset doesn't have yearly data, use whatever resolution it has.
    const model_metadata = _.filter(contextMeta, {
      model_id: model_id,
      multi_year_mean: true,
    });
    const resolutions = _.uniq(_.map(model_metadata, "timescale")).sort();
    const timescale = resolutions[resolutions.length - 1];

    // Array of unique model_id's
    const uniqueContextModelIds = _.uniq(_.map(contextMeta, "model_id"));
    const baseMetadata = {
      ensemble_name,
      experiment,
      variable_id,
      area,
      timescale: timescale,
      timeidx: 0,
      multi_year_mean: true,
    };
    const metadatas = uniqueContextModelIds
      .map((model_id) => ({ ...baseMetadata, model_id }))
      .filter(
        (metadata) =>
          // Note: length > 0 guaranteed for item containing props.model_id
          _.filter(
            contextMeta,
            _.omit(metadata, "ensemble_name", "timeidx", "area"),
          ).length > 0,
      );
    return metadatas;
  }

  function dataToGraphSpec(meta, data, selectedModelId) {
    let graph = dataToLongTermAverageGraph(data, meta);

    //select the median timestamp present in the future.
    let timestamps = graph.data.columns.find(function (series) {
      return series[0] === "x";
    });
    let futureTimestamps = [];
    for (let i = 1; i < timestamps.length; i++) {
      let timestamp = Date.parse(timestamps[i]);
      if (timestamp > Date.now()) {
        futureTimestamps.push(timestamps[i]);
      }
    }
    futureTimestamps.sort();
    let selectedTimestamp =
      futureTimestamps[Math.ceil((futureTimestamps.length - 1) / 2)];

    graph = makeTimeSliceGraph(selectedTimestamp, graph);
    graph.size = { width: 150 }; //adjust as needed to make a sidebar.
    graph = emphasizeSeries(graph, selectedModelId);

    return graph;
  }

  const graphProps = _.pick(
    props,
    "model_id",
    "variable_id",
    "experiment",
    "contextMeta",
    "area",
  );

  return (
    <ContextGraph
      {...graphProps}
      getMetadata={getMetadata}
      dataToGraphSpec={dataToGraphSpec}
    />
  );
}