Skip to content

Commit

Permalink
measurements: Jitter y-value for raw measurements within color-by groups
Browse files Browse the repository at this point in the history
For each subplot, jitter the y-values of the raw measurements within
each color-by group. The y-value range for each color-by group is
determined by the proportion of measurements within each group, i.e.
color-by groups with more measurements get a larger portion of the
subplot height.

Removes the jitter value added during loading of the measurements JSON
and the `measurementJitterSymbol` since they are no longer needed.
  • Loading branch information
joverlee521 committed Feb 3, 2023
1 parent daf2f1e commit b77f787
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 10 deletions.
8 changes: 2 additions & 6 deletions src/actions/measurements.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { pick } from "lodash";
import { measurementIdSymbol, measurementJitterSymbol } from "../util/globals";
import { layout as measurementsLayout } from "../components/measurements/measurementsD3";
import { measurementIdSymbol } from "../util/globals";
import {
APPLY_MEASUREMENTS_FILTER,
CHANGE_MEASUREMENTS_COLLECTION,
Expand Down Expand Up @@ -170,10 +169,7 @@ export const loadMeasurements = (json) => (dispatch, getState) => {
}
});

// Add jitter and stable id for each measurement to help visualization
const { yMin, yMax } = measurementsLayout;
// Generates a random number between the y min and max, inclusively
measurement[measurementJitterSymbol] = Math.random() * (yMax - yMin + 1) + yMin;
// Add stable id for each measurement to help visualization
measurement[measurementIdSymbol] = index;
});

Expand Down
4 changes: 3 additions & 1 deletion src/components/measurements/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
toggleDisplay,
addHoverPanelToMeasurementsAndMeans,
addColorByAttrToGroupingLabel,
layout
layout,
jitterRawMeansByColorBy
} from "./measurementsD3";

/**
Expand Down Expand Up @@ -223,6 +224,7 @@ const MeasurementsPlot = ({height, width, showLegend, setPanelTitle}) => {
useEffect(() => {
addColorByAttrToGroupingLabel(d3Ref.current, treeStrainColors);
colorMeasurementsSVG(d3Ref.current, treeStrainColors);
jitterRawMeansByColorBy(d3Ref.current, svgData, treeStrainColors, legendValues);
drawMeansForColorBy(d3Ref.current, svgData, treeStrainColors, legendValues);
addHoverPanelToMeasurementsAndMeans(d3Ref.current, handleHover, treeStrainColors);
}, [svgData, treeStrainColors, legendValues, handleHover]);
Expand Down
43 changes: 41 additions & 2 deletions src/components/measurements/measurementsD3.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { scaleLinear } from "d3-scale";
import { select, event as d3event } from "d3-selection";
import { symbol, symbolDiamond } from "d3-shape";
import { orderBy } from "lodash";
import { measurementIdSymbol, measurementJitterSymbol } from "../../util/globals";
import { measurementIdSymbol } from "../../util/globals";
import { getBrighterColor } from "../../util/colorHelpers";

/* C O N S T A N T S */
Expand Down Expand Up @@ -264,6 +264,7 @@ export const drawMeasurementsSVG = (ref, xAxisRef, svgData) => {
});

// Add circles for each measurement
// Note, "cy" is added later when jittering within color-by groups
subplot.append("g")
.attr("class", classes.rawMeasurementsGroup)
.attr("display", "none")
Expand All @@ -274,7 +275,6 @@ export const drawMeasurementsSVG = (ref, xAxisRef, svgData) => {
.attr("class", classes.rawMeasurements)
.attr("id", (d) => getMeasurementDOMId(d))
.attr("cx", (d) => xScale(d.value))
.attr("cy", (d) => yScale(d[measurementJitterSymbol]))
.attr("r", layout.circleRadius)
.on("mouseover.radius", (d, i, elements) => {
select(elements[i]).transition()
Expand Down Expand Up @@ -307,6 +307,45 @@ export const colorMeasurementsSVG = (ref, treeStrainColors) => {
.style("fill", (d) => getBrighterColor(treeStrainColors[d.strain].color));
};

export const jitterRawMeansByColorBy = (ref, svgData, treeStrainColors, legendValues) => {
const { groupedMeasurements } = svgData;
const svg = select(ref);

groupedMeasurements.forEach(([_, measurements]) => {
// For each color-by attribute, create an array of measurement DOM ids
const colorByGroups = {};
measurements.forEach((measurement) => {
const { attribute } = treeStrainColors[measurement.strain];
colorByGroups[attribute] = colorByGroups[attribute] || [];
colorByGroups[attribute].push(getMeasurementDOMId(measurement));
});
// Calculate total available subplot height
// Accounts for top/bottom padding and padding between color-by groups
const numberOfColorByAttributes = Object.keys(colorByGroups).length;
const totalColorByPadding = (numberOfColorByAttributes - 1) * 2 * layout.circleRadius;
const availableSubplotHeight = layout.subplotHeight - (2*layout.subplotPadding) - totalColorByPadding;

let currentYMin = layout.subplotPadding;
Object.keys(colorByGroups)
// Sort by legendValues for stable ordering of color-by groups
.sort((a, b) => legendValues.indexOf(a) - legendValues.indexOf(b))
.forEach((attribute) => {
// Calculate max Y value for each color-by attribute
// This is determined by the proportion of measurements in each attribute group
const domIds = colorByGroups[attribute];
const proportionOfMeasurements = domIds.length / measurements.length;
const currentYMax = currentYMin + (proportionOfMeasurements * availableSubplotHeight);
// Jitter "cy" value for each raw measurement
domIds.forEach((domId) => {
const jitter = Math.random() * (currentYMax - currentYMin) + currentYMin;
svg.select(`#${domId}`).attr("cy", jitter);
});
// Set next min Y value for next color-by attribute group
currentYMin = currentYMax + (2 * layout.circleRadius);
});
});
};

export const drawMeansForColorBy = (ref, svgData, treeStrainColors, legendValues) => {
const { xScale, groupingOrderedValues, groupedMeasurements } = svgData;
const svg = select(ref);
Expand Down
1 change: 0 additions & 1 deletion src/util/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ export const isValueValid = (value) => {
export const strainSymbol = Symbol('strain');
export const genotypeSymbol = Symbol('genotype');
export const measurementIdSymbol = Symbol('measurementId');
export const measurementJitterSymbol = Symbol('measurementJitter');

/**
* Address to fetch tiles from (including access key).
Expand Down

0 comments on commit b77f787

Please sign in to comment.