diff --git a/src/components/ForestPlot.js b/src/components/ForestPlot.js index 3f1c469b..1e0ce93e 100644 --- a/src/components/ForestPlot.js +++ b/src/components/ForestPlot.js @@ -12,10 +12,11 @@ import Help from '@material-ui/icons/Help'; import { pvalThreshold } from '../constants'; function traitFilterOptions(data, selectedCategories) { + let all_categories = _.sortBy(_.uniq(data.map(d => d.traitCategory)), d => d); // color scale let colorScale = d3 .scaleOrdinal() - .domain(selectedCategories) + .domain(all_categories) .range(d3.schemeCategory10); return _.sortBy( _.uniq(data.map(d => d.traitCategory)).map(d => { @@ -42,7 +43,8 @@ const cfg = { minBoxSize: 5, maxBoxSize: 20, maxPlotHeight: 800, - plotMargin: 100, + top_axis: 27, + bottom_axis: 52, treeColor: '#5A5F5F', evenRowColor: '#fff', unevenRowColor: '#f2f1f1', @@ -78,8 +80,9 @@ const ForestPlot = ({ ); const plot_height = - cfg.plotMargin + traits.length * cfg.rowHeight < cfg.maxPlotHeight - ? cfg.plotMargin + traits.length * cfg.rowHeight + traits.length * cfg.rowHeight + cfg.top_axis + cfg.bottom_axis < + cfg.maxPlotHeight + ? traits.length * cfg.rowHeight + cfg.top_axis + cfg.bottom_axis : cfg.maxPlotHeight; // draw the plot @@ -104,9 +107,15 @@ const ForestPlot = ({ d3.select('#topRow') .selectAll('*') .remove(); + d3.select('#topRowTable') + .selectAll('*') + .remove(); d3.select('#bottomRow') .selectAll('*') .remove(); + d3.select('#table') + .selectAll('*') + .remove(); // get component width cfg.component_width = d3 @@ -131,17 +140,32 @@ const ForestPlot = ({ const svg = d3 .select(refs.current) .attr('width', cfg.svgW) - .attr('height', traits.length * cfg.rowHeight + 3 * cfg.rowHeight) + .attr('height', traits.length * cfg.rowHeight + 2 * cfg.rowHeight) .style('position', 'absolute') + .style('top', cfg.top_axis) .append('g'); // set top row svg size and sticky const topRowSvg = d3 .select('#topRow') .attr('width', cfg.svgW - 45) - .attr('height', cfg.rowHeight + 5) + .attr('height', cfg.top_axis) + .style('position', 'absolute') + .style('flex-shrink', 0) + .style('flex-grow', 0) + .style('top', '0') + .style('z-index', '2'); + + // set top row table size and sticky + const topRowTable = d3 + .select('#topRowTable') + .attr('width', cfg.tableW) + .attr('height', cfg.top_axis) .style('position', 'sticky') - .style('top', '0'); + .style('flex-shrink', 0) + .style('flex-grow', 0) + .style('left', '0') + .style('z-index', '3'); // set bottom row svg size and sticky const bottomRowSvg = d3 @@ -149,12 +173,9 @@ const ForestPlot = ({ .attr('width', cfg.svgW) .attr('height', 2 * cfg.rowHeight) .style('position', 'sticky') - .style( - 'top', - plot_height <= 800 - ? plot_height - 3 * cfg.rowHeight - : plot_height - 2 * cfg.rowHeight - ) + .style('flex-shrink', 0) + .style('flex-grow', 0) + .style('top', plot_height - 2 * cfg.rowHeight) .style('background-color', 'white'); // clip trait name text (row width) @@ -166,17 +187,17 @@ const ForestPlot = ({ .attr('width', cfg.traitnameW); // add top row of table - topRowSvg + topRowTable .append('g') - .classed('topRow', true) + .classed('topRowTable', true) .append('rect') .attr('height', cfg.rowHeight) .attr('width', cfg.tableW) .attr('fill', cfg.unevenRowColor); // trait - topRowSvg - .select('.topRow') + topRowTable + .select('.topRowTable') .append('text') .text('Trait') .attr('clip-path', 'url(#clip1)') @@ -187,8 +208,8 @@ const ForestPlot = ({ .attr('dx', 8); // pval - topRowSvg - .select('.topRow') + topRowTable + .select('.topRowTable') .append('text') .text('P-value') .style('font-size', '17px') @@ -198,7 +219,7 @@ const ForestPlot = ({ .attr('dx', cfg.traitnameW + 8); // add horizontal line to separate top row from other rows - topRowSvg + topRowTable .append('line') .attr('x2', cfg.tableW) .attr('y1', cfg.rowHeight) @@ -206,7 +227,7 @@ const ForestPlot = ({ .attr('stroke', 'black'); // add vertical line to separate trait and pval columns - topRowSvg + topRowTable .append('line') .attr('x1', cfg.traitnameW) .attr('x2', cfg.traitnameW) @@ -214,14 +235,20 @@ const ForestPlot = ({ .attr('stroke', 'black'); // create table - let table = svg.append('g').attr('id', 'forestTable'); + const table = d3 + .select('#table') + .attr('width', 500) + .attr('height', traits.length === 0 ? 0 : cfg.rowHeight) + .style('position', 'sticky') + .style('left', '0') + .style('overflow', 'visible'); // add vertical line to separate trait and pval columns table .append('line') .attr('x1', cfg.traitnameW) .attr('x2', cfg.traitnameW) - .attr('y2', traits.length * cfg.rowHeight + cfg.rowHeight) + .attr('y2', traits.length * cfg.rowHeight) .attr('stroke', 'black'); // add rows to table @@ -231,10 +258,7 @@ const ForestPlot = ({ .enter() .append('g') .classed('row', true) - .attr( - 'transform', - (d, i) => 'translate(0,' + cfg.rowHeight * (i + 1) + ')' - ); + .attr('transform', (d, i) => 'translate(0,' + cfg.rowHeight * i + ')'); rows .append('rect') @@ -340,7 +364,7 @@ const ForestPlot = ({ let transf = n[i].parentNode.attributes.transform.nodeValue; return axisLines .append(() => n[i]) - .attr('y2', traits.length * cfg.rowHeight + cfg.rowHeight) + .attr('y2', traits.length * cfg.rowHeight) .attr('transform', transf); }); @@ -399,10 +423,7 @@ const ForestPlot = ({ .enter() .append('g') .classed('tree', true) - .attr( - 'transform', - (d, i) => 'translate(0,' + (i + 1) * cfg.rowHeight + ')' - ) + .attr('transform', (d, i) => 'translate(0,' + i * cfg.rowHeight + ')') .attr('id', (d, i) => i); // create confidence intervals @@ -469,6 +490,8 @@ const ForestPlot = ({ width: cfg.component_width, height: plot_height, margin: 'none', + display: 'flex', + 'flex-direction': 'column', }} > @@ -487,7 +510,20 @@ const ForestPlot = ({ transform={`translate(${cfg.svgW - 40},0)`} /> - +