Skip to content

Commit

Permalink
Row and column scale for heatmap and surface plots
Browse files Browse the repository at this point in the history
  • Loading branch information
derpylz committed Oct 4, 2020
1 parent 35b5b56 commit 4b7ad4d
Show file tree
Hide file tree
Showing 17 changed files with 125 additions and 42 deletions.
14 changes: 14 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-msedge",
"request": "launch",
"name": "Open index.html",
"file": "e:\\Dokumente\\repos\\babyplots_lib\\index.html"
}
]
}
40 changes: 28 additions & 12 deletions Axes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,49 +45,59 @@ export class Axes {
}
private _createAxes(heatmap: boolean = false): void {
if (heatmap) {
// Tick breaks for heat map on x and z coordinates have to match columns and rows
this.axisData.tickBreaks[0] = 1;
this.axisData.tickBreaks[2] = 1;
}
let xtickBreaks = this.axisData.tickBreaks[0] / this.axisData.scale[0];
let ytickBreaks = this.axisData.tickBreaks[1] / this.axisData.scale[1];
let ztickBreaks = this.axisData.tickBreaks[2] / this.axisData.scale[2];
// Apply scaling factor to tick break interval to get distance between ticks
let xtickBreaks = this.axisData.tickBreaks[0] * this.axisData.scale[0];
let ytickBreaks = this.axisData.tickBreaks[1] * this.axisData.scale[1];
let ztickBreaks = this.axisData.tickBreaks[2] * this.axisData.scale[2];
// Find minima and maxima of the axes as a multiple of the tick interval distance
let xmin = Math.floor(this.axisData.range[0][0] / xtickBreaks) * xtickBreaks;
let ymin = Math.floor(this.axisData.range[1][0] / ytickBreaks) * ytickBreaks;
let zmin = Math.floor(this.axisData.range[2][0] / ztickBreaks) * ztickBreaks;
let xmax = Math.ceil(this.axisData.range[0][1] / xtickBreaks) * xtickBreaks;
let ymax = Math.ceil(this.axisData.range[1][1] / ytickBreaks) * ytickBreaks;
let zmax = Math.ceil(this.axisData.range[2][1] / ztickBreaks) * ztickBreaks;
// create X axis
// Create X axis
if (this.axisData.showAxes[0]) {
// axis
// Create axis line
let axisX = LinesBuilder.CreateLines("axisX", {
points: [
new Vector3(xmin, ymin, zmin),
new Vector3(xmax, ymin, zmin)
]
}, this._scene);
// Apply axis color
axisX.color = Color3.FromHexString(this.axisData.color[0]);
this._axes.push(axisX);
// label
// Create axis label
let xChar = this._makeTextPlane(this.axisData.axisLabels[0], 1, this.axisData.color[0]);
// Place label near end of the axis
xChar.position = new Vector3(xmax / 2, ymin - 0.5 * ymax, zmin);
this._axisLabels.push(xChar);
// x ticks and tick lines
// Create ticks and tick lines
let xTicks = [];
// Find x coordinates for ticks
// Negative ticks
for (let i = 0; i < -Math.ceil(this.axisData.range[0][0] / xtickBreaks); i++) {
xTicks.push(-(i + 1) * xtickBreaks);
}
// Positive ticks
for (let i = 0; i <= Math.ceil(this.axisData.range[0][1] / xtickBreaks); i++) {
xTicks.push(i * xtickBreaks);
}
// Usually ticks start with 0, heat map starts with 1
let startTick = 0;
if (heatmap) {
startTick = 1;
}
// Create all ticks
for (let i = startTick; i < xTicks.length; i++) {
let tickPos = xTicks[i];
if (heatmap) {
tickPos = tickPos - 0.5;
tickPos = tickPos - 0.5 * this.axisData.scale[0];
}
let tick = LinesBuilder.CreateLines("xTicks", {
points: [
Expand All @@ -98,10 +108,13 @@ export class Axes {
}, this._scene);
tick.color = Color3.FromHexString(this.axisData.color[0]);
this._ticks.push(tick);
let tickLabel = this._roundTicks(tickPos * this.axisData.scale[0]).toString();
let tickLabel = this._roundTicks(tickPos / this.axisData.scale[0]).toString();
if (heatmap) {
tickLabel = this.axisData.colnames[i - 1];
}
if (tickLabel === undefined) {
continue;
}
let tickChar = this._makeTextPlane(tickLabel, 0.6, this.axisData.color[0]);
tickChar.position = new Vector3(tickPos, ymin - 0.1 * ymax, zmin);
this._tickLabels.push(tickChar);
Expand Down Expand Up @@ -161,7 +174,7 @@ export class Axes {
}, this._scene);
tick.color = Color3.FromHexString(this.axisData.color[1]);
this._ticks.push(tick);
let tickLabel = this._roundTicks(tickPos * this.axisData.scale[1]);
let tickLabel = this._roundTicks(tickPos / this.axisData.scale[1]);
let tickChar = this._makeTextPlane(tickLabel.toString(), 0.6, this.axisData.color[1]);
tickChar.position = new Vector3(xmin, tickPos, zmin - 0.05 * ymax);
this._tickLabels.push(tickChar);
Expand Down Expand Up @@ -218,7 +231,7 @@ export class Axes {
for (let i = startTick; i < zTicks.length; i++) {
let tickPos = zTicks[i];
if (heatmap) {
tickPos = tickPos - 0.5;
tickPos = tickPos - 0.5 * this.axisData.scale[2];
}
let tick = LinesBuilder.CreateLines("zTicks", {
points: [
Expand All @@ -229,10 +242,13 @@ export class Axes {
}, this._scene);
tick.color = Color3.FromHexString(this.axisData.color[2]);
this._ticks.push(tick);
let tickLabel = this._roundTicks(tickPos * this.axisData.scale[2]).toString();
let tickLabel = this._roundTicks(tickPos / this.axisData.scale[2]).toString();
if (heatmap) {
tickLabel = this.axisData.rownames[i - 1];
}
if (tickLabel === undefined) {
continue;
}
let tickChar = this._makeTextPlane(tickLabel, 0.6, this.axisData.color[2]);
tickChar.position = new Vector3(xmin, ymin - 0.1 * ymax, tickPos);
this._tickLabels.push(tickChar);
Expand Down
4 changes: 3 additions & 1 deletion HeatMap.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Scene } from "@babylonjs/core/scene";
import { Plot, LegendData } from "./babyplots";
export declare class HeatMap extends Plot {
constructor(scene: Scene, coordinates: number[][], colorVar: string[], size: number, legendData: LegendData);
scaleColumn: number;
scaleRow: number;
constructor(scene: Scene, coordinates: number[][], colorVar: string[], size: number, scaleColumn: number, scaleRow: number, legendData: LegendData);
private _createHeatMap;
}
24 changes: 18 additions & 6 deletions HeatMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
import { Plot, LegendData, matrixMax } from "./babyplots";

export class HeatMap extends Plot {
constructor(scene: Scene, coordinates: number[][], colorVar: string[], size: number, legendData: LegendData) {
scaleColumn: number;
scaleRow: number;
constructor(scene: Scene, coordinates: number[][], colorVar: string[], size: number, scaleColumn: number, scaleRow: number, legendData: LegendData) {
super(scene, coordinates, colorVar, size, legendData);
this.scaleColumn = scaleColumn;
this.scaleRow = scaleRow;
this._createHeatMap();
}
private _createHeatMap(): void {
Expand All @@ -22,19 +26,27 @@ export class HeatMap extends Plot {
let height = coord / max * this._size;
let box = BoxBuilder.CreateBox("box_" + row + "-" + column, {
height: height,
width: 1,
depth: 1
width: this.scaleColumn,
depth: this.scaleRow
}, this._scene);
box.position = new Vector3(row + 0.5, height / 2, column + 0.5);
box.position = new Vector3(
row * this.scaleColumn + 0.5 * this.scaleColumn,
height / 2,
column * this.scaleRow + 0.5 * this.scaleRow
);
let mat = new StandardMaterial("box_" + row + "-" + column + "_color", this._scene);
mat.alpha = 1;
mat.diffuseColor = Color3.FromHexString(this._coordColors[column + row * rowCoords.length].substring(0, 7));
box.material = mat;
boxes.push(box);
}
else {
let box = PlaneBuilder.CreatePlane("box_" + row + "-" + column, { size: 1 }, this._scene);
box.position = new Vector3(row + 0.5, 0, column + 0.5);
let box = PlaneBuilder.CreatePlane("box_" + row + "-" + column, { width: this.scaleColumn, height: this.scaleRow }, this._scene);
box.position = new Vector3(
row * this.scaleColumn + 0.5 * this.scaleColumn,
0,
column * this.scaleRow + 0.5 * this.scaleRow
);
box.rotation.x = Math.PI / 2;
let mat = new StandardMaterial("box_" + row + "-" + column + "_color", this._scene);
mat.alpha = 1;
Expand Down
4 changes: 3 additions & 1 deletion Surface.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Scene } from "@babylonjs/core/scene";
import { Plot, LegendData } from "./babyplots";
export declare class Surface extends Plot {
constructor(scene: Scene, coordinates: number[][], colorVar: string[], size: number, legendData: LegendData);
scaleColumn: number;
scaleRow: number;
constructor(scene: Scene, coordinates: number[][], colorVar: string[], size: number, scaleColumn: number, scaleRow: number, legendData: LegendData);
private _createSurface;
}
17 changes: 14 additions & 3 deletions Surface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import chroma from "chroma-js";


export class Surface extends Plot {
constructor(scene: Scene, coordinates: number[][], colorVar: string[], size: number, legendData: LegendData) {
scaleColumn: number;
scaleRow: number;
constructor(scene: Scene, coordinates: number[][], colorVar: string[], size: number, scaleColumn: number, scaleRow: number, legendData: LegendData) {
super(scene, coordinates, colorVar, size, legendData);
this.scaleColumn = scaleColumn;
this.scaleRow = scaleRow;
this._createSurface();
}
private _createSurface(): void {
Expand All @@ -20,9 +24,16 @@ export class Surface extends Plot {
const rowCoords = this._coords[row];
for (let column = 0; column < rowCoords.length; column++) {
const coord = rowCoords[column];
positions.push(column, coord / max * this._size, row);
positions.push(column * this.scaleRow, coord / max * this._size, row * this.scaleColumn);
if (row < this._coords.length - 1 && column < rowCoords.length - 1) {
indices.push(column + row * rowCoords.length, rowCoords.length + row * rowCoords.length + column, column + row * rowCoords.length + 1, column + row * rowCoords.length + 1, rowCoords.length + row * rowCoords.length + column, rowCoords.length + row * rowCoords.length + column + 1);
indices.push(
column + row * rowCoords.length,
rowCoords.length + row * rowCoords.length + column,
column + row * rowCoords.length + 1,
column + row * rowCoords.length + 1,
rowCoords.length + row * rowCoords.length + column,
rowCoords.length + row * rowCoords.length + column + 1
);
}
}
}
Expand Down
31 changes: 19 additions & 12 deletions babyplots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,16 @@ export class Plots {
this.scene.clearColor = Color4.FromHexString(this._backgroundColor);
}
if (plotData["coordinates"] && plotData["plotType"] && plotData["colorBy"]) {
console.log(plotData);
this.addPlot(
plotData["coordinates"],
plotData["plotType"],
plotData["colorBy"],
plotData["colorVar"],
{
size: plotData["size"],
scaleColumn: plotData["scaleColumn"],
scaleRow: plotData["scaleRow"],
colorScale: plotData["colorScale"],
customColorScale: plotData["customColorScale"],
colorScaleInverted: plotData["colorScaleInverted"],
Expand Down Expand Up @@ -633,6 +636,8 @@ export class Plots {
// default options
let opts = {
size: 1,
scaleColumn: 1,
scaleRow: 1,
colorScale: "Oranges",
customColorScale: [],
colorScaleInverted: false,
Expand Down Expand Up @@ -665,6 +670,8 @@ export class Plots {
colorBy: colorBy,
colorVar: colorVar,
size: opts.size,
scaleColumn: opts.scaleColumn,
scaleRow: opts.scaleRow,
colorScale: opts.colorScale,
customColorScale: opts.customColorScale,
colorScaleInverted: opts.colorScaleInverted,
Expand Down Expand Up @@ -863,25 +870,25 @@ export class Plots {
scale = [1, 1, 1]
break;
case "surface":
plot = new Surface(this.scene, coordinates, coordColors, opts.size, legendData);
rangeX = [0, coordinates.length];
rangeZ = [0, coordinates[0].length]
plot = new Surface(this.scene, coordinates, coordColors, opts.size, opts.scaleColumn, opts.scaleRow, legendData);
rangeX = [0, coordinates.length * opts.scaleColumn];
rangeZ = [0, coordinates[0].length * opts.scaleRow];
rangeY = [0, opts.size];
scale = [
1,
matrixMax(coordinates) / opts.size,
1
opts.scaleColumn,
opts.size / matrixMax(coordinates),
opts.scaleRow
]
break
case "heatMap":
plot = new HeatMap(this.scene, coordinates, coordColors, opts.size, legendData);
rangeX = [0, coordinates.length];
rangeZ = [0, coordinates[0].length]
plot = new HeatMap(this.scene, coordinates, coordColors, opts.size, opts.scaleColumn, opts.scaleRow, legendData);
rangeX = [0, coordinates.length * opts.scaleColumn];
rangeZ = [0, coordinates[0].length * opts.scaleRow];
rangeY = [0, opts.size];
scale = [
1,
matrixMax(coordinates) / opts.size,
1
opts.scaleColumn,
opts.size / matrixMax(coordinates),
opts.scaleRow
]
break
}
Expand Down
2 changes: 1 addition & 1 deletion dist/babyplots.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/babyplots.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/examples/heatMap.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions dist/examples/imagestack.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/examples/pointCloud.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/examples/surface.js

Large diffs are not rendered by default.

17 changes: 13 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Babylonjs + webpack + typescript</title>
<title>Babyplot Test</title>
<script src="dist/examples/surface.js"></script>
<script src="dist/examples/heatMap.js"></script>
<script src="dist/examples/pointCloud.js"></script>
<script src="dist/examples/imagestack.js"></script>
<script src="dist/babyplots.js"></script>
<style>
html,
body {
Expand All @@ -16,14 +21,18 @@
}

#renderCanvas {
width: 100%;
height: 100%;
width: 50%;
height: 50%;
touch-action: none;
}
</style>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<script src="dist/babyplots.js"></script>
<script>
var vis = new Baby.Plots("renderCanvas");
vis.fromJSON(heatMapData);
vis.doRender();
</script>
</body>
</html>
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@types/ccapture.js": "^1.1.0",
"@types/chroma-js": "^2.0.0",
"@types/downloadjs": "^1.4.2",
"@types/pako": "^1.0.1",
"babylonjs": "^4.1.0",
"babylonjs-gui": "^4.1.0",
"babylonjs-loaders": "^4.1.0",
Expand Down
1 change: 0 additions & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ module.exports = {
}]
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin(),
]
Expand Down

0 comments on commit 4b7ad4d

Please sign in to comment.