Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zoom to selected is stored as a URL query #1321

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions narratives/test_simultaneous-tree-updates.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ Check that both the branches and tips update.
# [P3: Zoom into clade A1b _and_ change color](http://localhost:4000/flu/seasonal/h3n2/ha/3y?d=tree&label=clade:A1b)
Check that the coloring of the branches and tips update as we zoom in.

# [P3b: Zoom in slightly more via "zoom to selected"](http://localhost:4000/flu/seasonal/h3n2/ha/3y?d=tree&f_clade_membership=A1b/186D,A1b/197R,A1b/94N&treeZoom=selected)

We're now recreating the functionality of filtering to clades A1b/186D, A1b/197R and A1b/94N then clicking "zoom to selected"

# [P4: Lots of simultaneous changes](http://localhost:4000/flu/seasonal/h3n2/ha/3y?c=lbi&d=tree&dmin=2017-01-01&f_region=North%20America&label=clade:3c2.A&m=div)
* Zoomed out to near the root (clade 3c2.A)
* Changed the horizontal scale to divergence
Expand Down
24 changes: 16 additions & 8 deletions src/actions/recomputeReduxState.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { cloneDeep } from 'lodash';
import { numericToCalendar, calendarToNumeric } from "../util/dateHelpers";
import { reallySmallNumber, twoColumnBreakpoint, defaultColorBy, defaultGeoResolution, defaultDateRange, nucleotide_gene, strainSymbol, genotypeSymbol } from "../util/globals";
import { calcBrowserDimensionsInitialState } from "../reducers/browserDimensions";
import { getIdxMatchingLabel, calculateVisiblityAndBranchThickness } from "../util/treeVisibilityHelpers";
import { getIdxMatchingLabel, calculateVisiblityAndBranchThickness, getFilteredAndIdxOfFilteredRoot } from "../util/treeVisibilityHelpers";
import { constructVisibleTipLookupBetweenTrees } from "../util/treeTangleHelpers";
import { getDefaultControlsState, shouldDisplayTemporalConfidence } from "../reducers/controls";
import { countTraitsAcrossTree, calcTotalTipsInTree } from "../util/treeCountingHelpers";
Expand Down Expand Up @@ -587,15 +587,23 @@ const checkAndCorrectErrorsInState = (state, metadata, query, tree, viewingNarra
return state;
};

const modifyTreeStateVisAndBranchThickness = (oldState, zoomSelected, controlsState, dispatch) => {
const modifyTreeStateVisAndBranchThickness = (oldState, query, controlsState, dispatch) => {
/* calculate new branch thicknesses & visibility */
let newIdxRoot = oldState.idxOfInViewRootNode;
if (zoomSelected) {

if (typeof query.label==="string") {
// Check and fix old format 'clade=B' - in this case selectionClade is just 'B'
const [labelName, labelValue] = zoomSelected.split(":");
const [labelName, labelValue] = query.label.split(":");
const cladeSelectedIdx = getIdxMatchingLabel(oldState.nodes, labelName, labelValue, dispatch);
oldState.selectedClade = zoomSelected;
oldState.selectedClade = query.label;
newIdxRoot = applyInViewNodesToTree(cladeSelectedIdx, oldState);
delete query.treeZoom;
} else if (query.treeZoom==="selected") {
// zoom to selected requires filters to be applied to tree to calculate the appropriate root
// Note that these are re-calculated by `calculateVisiblityAndBranchThickness`
const {idxOfFilteredRoot} = getFilteredAndIdxOfFilteredRoot(oldState, controlsState, oldState.nodes.map(() => true));
newIdxRoot = applyInViewNodesToTree(idxOfFilteredRoot, oldState);
if (!idxOfFilteredRoot) delete query.treeZoom;
} else {
oldState.selectedClade = undefined;
newIdxRoot = applyInViewNodesToTree(0, oldState);
Expand Down Expand Up @@ -831,12 +839,12 @@ export const createStateFromQueryOrJSONs = ({
}

/* if query.label is undefined then we intend to zoom to the root */
tree = modifyTreeStateVisAndBranchThickness(tree, query.label, controls, dispatch);
tree = modifyTreeStateVisAndBranchThickness(tree, query, controls, dispatch);

if (treeToo && treeToo.loaded) {
treeToo.nodeColorsVersion = tree.nodeColorsVersion;
treeToo.nodeColors = calcNodeColor(treeToo, controls.colorScale);
treeToo = modifyTreeStateVisAndBranchThickness(treeToo, undefined, controls, dispatch);
treeToo = modifyTreeStateVisAndBranchThickness(treeToo, {}, controls, dispatch);
controls = modifyControlsViaTreeToo(controls, treeToo.name);
treeToo.tangleTipLookup = constructVisibleTipLookupBetweenTrees(tree.nodes, treeToo.nodes, tree.visibility, treeToo.visibility);
}
Expand Down Expand Up @@ -912,7 +920,7 @@ export const createTreeTooState = ({
treeToo.debug = "RIGHT";
controls = modifyControlsStateViaTree(controls, tree, treeToo, oldState.metadata.colorings);
controls = modifyControlsViaTreeToo(controls, secondTreeUrl);
treeToo = modifyTreeStateVisAndBranchThickness(treeToo, undefined, controls, dispatch);
treeToo = modifyTreeStateVisAndBranchThickness(treeToo, {}, controls, dispatch);

/* calculate colours if loading from JSONs or if the query demands change */
const colorScale = calcColorScale(controls.colorBy, controls, tree, treeToo, oldState.metadata);
Expand Down
9 changes: 9 additions & 0 deletions src/actions/tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ export const updateVisibleTipsAndBranchThicknesses = (
visibilityToo: dispatchObj.visibilityToo
});

/* We set a flag for the URL middleware here */
if (root[0]!== undefined) {
if (tree.idxOfFilteredRoot===root[0]) {
dispatchObj.zoomToSelectedQuery = true;
} else {
dispatchObj.zoomToSelectedQuery = false;
}
}

/* D I S P A T C H */
dispatch(dispatchObj);
updateEntropyVisibility(dispatch, getState);
Expand Down
12 changes: 11 additions & 1 deletion src/middleware/changeURL.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,17 @@ export const changeURLMiddleware = (store) => (next) => (action) => {
}
case types.UPDATE_VISIBILITY_AND_BRANCH_THICKNESS: {
// query.s = action.selectedStrain ? action.selectedStrain : undefined;
query.label = action.cladeName ? action.cladeName : undefined;
if (action.cladeName) {
query.label = action.cladeName;
query.treeZoom = undefined; // we preferentially restore state from clade (branch) label
} else {
query.label = undefined;
if (action.zoomToSelectedQuery===true) {
query.treeZoom="selected"; // setting a string variable allows for future expansion
} else if (action.zoomToSelectedQuery===false) {
query.treeZoom=undefined;
}
}
break;
}
case types.MAP_ANIMATION_PLAY_PAUSE_BUTTON:
Expand Down
2 changes: 1 addition & 1 deletion src/util/treeVisibilityHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ const getInView = (tree) => {
* - controls.filters (redux) is a dict of trait name -> values
* - filters (in this code) is a list of filters to apply
* e.g. [{trait: "country", values: [...]}, ...] */
const getFilteredAndIdxOfFilteredRoot = (tree, controls, inView) => {
export const getFilteredAndIdxOfFilteredRoot = (tree, controls, inView) => {
if (!tree.nodes) {
console.error("getFiltered() ran without tree.nodes");
return null;
Expand Down