diff --git a/embryo-frontend/src/pages/EmbryoGeneration.tsx b/embryo-frontend/src/pages/EmbryoGeneration.tsx
index 87c8af8..4a9e23d 100644
--- a/embryo-frontend/src/pages/EmbryoGeneration.tsx
+++ b/embryo-frontend/src/pages/EmbryoGeneration.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect, useRef, useCallback } from "react";
+import React, { useState, useEffect, useRef, useCallback, useMemo } from "react";
import axios from "axios";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
@@ -34,10 +34,23 @@ interface AnimationSectionConfig {
};
layout: LayoutConfig;
}
+const CELL_COLORS = [
+ '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
+ '#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9',
+ '#F8C471', '#82E0AA', '#F1948A', '#85CDCE', '#D7BDE2',
+ '#A9DFBF', '#F9E79F', '#D5A6BD', '#AED6F1', '#E8DAEF',
+ '#FF9A8B', '#FF6CAB', '#C56CF0', '#6C5CE7', '#81ECEC',
+ '#74B9FF', '#A8E6CF', '#DCEDC1', '#FFD3B6', '#FFAAA5',
+ '#FFC3A0', '#FF677D', '#B2EBF2', '#80CBC4', '#C5E1A5',
+ '#FFF176', '#FFD54F', '#FFB347', '#B39DDB', '#9FA8DA',
+ '#90CAF9', '#64B5F6', '#4DD0E1', '#4DB6AC', '#81C784',
+ '#A5D6A7', '#E6EE9C', '#DCE775', '#FF8A65', '#F06292'
+];
+
const ANIMATION_SECTIONS: AnimationSectionConfig[] = [
{
id: "human-cs",
- title: "Human Carnegie stages",
+ title: "Human gastrulation",
description: "CS7 and CS8 point clouds converge into CS7.5 to highlight human embryonic development.",
stages: {
sourceLeft: "CS7",
@@ -59,7 +72,7 @@ const ANIMATION_SECTIONS: AnimationSectionConfig[] = [
},
{
id: "mouse-early",
- title: "Mouse early gastrulation",
+ title: "Mouse organogenesis",
description: "Mouse 7.5 and 7.75 datasets merge toward stage 8.5, mirroring the human pipeline.",
stages: {
// sourceLeft: "GSM9046243_Embryo_E7.5_stereo_rep1",
@@ -98,7 +111,7 @@ const EmbryoGeneration: React.FC = () => {
Embryo Generation
- Observe cell migration and merging across human CS7/CS8/CS7.5 and mouse 7.5/7.75/8.5 datasets with the same control workflow.
+ Observe cell migration and merging across human CS7/CS8/CS7.5 and mouse 7.5/7.75/8.0 datasets with the same control workflow.
@@ -136,7 +149,7 @@ interface EmbryoAnimationSectionProps {
}
const EmbryoAnimationSection: React.FC
= ({ config }) => {
- const { stages, title, description, layout } = config;
+ const { stages, title, layout } = config;
const { sourceLeft, sourceRight, target } = stages;
const [sourceLeftData, setSourceLeftData] = useState([]);
const [sourceRightData, setSourceRightData] = useState([]);
@@ -206,15 +219,14 @@ const EmbryoAnimationSection: React.FC = ({ config
setAnimationProgress(0);
};
- const datasetLabel = `${sourceLeft} + ${sourceRight} -> ${target}`;
const progressPercent = Math.round(animationProgress * 100);
return (
{title}
-
{description}
-
Dataset: {datasetLabel}
+ {/*
{description}
+
Dataset: {datasetLabel}
*/}
= ({ sourceL
const animationIdRef = useRef
(null);
const animationStateRef = useRef(null);
- const { leftOffsetX, rightOffsetX, targetOffsetX = 0, cameraParams, transFunc = null } = layout;
+ const { leftOffsetX, rightOffsetX, targetOffsetX = 0, cameraParams, transFunc } = layout;
if (transFunc) {
for (let i = 0; i < sourceLeftData.length; i++) {
@@ -339,17 +351,20 @@ const UnifiedEmbryoAnimation: React.FC = ({ sourceL
}
}
+ const legendEntries = useMemo(() => {
+ const allData = [...sourceLeftData, ...sourceRightData, ...targetData];
+ const cellTypes = Array.from(new Set(allData.map(p => p.value as string))).sort();
+ return cellTypes.map((type, idx) => ({
+ type,
+ color: CELL_COLORS[idx % CELL_COLORS.length]
+ }));
+ }, [sourceLeftData, sourceRightData, targetData]);
+
const getColorMap = (allData: Point[]) => {
const cellTypes = Array.from(new Set(allData.map(p => p.value as string))).sort();
- const colors = [
- '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
- '#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9',
- '#F8C471', '#82E0AA', '#F1948A', '#85CDCE', '#D7BDE2',
- '#A9DFBF', '#F9E79F', '#D5A6BD', '#AED6F1', '#E8DAEF'
- ];
const colorMap = new Map();
cellTypes.forEach((type, idx) => {
- colorMap.set(type, new THREE.Color(colors[idx % colors.length]));
+ colorMap.set(type, new THREE.Color(CELL_COLORS[idx % CELL_COLORS.length]));
});
return colorMap;
};
@@ -409,7 +424,7 @@ const UnifiedEmbryoAnimation: React.FC = ({ sourceL
sceneRef.current = scene;
const camera = new THREE.PerspectiveCamera(cameraParams.fov, width / height, cameraParams.near, cameraParams.far);
camera.position.set(cameraParams.position.x, cameraParams.position.y, cameraParams.position.z);
- camera.lookAt(0, 0, 0);
+ camera.lookAt(cameraParams.lookAt);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(width, height);
rendererRef.current = renderer;
@@ -559,10 +574,6 @@ const UnifiedEmbryoAnimation: React.FC = ({ sourceL
const toBaseY = to.y;
const toBaseZ = to.z;
- if (i < 5) {
- console.log(`Point ${i}: from (${fromX.toFixed(2)}, ${fromY.toFixed(2)}, ${fromZ.toFixed(2)}) to (${toBaseX.toFixed(2)}, ${toBaseY.toFixed(2)}, ${toBaseZ.toFixed(2)})`);
- }
-
fromPositions[fromBaseIndex] = fromX;
fromPositions[fromBaseIndex + 1] = fromY;
fromPositions[fromBaseIndex + 2] = fromZ;
@@ -700,7 +711,52 @@ const UnifiedEmbryoAnimation: React.FC = ({ sourceL
applyAnimationProgress(animationProgress);
}, [animationProgress, applyAnimationProgress]);
- return ;
+ return (
+
+
+ {legendEntries.length > 0 && (
+
+
Legend
+
+ {legendEntries.map((entry) => (
+
+
+ {entry.type}
+
+ ))}
+
+
+ )}
+
+ );
};
// 创建纹理贴图(与PointsMaterial相同)