Switch to unified view

a b/src/pages/GeneAnalysis/GeneAnalysis.tsx
1
import React, { useState, useCallback } from 'react';
2
import {
3
  Box,
4
  Typography,
5
  Paper,
6
  Grid,
7
  Card,
8
  CardContent,
9
  Button,
10
  Select,
11
  MenuItem,
12
  FormControl,
13
  InputLabel,
14
  CircularProgress,
15
  Alert,
16
  LinearProgress,
17
} from '@mui/material';
18
import {
19
  LineChart,
20
  Line,
21
  XAxis,
22
  YAxis,
23
  CartesianGrid,
24
  Tooltip,
25
  Legend,
26
  ResponsiveContainer,
27
} from 'recharts';
28
import { GeneAssembly } from '../../types';
29
import { usePipeline, useGenomicAnalyses } from '../../hooks/usePipeline';
30
import { mockGeneAssemblies } from '../../data/mockData';
31
32
const defaultExperimentConfig = {
33
  id: Math.random().toString(36).substr(2, 9),
34
  name: 'Gene Analysis Experiment',
35
  environmentalParams: {
36
    temperature: 25,
37
    humidity: 60,
38
    soilConditions: 'Controlled',
39
  },
40
  duration: 30,
41
  samplingFrequency: 24,
42
  baselineGenotypes: ['WT-Col-0'],
43
  targetTraits: ['stress_tolerance', 'growth_rate'],
44
};
45
46
const GeneAnalysis: React.FC = () => {
47
  const [selectedAssembly, setSelectedAssembly] = useState<string>('');
48
  const { startPipeline, isProcessing, error, clearError } = usePipeline();
49
  const analysisResults = useGenomicAnalyses();
50
51
  const handleAnalyze = useCallback(async () => {
52
    if (!selectedAssembly) return;
53
54
    const assembly = mockGeneAssemblies.find(a => a.id === selectedAssembly);
55
    if (!assembly) return;
56
57
    await startPipeline({
58
      experimentConfig: {
59
        ...defaultExperimentConfig,
60
        name: `Analysis of ${assembly.name}`,
61
      },
62
      assembly,
63
    });
64
  }, [selectedAssembly, startPipeline]);
65
66
  const renderAnalysisResults = () => {
67
    if (!analysisResults.length) return null;
68
69
    const latestResult = analysisResults[analysisResults.length - 1];
70
    const geneExpressionData = latestResult.metrics.geneExpression.map((value, index) => ({
71
      time: `T${index}`,
72
      expression: value,
73
    }));
74
75
    return (
76
      <Card sx={{ mt: 3 }}>
77
        <CardContent>
78
          <Typography variant="h6" gutterBottom>
79
            Analysis Results
80
          </Typography>
81
          <Grid container spacing={3}>
82
            <Grid item xs={12}>
83
              <Typography variant="subtitle2">Gene Expression Levels</Typography>
84
              <ResponsiveContainer width="100%" height={300}>
85
                <LineChart data={geneExpressionData}>
86
                  <CartesianGrid strokeDasharray="3 3" />
87
                  <XAxis dataKey="time" />
88
                  <YAxis />
89
                  <Tooltip />
90
                  <Legend />
91
                  <Line
92
                    type="monotone"
93
                    dataKey="expression"
94
                    stroke="#8884d8"
95
                    name="Expression Level"
96
                  />
97
                </LineChart>
98
              </ResponsiveContainer>
99
            </Grid>
100
            <Grid item xs={12} md={6}>
101
              <Typography variant="subtitle2" gutterBottom>
102
                Regulatory Elements
103
              </Typography>
104
              {latestResult.metrics.regulatoryElements.map((element, index) => (
105
                <Typography key={index} variant="body2">
106
                  • {element}
107
                </Typography>
108
              ))}
109
            </Grid>
110
            <Grid item xs={12} md={6}>
111
              <Typography variant="subtitle2" gutterBottom>
112
                Pathway Enrichment
113
              </Typography>
114
              {latestResult.metrics.pathwayEnrichment.map((pathway, index) => (
115
                <Box key={index} sx={{ mb: 1 }}>
116
                  <Typography variant="body2">
117
                    {pathway.pathway}: {(pathway.score * 100).toFixed(1)}%
118
                  </Typography>
119
                  <LinearProgress
120
                    variant="determinate"
121
                    value={pathway.score * 100}
122
                    sx={{ height: 8, borderRadius: 4 }}
123
                  />
124
                </Box>
125
              ))}
126
            </Grid>
127
          </Grid>
128
        </CardContent>
129
      </Card>
130
    );
131
  };
132
133
  return (
134
    <Box>
135
      <Typography variant="h4" gutterBottom>
136
        Gene Analysis
137
      </Typography>
138
139
      {error && (
140
        <Alert severity="error" onClose={clearError} sx={{ mb: 2 }}>
141
          {error}
142
        </Alert>
143
      )}
144
145
      <Grid container spacing={3}>
146
        <Grid item xs={12} md={4}>
147
          <Paper sx={{ p: 2 }}>
148
            <Typography variant="h6" gutterBottom>
149
              Gene Assembly Selection
150
            </Typography>
151
            <FormControl fullWidth sx={{ mb: 2 }}>
152
              <InputLabel>Select Assembly</InputLabel>
153
              <Select
154
                value={selectedAssembly}
155
                label="Select Assembly"
156
                onChange={(e) => setSelectedAssembly(e.target.value)}
157
              >
158
                {mockGeneAssemblies.map((assembly) => (
159
                  <MenuItem key={assembly.id} value={assembly.id}>
160
                    {assembly.name}
161
                  </MenuItem>
162
                ))}
163
              </Select>
164
            </FormControl>
165
            <Button
166
              variant="contained"
167
              fullWidth
168
              onClick={handleAnalyze}
169
              disabled={!selectedAssembly || isProcessing}
170
            >
171
              {isProcessing ? <CircularProgress size={24} /> : 'Analyze Assembly'}
172
            </Button>
173
          </Paper>
174
        </Grid>
175
176
        <Grid item xs={12} md={8}>
177
          {renderAnalysisResults()}
178
        </Grid>
179
      </Grid>
180
    </Box>
181
  );
182
};
183
184
export default GeneAnalysis;