Parametrization

This commit is contained in:
Emanuele Bezzi
2021-12-07 19:42:40 -05:00
parent b048bbfd0c
commit efe3bf7a72
10 changed files with 177 additions and 36 deletions
+2
View File
@@ -8,6 +8,7 @@ import {
import { loadUserColorConfig } from "../util/stateManager/colorHelpers";
import * as selnActions from "./selection";
import * as annoActions from "./annotation";
import * as spatialActions from "./spatial";
import * as viewActions from "./viewStack";
import * as embActions from "./embedding";
import * as genesetActions from "./geneset";
@@ -272,4 +273,5 @@ export default {
genesetDelete: genesetActions.genesetDelete,
genesetAddGenes: genesetActions.genesetAddGenes,
genesetDeleteGenes: genesetActions.genesetDeleteGenes,
requestSpatialMetadata: spatialActions.requestSpatialMetadata,
};
+35
View File
@@ -0,0 +1,35 @@
import * as globals from "../globals";
export const requestSpatialMetadata = () => async (dispatch) => {
dispatch({ type: "request spatial metadata started" });
try {
const res = await fetch(
`${globals.API.prefix}${globals.API.version}spatial/meta`,
{
method: "GET",
headers: new Headers({
Accept: "application/json",
"Content-Type": "application/json",
}),
credentials: "include",
}
);
if (!res.ok || res.headers.get("Content-Type") !== "application/json") {
return null; // TODO need a dispatch //dispatchDiffExpErrors(dispatch, res);
}
const response = await res.json();
/* then send the success case action through */
return dispatch({
type: "request spatial metadata success",
data: response,
});
} catch (error) {
return dispatch({
type: "request spatial metadata error",
error,
});
}
};
+2
View File
@@ -23,6 +23,8 @@ class App extends React.Component {
componentDidMount() {
const { dispatch } = this.props;
dispatch(actions.requestSpatialMetadata());
/* listen for url changes, fire one when we start the app up */
window.addEventListener("popstate", this._onURLChanged);
this._onURLChanged();
@@ -45,35 +45,15 @@ export default function drawSpatialImageRegl(regl) {
attributes: {
a_texCoord: [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0],
// a_position: [
// 10, 0,
// 10 + regl.prop("img_width"), 0,
// 10, 0 + regl.prop("img_height"),
// 10, 0 + regl.prop("img_height"),
// 10 + regl.prop("img_width"), 0,
// 10 + regl.prop("img_width"), 0 + regl.prop("img_height"),
// ],
a_position: [
0,
0,
0 + 1921,
0,
0,
0 + 2000,
0,
0 + 2000,
0 + 1921,
0,
0 + 1921,
0 + 2000,
],
a_position: regl.prop("rectCoords"),
},
uniforms: {
projView: regl.prop("projView"),
u_image: regl.prop("spatialImageAsTexture"),
color: [1, 0, 0, 1],
u_resolution: [1921, 2000],
u_resolution: [regl.prop("imageWidth"), regl.prop("imageHeight")],
image_width: regl.prop("imageWidth"),
// translate:
},
+50 -10
View File
@@ -78,6 +78,7 @@ function createModelTF() {
colors: state.colors,
pointDilation: state.pointDilation,
genesets: state.genesets.genesets,
spatial: state.spatial.metadata,
}))
class Graph extends React.Component {
static createReglState(canvas) {
@@ -110,19 +111,20 @@ class Graph extends React.Component {
return !shallowEqual(props.watchProps, prevProps.watchProps);
}
computePointPositions = memoize((X, Y, modelTF) => {
computePointPositions = memoize((X, Y, modelTF, spatialMetadata) => {
/*
compute the model coordinate for each point
*/
console.log({ X }, { Y });
const positions = new Float32Array(2 * X.length);
for (let i = 0, len = X.length; i < len; i += 1) {
const p = vec2.fromValues(X[i], Y[i]);
// TODO: Introduce the feature flag here
// const p = vec2.fromValues(X[i], Y[i]);
const p = this.rescalePointForSpatial(X[i], Y[i], spatialMetadata);
vec2.transformMat3(p, p, modelTF);
positions[2 * i] = p[0];
positions[2 * i + 1] = p[1];
}
console.log({ transformed: positions });
return positions;
});
@@ -238,6 +240,7 @@ class Graph extends React.Component {
colorBuffer: null,
flagBuffer: null,
drawSpatialImage: null,
spatial: null,
// component rendering derived state - these must stay synchronized
// with the reducer state they were generated from.
@@ -452,6 +455,33 @@ class Graph extends React.Component {
});
}
rescalePointForSpatial = (x, y, spatialMetadata) => {
// console.log({spatialMetadata});
const translate = vec2.fromValues(
spatialMetadata.inverseTranslate[0],
spatialMetadata.inverseTranslate[1]
);
const min = vec2.fromValues(
spatialMetadata.inverseMin[0],
spatialMetadata.inverseMin[1]
);
const scalefactor = spatialMetadata.scaleref;
const wh = vec2.fromValues(
spatialMetadata.imageWidth,
spatialMetadata.imageHeight
);
// Apply the inverse transform
const p = vec2.fromValues(x, y);
vec2.sub(p, p, translate);
vec2.scale(p, p, spatialMetadata.inverseScale);
vec2.add(p, p, min);
vec2.scale(p, p, scalefactor);
vec2.div(p, p, wh);
return p;
};
setReglCanvas = (canvas) => {
this.reglCanvas = canvas;
this.setState({
@@ -534,9 +564,12 @@ class Graph extends React.Component {
crossfilter,
pointDilation,
viewport,
spatial,
} = props.watchProps;
const { modelTF } = this.state;
console.log({ spatial });
const [layoutDf, colorDf, pointDilationDf] = await this.fetchData(
annoMatrix,
layoutChoice,
@@ -547,7 +580,7 @@ class Graph extends React.Component {
const { currentDimNames } = layoutChoice;
const X = layoutDf.col(currentDimNames[0]).asArray();
const Y = layoutDf.col(currentDimNames[1]).asArray();
const positions = this.computePointPositions(X, Y, modelTF);
const positions = this.computePointPositions(X, Y, modelTF, spatial.data);
const colorTable = this.updateColorTable(colorsProp, colorDf);
const colors = this.computePointColors(colorTable.rgb);
@@ -579,6 +612,7 @@ class Graph extends React.Component {
flags,
width,
height,
spatial,
};
};
@@ -760,7 +794,6 @@ class Graph extends React.Component {
const { positions, colors, flags, height, width } = asyncProps;
this.cachedAsyncProps = asyncProps;
const { pointBuffer, colorBuffer, flagBuffer } = this.state;
console.log({ pos2: positions });
let needToRenderCanvas = false;
if (height !== prevAsyncProps?.height || width !== prevAsyncProps?.width) {
@@ -824,20 +857,21 @@ class Graph extends React.Component {
projectionTF,
drawSpatialImage
) {
const { annoMatrix } = this.props;
const { annoMatrix, spatial } = this.props;
if (!this.reglCanvas || !annoMatrix) return;
const { schema } = annoMatrix;
const cameraTF = camera.view();
const projView = mat3.multiply(mat3.create(), projectionTF, cameraTF);
const { width, height } = this.reglCanvas;
const imW = spatial.data.imageWidth;
const imH = spatial.data.imageHeight;
regl.poll();
regl.clear({
depth: 1,
color: [0, 0, 0, 0],
});
console.log({ pointBuffer });
console.log({ projView });
drawPoints({
distance: camera.distance(),
color: colorBuffer,
@@ -850,8 +884,9 @@ class Graph extends React.Component {
});
drawSpatialImage({
projView,
img_width: this.spatialImage.width,
img_height: this.spatialImage.height,
imageWidth: imW,
imageHeight: imH,
rectCoords: [0, 0, imW, 0, 0, imH, 0, imH, imW, 0, imW, imH],
spatialImageAsTexture: regl.texture({
data: this.spatialImage,
wrapS: "clamp",
@@ -869,10 +904,14 @@ class Graph extends React.Component {
layoutChoice,
pointDilation,
crossfilter,
spatial,
} = this.props;
const { modelTF, projectionTF, camera, viewport, regl } = this.state;
const cameraTF = camera?.view()?.slice();
console.log("---RENDER");
console.log({ props: this.props });
return (
<div
id="graph-wrapper"
@@ -939,6 +978,7 @@ class Graph extends React.Component {
pointDilation,
crossfilter,
viewport,
spatial,
}}
>
<Async.Pending initial>
+3
View File
@@ -11,6 +11,7 @@ import continuousSelection from "./continuousSelection";
import graphSelection from "./graphSelection";
import colors from "./colors";
import differential from "./differential";
import spatial from "./spatial";
import layoutChoice from "./layoutChoice";
import controls from "./controls";
import annotations from "./annotations";
@@ -38,6 +39,7 @@ const Reducer = undoable(
["colors", colors],
["controls", controls],
["differential", differential],
["spatial", spatial],
["centroidLabels", centroidLabels],
["pointDilation", pointDialation],
["autosave", autosave],
@@ -51,6 +53,7 @@ const Reducer = undoable(
"colors",
"controls",
"differential",
"spatial",
"layoutChoice",
"centroidLabels",
"genesets",
+34
View File
@@ -0,0 +1,34 @@
const Spatial = (
state = {
loading: null,
error: null,
metadata: null,
},
action
) => {
switch (action.type) {
case "request spatial metadata started":
return {
...state,
loading: true,
error: null,
};
case "request spatial metadata success":
return {
...state,
error: null,
loading: false,
metadata: action,
};
case "request spatial metadata error":
return {
...state,
loading: false,
error: action.data,
};
default:
return state;
}
};
export default Spatial;