Skip to content

Commit

Permalink
Merge pull request #586 from nextstrain/meta-safety-checks
Browse files Browse the repository at this point in the history
Meta safety checks
  • Loading branch information
jameshadfield authored Jul 2, 2018
2 parents e6d7079 + 46f5bcc commit 6f816a1
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 45 deletions.
5 changes: 2 additions & 3 deletions src/actions/loadData.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,8 @@ const fetchDataAndDispatch = (dispatch, datasets, query, s3bucket, narrativeJSON
values.forEach((v, i) => {
if (v) data.JSONs[promisesOrder[i]] = v; // if statement removes undefinds
});
// console.log(data);
if (!(data.JSONs.meta && data.JSONs.tree)) {
console.error("Tree & Meta JSONs could not be loaded.");
if (!data.JSONs.tree) {
console.error("Tree JSON could not be loaded.");
dispatch(goTo404(`
Auspice attempted to load JSONs for the dataset "${datasets.datapath.replace(/_/g, '/')}", but they couldn't be found.
`));
Expand Down
88 changes: 65 additions & 23 deletions src/actions/recomputeReduxState.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ const modifyStateViaMetadata = (state, metadata) => {
// need authors in metadata.filters to include as filter
// but metadata.author_info is generally required for app functioning
} else {
console.error("the meta.json must include author_info");
console.warn("the meta.json did not include author_info");
}
if (metadata.filters) {
metadata.filters.forEach((v) => {
Expand Down Expand Up @@ -179,8 +179,25 @@ const modifyStateViaMetadata = (state, metadata) => {
}
}

state.panelsAvailable = metadata.panels.slice();
state.panelsToDisplay = metadata.panels.slice();
if (metadata.panels) {
state.panelsAvailable = metadata.panels.slice();
state.panelsToDisplay = metadata.panels.slice();
} else {
state.panelsAvailable = ["tree"];
state.panelsToDisplay = ["tree"];
}

/* if metadata lacks geo, remove map from panels to display */
if (!metadata.geo) {
state.panelsAvailable = state.panelsAvailable.filter((item) => item !== "map");
state.panelsToDisplay = state.panelsToDisplay.filter((item) => item !== "map");
}

/* if metadata lacks annotations, remove entropy from panels to display */
if (!metadata.annotations) {
state.panelsAvailable = state.panelsAvailable.filter((item) => item !== "entropy");
state.panelsToDisplay = state.panelsToDisplay.filter((item) => item !== "entropy");
}

/* if only map or only tree, then panelLayout must be full */
/* note - this will be overwritten by the URL query */
Expand All @@ -189,13 +206,17 @@ const modifyStateViaMetadata = (state, metadata) => {
state.canTogglePanelLayout = false;
}
/* annotations in metadata */
if (!metadata.annotations) {console.error("Metadata needs updating with annotations field. Rerun augur. FATAL.");}
for (const gene of Object.keys(metadata.annotations)) {
state.geneLength[gene] = metadata.annotations[gene].end - metadata.annotations[gene].start;
if (gene !== "nuc") {
state.geneLength[gene] /= 3;
if (metadata.annotations) {
for (const gene of Object.keys(metadata.annotations)) {
state.geneLength[gene] = metadata.annotations[gene].end - metadata.annotations[gene].start;
if (gene !== "nuc") {
state.geneLength[gene] /= 3;
}
}
} else {
console.warn("The meta.json did not include annotations.");
}

return state;
};

Expand Down Expand Up @@ -246,14 +267,22 @@ const checkAndCorrectErrorsInState = (state, metadata) => {
a URL QUERY (and correct it in state), we can't correct the URL */

/* colorBy */
if (!metadata.colorOptions) {
metadata.colorOptions = {};
}
if (Object.keys(metadata.colorOptions).indexOf(state.colorBy) === -1 && !state["colorBy"].startsWith("gt-")) {
const availableNonGenotypeColorBys = Object.keys(metadata.colorOptions);
if (availableNonGenotypeColorBys.indexOf("gt") > -1) {
availableNonGenotypeColorBys.splice(availableNonGenotypeColorBys.indexOf("gt"), 1);
}
console.error("Error detected trying to set colorBy to", state.colorBy, "(valid options are", Object.keys(metadata.colorOptions).join(", "), "). Setting to", availableNonGenotypeColorBys[0]);
state.colorBy = availableNonGenotypeColorBys[0];
state.defaults.colorBy = availableNonGenotypeColorBys[0];
if (Object.keys(metadata.colorOptions).length > 0) {
state.colorBy = availableNonGenotypeColorBys[0];
state.defaults.colorBy = availableNonGenotypeColorBys[0];
} else {
state.colorBy = "none";
state.defaults.colorBy = "none";
}
}

/* colorBy confidence */
Expand All @@ -266,10 +295,14 @@ const checkAndCorrectErrorsInState = (state, metadata) => {
}

/* geoResolution */
const availableGeoResultions = Object.keys(metadata.geo);
if (availableGeoResultions.indexOf(state["geoResolution"]) === -1) {
state["geoResolution"] = availableGeoResultions[0];
console.error("Error detected. Setting geoResolution to ", state["geoResolution"]);
if (metadata.geo) {
const availableGeoResultions = Object.keys(metadata.geo);
if (availableGeoResultions.indexOf(state["geoResolution"]) === -1) {
state["geoResolution"] = availableGeoResultions[0];
console.error("Error detected. Setting geoResolution to ", state["geoResolution"]);
}
} else {
console.warn("The meta.json did not include geo info.");
}

/* temporalConfidence */
Expand All @@ -284,8 +317,12 @@ const checkAndCorrectErrorsInState = (state, metadata) => {
}

/* if colorBy is a genotype then we need to set mutType */
const maybeMutType = determineColorByGenotypeType(state.colorBy);
if (maybeMutType) state.mutType = maybeMutType;
if (state.colorBy) {
const maybeMutType = determineColorByGenotypeType(state.colorBy);
if (maybeMutType) {
state.mutType = maybeMutType;
}
}

return state;
};
Expand Down Expand Up @@ -348,21 +385,24 @@ export const createStateFromQueryOrJSONs = ({
/* first task is to create metadata, entropy, controls & tree partial state */
if (JSONs) {
if (JSONs.narrative) narrative = JSONs.narrative;
/* ceate metadata state */
/* create metadata state */
metadata = JSONs.meta;
if (metadata === undefined) {
metadata = {};
}
if (Object.prototype.hasOwnProperty.call(metadata, "loaded")) {
console.error("Metadata JSON must not contain the key \"loaded\". Ignoring.");
}
metadata.colorOptions = metadata.color_options;
delete metadata.color_options;
metadata.loaded = true;
/* entropy state */
entropy = entropyCreateStateFromJsons(JSONs.meta);
entropy = entropyCreateStateFromJsons(metadata);
/* new tree state(s) */
tree = treeJsonToState(JSONs.tree, JSONs.meta.vaccine_choices);
tree = treeJsonToState(JSONs.tree, metadata.vaccine_choices);
tree.debug = "LEFT";
if (JSONs.treeToo) {
treeToo = treeJsonToState(JSONs.treeToo, JSONs.meta.vaccine_choices);
treeToo = treeJsonToState(JSONs.treeToo, metadata.vaccine_choices);
treeToo.debug = "RIGHT";
}
/* new controls state - don't apply query yet (or error check!) */
Expand Down Expand Up @@ -415,9 +455,11 @@ export const createStateFromQueryOrJSONs = ({
}

/* calculate entropy in view */
const [entropyBars, entropyMaxYVal] = calcEntropyInView(tree.nodes, tree.visibility, controls.mutType, entropy.geneMap, entropy.showCounts);
entropy.bars = entropyBars;
entropy.maxYVal = entropyMaxYVal;
if (entropy.loaded) {
const [entropyBars, entropyMaxYVal] = calcEntropyInView(tree.nodes, tree.visibility, controls.mutType, entropy.geneMap, entropy.showCounts);
entropy.bars = entropyBars;
entropy.maxYVal = entropyMaxYVal;
}

/* potentially calculate frequency (or update it!)
this needs to come after the colorscale & tree is set */
Expand Down
20 changes: 11 additions & 9 deletions src/components/download/helperFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,17 @@ export const authorCSV = (dispatch, filePrefix, metadata, tree) => {
}
});
const body = [];
for (const author of Object.keys(metadata.author_info)) {
body.push([
prettyString(author, {camelCase: false}),
metadata.author_info[author].n,
prettyString(metadata.author_info[author].title, {removeComma: true}),
prettyString(metadata.author_info[author].journal, {removeComma: true}),
isPaperURLValid(metadata.author_info[author]) ? formatURLString(metadata.author_info[author].paper_url) : "unknown",
authors[author].join(" ")
]);
if (metadata.author_info) {
for (const author of Object.keys(metadata.author_info)) {
body.push([
prettyString(author, {camelCase: false}),
metadata.author_info[author].n,
prettyString(metadata.author_info[author].title, {removeComma: true}),
prettyString(metadata.author_info[author].journal, {removeComma: true}),
isPaperURLValid(metadata.author_info[author]) ? formatURLString(metadata.author_info[author].paper_url) : "unknown",
authors[author].join(" ")
]);
}
}

body.forEach((line) => { lineArray.push(line.join(",")); });
Expand Down
6 changes: 4 additions & 2 deletions src/components/info/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,10 @@ class Info extends React.Component {
}

getNumSelectedAuthors() {
if (!Object.prototype.hasOwnProperty.call(this.props.filters, "authors") || this.props.filters.authors.length === 0) {
return Object.keys(this.props.metadata.author_info).length;
if (this.props.metadata.author_info) {
if (!Object.prototype.hasOwnProperty.call(this.props.filters, "authors") || this.props.filters.authors.length === 0) {
return Object.keys(this.props.metadata.author_info).length;
}
}
return this.props.filters.authors.length;
}
Expand Down
12 changes: 11 additions & 1 deletion src/components/tree/infoPanels/click.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,17 @@ const TipClickedPanel = ({tip, goAwayCallback, metadata}) => {
const url = validAttr(tip.n.attr, "url") ? formatURL(tip.n.attr.url) : false;
const uncertainty = "num_date_confidence" in tip.n.attr && tip.n.attr.num_date_confidence[0] !== tip.n.attr.num_date_confidence[1];
const author = tip.n.attr.authors || undefined;
const authorInfo = metadata.author_info;
let authorInfo = {
author: {
n: null,
title: null,
journal: null,
paper_url: null
}
};
if (metadata.author_info) {
authorInfo = metadata.author_info;
}
return (
<div style={styles.container} onClick={() => goAwayCallback(tip)}>
<div className={"panel"} style={infoPanelStyles.panel} onClick={(e) => stopProp(e)}>
Expand Down
21 changes: 19 additions & 2 deletions src/util/colorScale.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getExtraVals } from "./colorHelpers";
import { parseEncodedGenotype } from "./getGenotype";
import { setGenotype, orderOfGenotypeAppearance } from "./setGenotype";

const unknownColor = "#DDDDDD";
const unknownColor = "#AAAAAA";

const getMinMaxFromTree = (nodes, nodesToo, attr) => {
const arr = nodesToo ? nodes.concat(nodesToo) : nodes.slice();
Expand Down Expand Up @@ -80,7 +80,24 @@ const createLegendBounds = (legendValues) => {


export const calcColorScale = (colorBy, controls, tree, treeToo, metadata) => {
// console.log(`calcColorScale for ${colorBy}. TreeToo? ${!!treeToo}`)

if (colorBy === "none") {
console.warn("ColorScale fallthrough for colorBy set to none");
const colorScale = () => unknownColor;
const genotype = null;
const legendValues = ["unknown"];
const legendBounds = createLegendBounds(legendValues);
return {
scale: colorScale,
continuous: false,
colorBy: colorBy,
version: controls.colorScale === undefined ? 1 : controls.colorScale.version + 1,
legendValues,
legendBounds,
genotype
};
}

let genotype;
if (colorBy.slice(0, 3) === "gt-" && controls.geneLength) {
genotype = parseEncodedGenotype(colorBy, controls.geneLength);
Expand Down
4 changes: 3 additions & 1 deletion src/util/entropy.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ const calcEntropy = (nodes, visibility, geneMap, isAA) => {
if (isAA) {
if (node.aa_muts) {
for (const prot in node.aa_muts) { // eslint-disable-line
node.aa_muts[prot].forEach(assignFn, [prot, state]);
if (arrayOfProts.includes(prot)) {
node.aa_muts[prot].forEach(assignFn, [prot, state]);
}
}
}
} else if (node.muts && node.muts.length) {
Expand Down
16 changes: 12 additions & 4 deletions src/util/entropyCreateStateFromJsons.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,20 @@ const processAnnotations = (annotations) => {
};

export const entropyCreateStateFromJsons = (metaJSON) => {
/* TODO check that metadata defines the entropy panel */
const annotations = getAnnotations(metaJSON.annotations);
if (metaJSON.annotations) {
const annotations = getAnnotations(metaJSON.annotations);
return {
showCounts: false,
loaded: true,
annotations,
geneMap: processAnnotations(annotations)
};
}
const annotations = [];
return {
showCounts: false,
loaded: true,
loaded: false,
annotations,
geneMap: processAnnotations(annotations)
geneMap: {}
};
};

0 comments on commit 6f816a1

Please sign in to comment.