Skip to content

Commit

Permalink
wip - handle metric changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jameshadfield committed Nov 14, 2024
1 parent f24a01a commit 42c111e
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/actions/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const changeColorBy = (providedColorBy = undefined) => {
dispatch(changeEntropyCdsSelection(colorBy));

// Recompute streams
const streams = partitionIntoStreams(controls.showStreamTrees, controls.streamTreeBranchLabel, tree.nodes, tree.visibility, colorScale, controls.absoluteDateMinNumeric, controls.absoluteDateMaxNumeric)
const streams = partitionIntoStreams(controls.showStreamTrees, controls.streamTreeBranchLabel, tree.nodes, tree.visibility, colorScale, controls.absoluteDateMinNumeric, controls.absoluteDateMaxNumeric, controls.distanceMeasure)


dispatch({
Expand Down
2 changes: 1 addition & 1 deletion src/actions/recomputeReduxState.js
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,7 @@ export const createStateFromQueryOrJSONs = ({
streamBranchLabels.includes('clade') ? 'clade' :
'none';
}
tree.streams = partitionIntoStreams(controls.showStreamTrees, controls.streamTreeBranchLabel, tree.nodes, tree.visibility, controls.colorScale, controls.absoluteDateMinNumeric, controls.absoluteDateMaxNumeric)
tree.streams = partitionIntoStreams(controls.showStreamTrees, controls.streamTreeBranchLabel, tree.nodes, tree.visibility, controls.colorScale, controls.absoluteDateMinNumeric, controls.absoluteDateMaxNumeric, controls.distanceMeasure)
console.log("tree.streams", tree.streams)

/* calculate entropy in view */
Expand Down
14 changes: 11 additions & 3 deletions src/actions/streamTrees.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@

import { TOGGLE_STREAM_TREE, CHANGE_STREAM_TREE_BRANCH_LABEL } from "./types";
import { TOGGLE_STREAM_TREE, CHANGE_STREAM_TREE_BRANCH_LABEL, CHANGE_DISTANCE_MEASURE } from "./types";
import { partitionIntoStreams } from "../util/partitionIntoStreams";

export function toggleStreamTree() {
return function(dispatch, getState) {
const {controls, tree} = getState();
const showStreamTrees = !controls.showStreamTrees;
const streams = partitionIntoStreams(showStreamTrees, controls.streamTreeBranchLabel, tree.nodes, tree.visibility, controls.colorScale, controls.absoluteDateMinNumeric, controls.absoluteDateMaxNumeric)
const streams = partitionIntoStreams(showStreamTrees, controls.streamTreeBranchLabel, tree.nodes, tree.visibility, controls.colorScale, controls.absoluteDateMinNumeric, controls.absoluteDateMaxNumeric, controls.distanceMeasure)
dispatch({type: TOGGLE_STREAM_TREE, showStreamTrees, streams})
}
}
Expand All @@ -15,7 +15,7 @@ export function changeStreamTreeBranchLabel(newLabel) {
return function(dispatch, getState) {
const {controls, tree} = getState();
const showStreamTrees = newLabel!=='none';
const streams = partitionIntoStreams(showStreamTrees, newLabel, tree.nodes, tree.visibility, controls.colorScale, controls.absoluteDateMinNumeric, controls.absoluteDateMaxNumeric)
const streams = partitionIntoStreams(showStreamTrees, newLabel, tree.nodes, tree.visibility, controls.colorScale, controls.absoluteDateMinNumeric, controls.absoluteDateMaxNumeric, controls.distanceMeasure)
dispatch({
type: CHANGE_STREAM_TREE_BRANCH_LABEL,
streams,
Expand All @@ -24,3 +24,11 @@ export function changeStreamTreeBranchLabel(newLabel) {
})
}
}

export function changeDistanceMeasure(metric) {
return function(dispatch, getState) {
const {controls, tree} = getState();
const streams = partitionIntoStreams(controls.showStreamTrees, controls.streamTreeBranchLabel, tree.nodes, tree.visibility, controls.colorScale, controls.absoluteDateMinNumeric, controls.absoluteDateMaxNumeric, metric)
dispatch({type: CHANGE_DISTANCE_MEASURE, data: metric, streams})
}
}
6 changes: 3 additions & 3 deletions src/components/controls/choose-metric.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { withTranslation } from "react-i18next";
import { CHANGE_DISTANCE_MEASURE } from "../../actions/types";
import { analyticsControlsEvent } from "../../util/googleAnalytics";
import { toggleTemporalConfidence } from "../../actions/tree";
import { toggleStreamTree } from "../../actions/streamTrees";
import { toggleStreamTree, changeDistanceMeasure } from "../../actions/streamTrees";
import { SidebarSubtitle, SidebarButton } from "./styles";
import Toggle from "./toggle";
import { canShowStreamTrees, branchLabelsForStreamTrees } from "./choose-stream-tree-branch-label";
Expand Down Expand Up @@ -39,7 +39,7 @@ class ChooseMetric extends React.Component {
selected={this.props.distanceMeasure === "num_date"}
onClick={() => {
analyticsControlsEvent("tree-metric-temporal");
this.props.dispatch({ type: CHANGE_DISTANCE_MEASURE, data: "num_date" });
this.props.dispatch(changeDistanceMeasure('num_date'))
}}
>
{t("sidebar:time")}
Expand All @@ -49,7 +49,7 @@ class ChooseMetric extends React.Component {
selected={this.props.distanceMeasure === "div"}
onClick={() => {
analyticsControlsEvent("tree-metric-temporal");
this.props.dispatch({ type: CHANGE_DISTANCE_MEASURE, data: "div" });
this.props.dispatch(changeDistanceMeasure('div'))
}}
>
{t("sidebar:divergence")}
Expand Down
2 changes: 2 additions & 0 deletions src/components/tree/phyloTree/change.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ export const change = function change(
transitionTime = 0;
}

if (streams) this.streams = streams;

/* the logic of converting what react is telling us to change
and what SVG elements, node properties, svg props we actually change */
if (changeColorBy) {
Expand Down
4 changes: 3 additions & 1 deletion src/components/tree/phyloTree/layouts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ export function streamLayout(this: PhyloTreeType): void {
break
}
}
const startXVal = getTraitFromNode(this.nodes[stream.originatingNodeIdx].n, "num_date");
const startXVal = this.distance==='num_date' ?
getTraitFromNode(this.nodes[stream.originatingNodeIdx].n, 'num_date') :
getDivFromNode(this.nodes[stream.originatingNodeIdx].n);
// connector start if parent not a stream
if (stream.originatingStreamIdx===null) {
// Increase the tee length of the parent node (a "normal" branch in the tree) so it matches the y-position of the (branch to the) stream
Expand Down
1 change: 1 addition & 0 deletions src/components/tree/reactD3Interface/change.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export const changePhyloTreeViaPropsComparison = (
/* change from timetree to divergence tree */
if (oldProps.distanceMeasure !== newProps.distanceMeasure) {
args.newDistance = newProps.distanceMeasure;
args.streams = newTreeRedux.streams;
}

/* explode! */
Expand Down
5 changes: 5 additions & 0 deletions src/reducers/tree/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ const Tree = (

return Object.assign({}, state, newStates);
}
case types.CHANGE_DISTANCE_MEASURE:
if (action.streams) {
return {...state, streams: action.streams};
}
return state;
case types.UPDATE_TIP_RADII:
return {
...state,
Expand Down
32 changes: 23 additions & 9 deletions src/util/partitionIntoStreams.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getTraitFromNode } from "./treeMiscHelpers"
import { getTraitFromNode, getDivFromNode } from "./treeMiscHelpers"
import { NODE_VISIBLE } from "./globals";

/**
Expand All @@ -7,7 +7,7 @@ import { NODE_VISIBLE } from "./globals";
* - only works for categorical colorScal`e
* - only works for temporal tree
*/
export function partitionIntoStreams(enabled, branchLabel, nodes, visibility, colorScale, absoluteDateMinNumeric, absoluteDateMaxNumeric) {
export function partitionIntoStreams(enabled, branchLabel, nodes, visibility, colorScale, absoluteDateMinNumeric, absoluteDateMaxNumeric, metric) {

const streams = {
streams: [],
Expand Down Expand Up @@ -61,11 +61,11 @@ export function partitionIntoStreams(enabled, branchLabel, nodes, visibility, co
// TODO XXX - the starting color needs to be modified if it is to match the branches!
// See calculateStrokeColors, but this would need refactoring
stream.startingColor = colorScale.scale(getTraitFromNode(nodes[founderInfo.idx], colorScale.colorBy))
const pivotData = calcPivots(nodesInStream, absoluteDateMinNumeric, absoluteDateMaxNumeric);
const pivotData = calcPivots(metric, nodesInStream, absoluteDateMinNumeric, absoluteDateMaxNumeric);
stream.pivotIntervals = pivotData.intervals;
stream.pivots = pivotData.pivots;
// nodeIdxs are all nodes, visible and not visible
stream.nodeIdxs = groupNodesIntoIntervals(nodesInStream, pivotData.intervals); // indexed by pivot idx
stream.nodeIdxs = groupNodesIntoIntervals(nodesInStream, pivotData.intervals, metric); // indexed by pivot idx
// stream.numNodes = nodesInStream.length;
stream.maxNodesInInterval = Math.max(...stream.nodeIdxs.map((idxs) => idxs.length));
stream.countsByCategory = countsByCategory(nodes, stream.nodeIdxs, visibility, colorScale.colorBy, stream.categories);
Expand Down Expand Up @@ -105,9 +105,13 @@ function observedCategories(nodes, colorScale) {
return Array.from(values).sort((a,b) => colorScale.legendValues.indexOf(a) - colorScale.legendValues.indexOf(b))
}

function calcPivots(nodes, absoluteDateMinNumeric, absoluteDateMaxNumeric) {
const domain = nodes.reduce((acc, node) => {
const value = getTraitFromNode(node, "num_date"); // TODO XXX
function calcPivots(metric, nodes, absoluteDateMinNumeric, absoluteDateMaxNumeric) {
/**
* TODO XXX - pivot number always calculated using num_date - this helps ensure the number of pivots
* doesn't change when we change the metric. Obviously needs to be fixed.
*/
let domain = nodes.reduce((acc, node) => {
const value = getTraitFromNode(node, 'num_date');
if (acc[0] > value) acc[0] = value;
if (acc[1] < value) acc[1] = value;
return acc;
Expand All @@ -116,6 +120,16 @@ function calcPivots(nodes, absoluteDateMinNumeric, absoluteDateMaxNumeric) {
const domainFraction = (domain[1]-domain[0]) / (absoluteDateMaxNumeric - absoluteDateMinNumeric);
const availablePivots = 50;
const nPivots = Math.ceil(domainFraction * availablePivots);

if (metric==='div') {
domain = nodes.reduce((acc, node) => {
const value = getDivFromNode(node);
if (acc[0] > value) acc[0] = value;
if (acc[1] < value) acc[1] = value;
return acc;
}, [Infinity, -Infinity])
}

const size = (domain[1]-domain[0])/(nPivots-1);
const intervals = Array.from(Array(nPivots), undefined);
intervals[0] = [domain[0], domain[0] + size/2];
Expand All @@ -129,11 +143,11 @@ function calcPivots(nodes, absoluteDateMinNumeric, absoluteDateMaxNumeric) {
}


function groupNodesIntoIntervals(nodes, intervals) {
function groupNodesIntoIntervals(nodes, intervals, metric) {
const groups = Array.from(Array(intervals.length), () => [])
// TODO XXX this is very crude
for (const node of nodes) {
const value = getTraitFromNode(node, "num_date"); // TODO XXX
const value = metric==='num_date' ? getTraitFromNode(node, "num_date") : getDivFromNode(node);
for (let i =0; i<intervals.length; i++) {
if (value>intervals[i][0] && value<=intervals[i][1]) { // TODO - which side is open, which is closed?
// TODO XXX - I use arrayIdx not the node itself as adding references to nodes like this
Expand Down

0 comments on commit 42c111e

Please sign in to comment.