Add margins to histogram SVGs (#1085)

* Add a left margin to histogram SVGs

Fixes https://github.com/chanzuckerberg/cellxgene/issues/1042

1. Added "margins" to the SVG as in https://bl.ocks.org/mbostock/3019563
2. Tailored the brushable area to be just where the data is and locked
   puppeteerUtils to use that in e2e testing.

* Dial in margins to avoid y-axis clipping
This commit is contained in:
Matt Weiden
2020-01-06 10:46:06 -08:00
committed by GitHub
parent 327d005a1f
commit b172ff7f15
3 changed files with 44 additions and 28 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ export const datasets = {
{
metadata: "n_genes",
"coordinates-as-percent": { x1: 0.25, y1: 0.5, x2: 0.55, y2: 0.5 },
count: "1537"
count: "1552"
}
]
},
+9 -9
View File
@@ -126,12 +126,12 @@ describe("cell selection", () => {
test("selects cells via continuous", async () => {
for (const cellset of data.cellsets.continuous) {
const histId = `histogram-${cellset.metadata}-plot-brush`;
const histBrushableAreaId = `histogram-${cellset.metadata}-plot-brushable-area`;
const coords = await cxgActions.calcDragCoordinates(
histId,
histBrushableAreaId,
cellset["coordinates-as-percent"]
);
await cxgActions.drag(histId, coords.start, coords.end);
await cxgActions.drag(histBrushableAreaId, coords.start, coords.end);
const cellCount = await cxgActions.cellSet(1);
expect(cellCount).toBe(cellset.count);
}
@@ -280,12 +280,12 @@ describe("scatter plot", () => {
describe("clipping", () => {
test("clip continuous", async () => {
await cxgActions.clip(data.clip.min, data.clip.max);
const histId = `histogram-${data.clip.metadata}-plot-brush`;
const histBrushableAreaId = `histogram-${data.clip.metadata}-plot-brushable-area`;
const coords = await cxgActions.calcDragCoordinates(
histId,
histBrushableAreaId,
data.clip["coordinates-as-percent"]
);
await cxgActions.drag(histId, coords.start, coords.end);
await cxgActions.drag(histBrushableAreaId, coords.start, coords.end);
const cellCount = await cxgActions.cellSet(1);
expect(cellCount).toBe(data.clip.count);
});
@@ -295,12 +295,12 @@ describe("clipping", () => {
await page.keyboard.press("Enter");
await page.waitForSelector(`[data-testid='histogram-${data.clip.gene}']`);
await cxgActions.clip(data.clip.min, data.clip.max);
const histId = `histogram-${data.clip.gene}-plot-brush`;
const histBrushableAreaId = `histogram-${data.clip.gene}-plot-brushable-area`;
const coords = await cxgActions.calcDragCoordinates(
histId,
histBrushableAreaId,
data.clip["coordinates-as-percent"]
);
await cxgActions.drag(histId, coords.start, coords.end);
await cxgActions.drag(histBrushableAreaId, coords.start, coords.end);
const cellCount = await cxgActions.cellSet(1);
expect(cellCount).toBe(data.clip["gene-cell-count"]);
});
@@ -2,6 +2,7 @@
https://bl.ocks.org/mbostock/4341954
https://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172
https://bl.ocks.org/SpaceActuary/2f004899ea1b2bd78d6f1dbb2febf771
https://bl.ocks.org/mbostock/3019563
*/
// jshint esversion: 6
import React from "react";
@@ -55,7 +56,7 @@ class HistogramBrush extends React.PureComponent {
histogramCache.x = d3
.scaleLinear()
.domain([domainMin, domainMax])
.range([0, this.width - this.marginRight]);
.range([this.marginLeft, this.marginLeft + this.width]);
histogramCache.bins = d3
.histogram()
@@ -68,7 +69,7 @@ class HistogramBrush extends React.PureComponent {
histogramCache.y = d3
.scaleLinear()
.domain([0, yMax])
.range([this.height - this.marginBottom, 0]);
.range([this.marginTop + this.height, this.marginTop]);
return histogramCache;
});
@@ -76,10 +77,13 @@ class HistogramBrush extends React.PureComponent {
constructor(props) {
super(props);
this.width = 340;
this.height = 100;
this.marginBottom = 20; // space for X axis & labels
this.marginLeft = 3; // Space for 0 tick label on X axis
this.marginRight = 40; // space for Y axis & labels
this.marginBottom = 25; // space for X axis & labels
this.marginTop = 3;
this.width = 340 - this.marginLeft - this.marginRight;
this.height = 135 - this.marginTop - this.marginBottom;
}
componentDidMount() {
@@ -315,8 +319,16 @@ class HistogramBrush extends React.PureComponent {
/* Remove everything */
svg.selectAll("*").remove();
/* Set margins within the SVG */
const container = svg
.attr("width", this.width + this.marginLeft + this.marginRight)
.attr("height", this.height + this.marginTop + this.marginBottom)
.append("g")
.attr("class", "histogram-container")
.attr("transform", `translate(${this.marginLeft},${this.marginTop})`);
/* BINS */
svg
container
.insert("g", "*")
.attr("fill", "#bbb")
.selectAll("rect")
@@ -328,10 +340,14 @@ class HistogramBrush extends React.PureComponent {
.attr("width", d => Math.abs(x(d.x1) - x(d.x0) - 1))
.attr("height", d => y(0) - y(d.length));
/* BRUSH */
// BRUSH
// Note the brushable area is bounded by the data on three sides, but goes down to cover the x-axis
const brushX = d3
.brushX()
.extent([[0, 0], [this.width - this.marginRight, this.height]])
.extent([
[x.range()[0], y.range()[1]],
[x.range()[1], this.marginTop + this.height + this.marginBottom]
])
/*
emit start so that the Undoable history can save an undo point
upon drag start, and ignore the subsequent intermediate drag events.
@@ -339,18 +355,18 @@ class HistogramBrush extends React.PureComponent {
.on("start", this.onBrush(field, x.invert, "start").bind(this))
.on("brush", this.onBrush(field, x.invert, "brush").bind(this))
.on("end", this.onBrushEnd(field, x.invert).bind(this));
const brushXselection = d3
.select(svgRef)
.append("g")
const brushXselection = container
.insert("g")
.attr("class", "brush")
.attr("data-testid", `${svgRef.dataset.testid}-brush`)
.attr("data-testid", `${svgRef.dataset.testid}-brushable-area`)
.call(brushX);
/* X AXIS */
svg
.append("g")
container
.insert("g")
.attr("class", "axis axis--x")
.attr("transform", `translate(0,${this.height - this.marginBottom})`)
.attr("transform", `translate(0,${this.marginTop + this.height})`)
.call(
d3
.axisBottom(x)
@@ -359,10 +375,10 @@ class HistogramBrush extends React.PureComponent {
);
/* Y AXIS */
svg
.append("g")
container
.insert("g")
.attr("class", "axis axis--y")
.attr("transform", `translate(${this.width - this.marginRight},0)`)
.attr("transform", `translate(${this.marginLeft + this.width},0)`)
.call(
d3
.axisRight(y)