gramene-search 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.parcel-cache/4987902b3f9787cc-BundleGraph-0 +0 -0
- package/.parcel-cache/70f1f7555dda250d-AssetGraph-0 +0 -0
- package/.parcel-cache/7b8e4611c0f03524-AssetGraph-0 +0 -0
- package/.parcel-cache/data.mdb +0 -0
- package/.parcel-cache/lock.mdb +0 -0
- package/.parcel-cache/requestGraph-369948a06d23ec44-0 +0 -0
- package/.parcel-cache/requestGraph-nodes-0-369948a06d23ec44-0 +0 -0
- package/.parcel-cache/snapshot-369948a06d23ec44.txt +2 -2
- package/dist/BAR-logo.15c36467.png +0 -0
- package/dist/{Study.b2ce28e8.js → Study.5ff9518c.js} +9 -4
- package/dist/Study.5ff9518c.js.map +1 -0
- package/dist/android-chrome-192x192.4d149c27.png +0 -0
- package/dist/apple-touch-icon-114x114.27e956ae.png +0 -0
- package/dist/apple-touch-icon-120x120.b209ed9f.png +0 -0
- package/dist/apple-touch-icon-144x144.9f8e2136.png +0 -0
- package/dist/apple-touch-icon-152x152.b6107a9b.png +0 -0
- package/dist/apple-touch-icon-180x180.58fbcc65.png +0 -0
- package/dist/apple-touch-icon-57x57.f670c755.png +0 -0
- package/dist/apple-touch-icon-60x60.3fbc15ae.png +0 -0
- package/dist/apple-touch-icon-72x72.a0fd991d.png +0 -0
- package/dist/apple-touch-icon-76x76.437b43b5.png +0 -0
- package/dist/expression-atlas-logo.2d957e5a.png +0 -0
- package/dist/favicon-16x16.4dd6b101.png +0 -0
- package/dist/favicon-32x32.a0d53b79.png +0 -0
- package/dist/favicon-96x96.6cd9b68e.png +0 -0
- package/dist/genetree.d75946eb.png +0 -0
- package/dist/index.js +121 -45
- package/dist/index.js.map +1 -1
- package/dist/results.a8da7555.png +0 -0
- package/dist/sorghum.html +39 -0
- package/dist/suggestions.099b7c0e.png +0 -0
- package/package.json +1 -1
- package/src/bundles/docs.js +15 -1
- package/src/bundles/views.js +3 -2
- package/src/components/results/Expression.js +18 -10
- package/src/components/results/Study.js +10 -3
- package/src/components/results/details/Expression.js +66 -8
- package/src/components/results/details/VEP.js +1 -1
- package/src/demo.js +1 -0
- package/src/static/atlasWidget.html +12 -4
- package/dist/Study.b2ce28e8.js.map +0 -1
|
Binary file
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Gramene Search</title>
|
|
6
|
+
<link rel="stylesheet" href="/sorghum.d3289a0b.css"><script>window.gramene = {};
|
|
7
|
+
gramene.defaultServer = "https://data.sorghumbase.org/sorghum_v6/swagger";
|
|
8
|
+
|
|
9
|
+
</script>
|
|
10
|
+
<script async="" src="/sorghum.250fb7b9.js"></script>
|
|
11
|
+
<script async="" src="https://plantreactome.gramene.org/DiagramJs/diagram/diagram.nocache.js"></script>
|
|
12
|
+
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.f670c755.png">
|
|
13
|
+
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.3fbc15ae.png">
|
|
14
|
+
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.a0fd991d.png">
|
|
15
|
+
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.437b43b5.png">
|
|
16
|
+
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.27e956ae.png">
|
|
17
|
+
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.b209ed9f.png">
|
|
18
|
+
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.9f8e2136.png">
|
|
19
|
+
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.b6107a9b.png">
|
|
20
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.58fbcc65.png">
|
|
21
|
+
<link rel="icon" type="image/png" href="/favicon-32x32.a0d53b79.png" sizes="32x32">
|
|
22
|
+
<link rel="icon" type="image/png" href="/android-chrome-192x192.4d149c27.png" sizes="192x192">
|
|
23
|
+
<link rel="icon" type="image/png" href="/favicon-96x96.6cd9b68e.png" sizes="96x96">
|
|
24
|
+
<link rel="icon" type="image/png" href="/favicon-16x16.4dd6b101.png" sizes="16x16">
|
|
25
|
+
</head>
|
|
26
|
+
<body>
|
|
27
|
+
<div id="demo"></div>
|
|
28
|
+
<script src="/sorghum.b34cb912.js" defer=""></script>
|
|
29
|
+
<script>document.addEventListener("keyup", possiblyFocus);
|
|
30
|
+
function possiblyFocus(e) {
|
|
31
|
+
if (e.key === "/") {
|
|
32
|
+
var el = document.getElementById("search-input");
|
|
33
|
+
if (el) el.focus();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
</script>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
|
Binary file
|
package/package.json
CHANGED
package/src/bundles/docs.js
CHANGED
|
@@ -11,6 +11,7 @@ const grameneDocs = {
|
|
|
11
11
|
rnaSequences: {},
|
|
12
12
|
pepSequences: {},
|
|
13
13
|
studies: {},
|
|
14
|
+
desiredSamples: {},
|
|
14
15
|
consequences: {}
|
|
15
16
|
};
|
|
16
17
|
return (state = initialState, {type, payload}) => {
|
|
@@ -116,10 +117,22 @@ const grameneDocs = {
|
|
|
116
117
|
newState.expression = Object.assign({}, state.expression);
|
|
117
118
|
newState.expression[payload.id] = payload.paralogs;
|
|
118
119
|
return newState;
|
|
120
|
+
case 'EXPRESSION_SAMPLE_TOGGLED':
|
|
121
|
+
newState = Object.assign({}, state);
|
|
122
|
+
newState.desiredSamples = Object.assign({}, state.desiredSamples);
|
|
123
|
+
if (newState.desiredSamples.hasOwnProperty(payload)) {
|
|
124
|
+
delete newState.desiredSamples[payload]
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
newState.desiredSamples[payload] = {status: 'need'}
|
|
128
|
+
}
|
|
119
129
|
}
|
|
120
130
|
return state;
|
|
121
131
|
}
|
|
122
132
|
},
|
|
133
|
+
doToggleExpressionSample: id => ({dispatch}) => {
|
|
134
|
+
dispatch({type: 'EXPRESSION_SAMPLE_TOGGLED', payload: id});
|
|
135
|
+
},
|
|
123
136
|
doRequestVEP: id => ({dispatch, store}) => {
|
|
124
137
|
const consequences = store.selectGrameneConsequences();
|
|
125
138
|
if (!consequences.hasOwnProperty(id)) {
|
|
@@ -323,7 +336,8 @@ const grameneDocs = {
|
|
|
323
336
|
selectGeneSequences: state => state.grameneDocs.sequences,
|
|
324
337
|
selectRnaSequences: state => state.grameneDocs.rnaSequences,
|
|
325
338
|
selectPepSequences: state => state.grameneDocs.pepSequences,
|
|
326
|
-
selectAtlasStudies: state => state.grameneDocs.studies
|
|
339
|
+
selectAtlasStudies: state => state.grameneDocs.studies,
|
|
340
|
+
selectDesiredSamples: state => state.grameneDocs.desiredSamples
|
|
327
341
|
};
|
|
328
342
|
|
|
329
343
|
export default grameneDocs;
|
package/src/bundles/views.js
CHANGED
|
@@ -25,7 +25,8 @@ const grameneViews = {
|
|
|
25
25
|
id: 'expression',
|
|
26
26
|
name: 'Gene expression',
|
|
27
27
|
show: 'off',
|
|
28
|
-
shouldScroll: false
|
|
28
|
+
shouldScroll: false,
|
|
29
|
+
desiredSamples: {}
|
|
29
30
|
},
|
|
30
31
|
{
|
|
31
32
|
id: 'attribs',
|
|
@@ -86,7 +87,7 @@ const grameneViews = {
|
|
|
86
87
|
doCancelShouldScroll: () => ({dispatch, getState}) => {
|
|
87
88
|
dispatch({type: 'GRAMENE_VIEW_SCROLLED', payload: null})
|
|
88
89
|
},
|
|
89
|
-
selectGrameneViews: state => state.grameneViews
|
|
90
|
+
selectGrameneViews: state => state.grameneViews
|
|
90
91
|
};
|
|
91
92
|
|
|
92
93
|
export default grameneViews;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState, Suspense } from 'react'
|
|
2
2
|
import {connect} from "redux-bundler-react";
|
|
3
|
-
import { Accordion } from 'react-bootstrap';
|
|
3
|
+
import { Accordion, Button } from 'react-bootstrap';
|
|
4
4
|
import "./expression.css";
|
|
5
5
|
const LazyStudy = React.lazy(() => import('./Study'));
|
|
6
6
|
|
|
@@ -32,15 +32,22 @@ const Expression = props => {
|
|
|
32
32
|
.filter(tid => searchTaxa[tid] || searchTaxa[tid + '001'])
|
|
33
33
|
.sort((a,b) => props.grameneMaps[a + '001'].left_index - props.grameneMaps[b + '001'].left_index);
|
|
34
34
|
return availableTaxa && props.grameneTaxonomy &&
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
<div>
|
|
36
|
+
<div>This is where you can launch a component for the selected samples. props.desiredSamples lists them.
|
|
37
|
+
This component can request the data from the API
|
|
38
|
+
organize samples by factor metadata? One big table with all the studies?
|
|
39
|
+
<Button>Show Samples ({Object.keys(props.desiredSamples).length} selected)</Button>
|
|
40
|
+
</div>
|
|
41
|
+
<Accordion alwaysOpen defaultActiveKey={availableTaxa.length === 1 ? "tax_0" : undefined}>
|
|
42
|
+
{availableTaxa.map((tid, idx) => {
|
|
43
|
+
const n = props.expressionStudies[tid].length;
|
|
44
|
+
return <Accordion.Item key={idx} eventKey={'tax_'+idx}>
|
|
45
|
+
<Accordion.Header>{props.grameneTaxonomy[tid].name} - {n} {n === 1 ? 'study' : 'studies'}</Accordion.Header>
|
|
46
|
+
<Accordion.Body><StudyList studies={props.expressionStudies[tid]}/></Accordion.Body>
|
|
47
|
+
</Accordion.Item>
|
|
48
|
+
})}
|
|
49
|
+
</Accordion>
|
|
50
|
+
</div>
|
|
44
51
|
};
|
|
45
52
|
|
|
46
53
|
export default connect(
|
|
@@ -49,5 +56,6 @@ export default connect(
|
|
|
49
56
|
'selectGrameneTaxonomy',
|
|
50
57
|
'selectGrameneMaps',
|
|
51
58
|
'selectExpressionStudies',
|
|
59
|
+
'selectDesiredSamples', // current set of samples to fetch expression data for
|
|
52
60
|
Expression
|
|
53
61
|
);
|
|
@@ -10,10 +10,14 @@ const metaRenderer = params => {
|
|
|
10
10
|
}
|
|
11
11
|
return params.value.label
|
|
12
12
|
}
|
|
13
|
+
const sampleRenderer = params => {
|
|
14
|
+
const sampleMeta = params.value;
|
|
15
|
+
return JSON.stringify(sampleMeta,null,2);
|
|
16
|
+
}
|
|
13
17
|
const Study = props => {
|
|
14
18
|
let samples = props.expressionSamples[props.id];
|
|
15
19
|
let sampleMetadata = [];
|
|
16
|
-
let metadataFields = [{ field: "sampleId" }];
|
|
20
|
+
let metadataFields = [{ field: "sampleId", cellRenderer: sampleRenderer }];
|
|
17
21
|
let isFactor={};
|
|
18
22
|
samples.forEach((sample, idx) => {
|
|
19
23
|
if (idx === 0) {
|
|
@@ -37,7 +41,7 @@ const Study = props => {
|
|
|
37
41
|
});
|
|
38
42
|
metadataFields.push(characteristics)
|
|
39
43
|
}
|
|
40
|
-
let s_info = {sampleId: sample
|
|
44
|
+
let s_info = {sampleId: sample}
|
|
41
45
|
sample.factor.forEach(factor => {
|
|
42
46
|
s_info[factor.type] = {label: factor.label};
|
|
43
47
|
if (factor.ontology) {
|
|
@@ -70,4 +74,7 @@ const Study = props => {
|
|
|
70
74
|
</div>
|
|
71
75
|
);
|
|
72
76
|
};
|
|
73
|
-
export default connect(
|
|
77
|
+
export default connect(
|
|
78
|
+
'selectExpressionSamples',
|
|
79
|
+
'doToggleExpressionSample',
|
|
80
|
+
Study);
|
|
@@ -1,8 +1,64 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useRef, useEffect } from 'react'
|
|
2
2
|
import {connect} from "redux-bundler-react";
|
|
3
3
|
import {Tabs, Tab} from 'react-bootstrap';
|
|
4
4
|
import BAR, {haveBAR} from "gramene-efp-browser";
|
|
5
5
|
|
|
6
|
+
function DynamicIframe(props) {
|
|
7
|
+
// Create a ref for the iframe element
|
|
8
|
+
const iframeRef = useRef(null);
|
|
9
|
+
|
|
10
|
+
// Function to resize iframe height
|
|
11
|
+
const resizeIframe = () => {
|
|
12
|
+
if (iframeRef.current) {
|
|
13
|
+
const iframe = iframeRef.current;
|
|
14
|
+
const innerDoc = iframe.contentDocument || iframe.contentWindow.document;
|
|
15
|
+
iframe.style.height = 44 + innerDoc.body.scrollHeight + 'px';
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Resize iframe when content loads
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
resizeIframe();
|
|
22
|
+
}, []); // Empty dependency array ensures it only runs once after initial render
|
|
23
|
+
|
|
24
|
+
// Optional: Resize iframe when window is resized
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
window.addEventListener('resize', resizeIframe);
|
|
27
|
+
return () => {
|
|
28
|
+
window.removeEventListener('resize', resizeIframe);
|
|
29
|
+
};
|
|
30
|
+
}, []); // Empty dependency array ensures it only runs once after initial render
|
|
31
|
+
|
|
32
|
+
// Resize iframe when content changes
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const iframe = iframeRef.current;
|
|
35
|
+
if (!iframe) return;
|
|
36
|
+
|
|
37
|
+
const observer = new MutationObserver(resizeIframe);
|
|
38
|
+
const checkElement = () => {
|
|
39
|
+
const innerDoc = iframe.contentDocument || iframe.contentWindow.document;
|
|
40
|
+
const targetElement = innerDoc.querySelector('#heatmapContainer');
|
|
41
|
+
if (targetElement) {
|
|
42
|
+
observer.observe(targetElement, { attributes: true, childList: true, subtree: true });
|
|
43
|
+
} else {
|
|
44
|
+
setTimeout(checkElement, 200); // Check again after 100 milliseconds
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
checkElement();
|
|
48
|
+
|
|
49
|
+
return () => observer.disconnect();
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<iframe
|
|
54
|
+
ref={iframeRef}
|
|
55
|
+
src={props.url}
|
|
56
|
+
title="Dynamic Iframe"
|
|
57
|
+
style={{ width: '100%', border: 'none' }}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
6
62
|
const Detail = props => {
|
|
7
63
|
const gene = props.geneDocs[props.searchResult.id];
|
|
8
64
|
let paralogs_url;
|
|
@@ -18,13 +74,15 @@ const Detail = props => {
|
|
|
18
74
|
props.doRequestParalogExpression(gene._id)
|
|
19
75
|
}
|
|
20
76
|
return <Tabs>
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
77
|
+
{paralogs_url &&
|
|
78
|
+
<Tab tabClassName="gxa" eventKey="paralogs" title="Reference Study (all paralogs)">
|
|
79
|
+
<DynamicIframe url={paralogs_url}/>
|
|
80
|
+
</Tab>
|
|
81
|
+
}
|
|
82
|
+
<Tab tabClassName="gxa" eventKey="gene" title="All Studies"><DynamicIframe url={gene_url}/></Tab>
|
|
83
|
+
{haveBAR(gene) &&
|
|
84
|
+
<Tab tabClassName="eFP" eventKey="eFP" title="eFP Browser"><BAR gene={gene}/></Tab>
|
|
85
|
+
}
|
|
28
86
|
</Tabs>
|
|
29
87
|
};
|
|
30
88
|
|
|
@@ -88,7 +88,7 @@ const Detail = props => {
|
|
|
88
88
|
<h5>Predicted loss-of-function alleles were detected in these germplasm.</h5>
|
|
89
89
|
<div >Explore other variants within this gene in the <a target="_blank"
|
|
90
90
|
href={`${props.configuration.ensemblURL}/${gene.system_name}/Gene/Variation_Gene/Image?db=core;g=${props.searchResult.id}`}>
|
|
91
|
-
Variant image</a> page
|
|
91
|
+
Variant image</a> page in the Ensembl genome browser.</div>
|
|
92
92
|
<div className="ag-theme-quartz" style={{height: `${44 * (accessionTable.length + 2)}px`}}>
|
|
93
93
|
<AgGridReact rowData={accessionTable} columnDefs={tableFields} defaultColDef={defaultColDef}/>
|
|
94
94
|
</div>
|
package/src/demo.js
CHANGED
|
@@ -10,9 +10,17 @@
|
|
|
10
10
|
<body>
|
|
11
11
|
<div id="heatmapContainer"></div>
|
|
12
12
|
<script language="JavaScript" type="application/javascript">
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const queryString = location.search;
|
|
14
|
+
const urlParams = new URLSearchParams(queryString);
|
|
15
|
+
const genes = urlParams.get('genes');
|
|
16
|
+
const experiment = urlParams.get('reference');
|
|
17
|
+
const options = {
|
|
18
|
+
target: "heatmapContainer",
|
|
19
|
+
query: { gene: genes }
|
|
20
|
+
};
|
|
21
|
+
if (+experiment === 1) {
|
|
22
|
+
options["experiment"] = "reference"
|
|
23
|
+
}
|
|
24
|
+
expressionAtlasHeatmapHighcharts.render(options);
|
|
17
25
|
</script>
|
|
18
26
|
</body>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,MAAM,qCAAe,CAAA;IACnB,IAAI,OAAO,KAAK,CAAC,QAAQ,EACvB,qBAAO,gCAAC;QAAE,MAAM,CAAC,+BAA+B,EAAE,OAAO,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,KAAI,KAAK,CAAC;QAAE,QAAO;kBAAU,OAAO,KAAK,CAAC,KAAK;;IAE3H,OAAO,OAAO,KAAK,CAAC,KAAK;AAC3B;AACA,MAAM,8BAAQ,CAAA;IACZ,IAAI,UAAU,MAAM,iBAAiB,CAAC,MAAM,EAAE,CAAC;IAC/C,IAAI,iBAAiB,EAAE;IACvB,IAAI,iBAAiB;QAAC;YAAE,OAAO;QAAW;KAAE;IAC5C,IAAI,WAAS,CAAC;IACd,QAAQ,OAAO,CAAC,CAAC,QAAQ;QACvB,IAAI,QAAQ,GAAG;YACb,IAAI,UAAU;gBACZ,YAAY;gBACZ,UAAU,EAAE;YACd;YACA,OAAO,MAAM,CAAC,OAAO,CAAC,CAAA;gBACpB,QAAQ,QAAQ,CAAC,IAAI,CAAC;oBAAC,OAAO,OAAO,IAAI;oBAAE,cAAc;gBAAY;gBACrE,QAAQ,CAAC,OAAO,IAAI,CAAC,GAAG;YAC1B;YACA,eAAe,IAAI,CAAC;YACpB,IAAI,kBAAkB;gBACpB,YAAY;gBACZ,UAAU,EAAE;YACd;YACA,OAAO,cAAc,CAAC,OAAO,CAAC,CAAA;gBAC5B,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,EACpB,gBAAgB,QAAQ,CAAC,IAAI,CAAC;oBAAC,OAAO,GAAG,IAAI;oBAAE,cAAc;gBAAY;YAE7E;YACA,eAAe,IAAI,CAAC;QACtB;QACA,IAAI,SAAS;YAAC,UAAU,OAAO,KAAK;QAAA;QACpC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAA;YACpB,MAAM,CAAC,OAAO,IAAI,CAAC,GAAG;gBAAC,OAAO,OAAO,KAAK;YAAA;YAC1C,IAAI,OAAO,QAAQ,EAAE;gBACnB,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,WAAW,GAAG,OAAO,QAAQ;gBACjD,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,GAAG,OAAO,EAAE;YACvC;QACF;QACA,OAAO,cAAc,CAAC,OAAO,CAAC,CAAA;YAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG;gBAAC,OAAO,GAAG,KAAK;YAAA;YAClC,IAAI,GAAG,QAAQ,EAAE;gBACf,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,WAAW,GAAG,GAAG,QAAQ;gBACzC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG,GAAG,EAAE;YAC/B;QACF;QACA,eAAe,IAAI,CAAC;IACtB;IACA,MAAM,CAAC,SAAS,WAAW,GAAG,CAAA,GAAA,qBAAO,EAAE;IACvC,MAAM,CAAC,SAAS,WAAW,GAAG,CAAA,GAAA,qBAAO,EAAE;IACvC,MAAM,gBAAgB,CAAA,GAAA,oBAAM,EAAE;QAC5B,OAAO;YACL,QAAQ;QACV;IACF,GAAG,EAAE;IACL,qBACE,iCAAC;;0BACC,gCAAC;gBAAI,WAAU;gBAAkB,OAAO;oBAAC,QAAQ,CAAC,EAAE,KAAM,CAAA,QAAQ,MAAM,GAAG,CAAA,EAAG,EAAE,CAAC;gBAAA;0BAC/E,cAAA,gCAAC,CAAA,GAAA,8BAAU;oBAAE,SAAS;oBAAS,YAAY;oBAAS,eAAe;;;0BAErE,iCAAC;gBAAE,MAAM,CAAC,sCAAsC,EAAE,MAAM,EAAE,CAAC,CAAC;;oBAAE;oBAAuB,MAAM,EAAE;;;;;AAGnG;IACA,2CAAe,CAAA,GAAA,gCAAM,EAAE,2BAA2B","sources":["src/components/results/Study.js"],"sourcesContent":["import React, { useState, useMemo } from 'react'\nimport {connect} from \"redux-bundler-react\";\nimport { AgGridReact } from \"ag-grid-react\";\nimport \"ag-grid-community/styles/ag-grid.css\";\nimport \"ag-grid-community/styles/ag-theme-quartz.css\";\n\nconst metaRenderer = params => {\n if (params.value.ontology) {\n return <a href={`http://purl.obolibrary.org/obo/${params.value.id.replace(\":\",\"_\")}`} target='_blank'>{params.value.label}</a>\n }\n return params.value.label\n}\nconst Study = props => {\n let samples = props.expressionSamples[props.id];\n let sampleMetadata = [];\n let metadataFields = [{ field: \"sampleId\" }];\n let isFactor={};\n samples.forEach((sample, idx) => {\n if (idx === 0) {\n let factors = {\n headerName: 'Experimental Variables',\n children: []\n }\n sample.factor.forEach(factor => {\n factors.children.push({field: factor.type, cellRenderer: metaRenderer})\n isFactor[factor.type] = true;\n });\n metadataFields.push(factors);\n let characteristics = {\n headerName: 'Sample Characteristics',\n children: []\n }\n sample.characteristic.forEach(ch => {\n if (!isFactor[ch.type]) {\n characteristics.children.push({field: ch.type, cellRenderer: metaRenderer})\n }\n });\n metadataFields.push(characteristics)\n }\n let s_info = {sampleId: sample.group}\n sample.factor.forEach(factor => {\n s_info[factor.type] = {label: factor.label};\n if (factor.ontology) {\n s_info[factor.type]['ontology'] = factor.ontology\n s_info[factor.type]['id'] = factor.id;\n }\n })\n sample.characteristic.forEach(ch => {\n s_info[ch.type] = {label: ch.label};\n if (ch.ontology) {\n s_info[ch.type]['ontology'] = ch.ontology\n s_info[ch.type]['id'] = ch.id;\n }\n })\n sampleMetadata.push(s_info)\n })\n const [rowData, setRowData] = useState(sampleMetadata);\n const [colDefs, setColDefs] = useState(metadataFields);\n const defaultColDef = useMemo(() => {\n return {\n filter: true\n }\n }, []);\n return (\n <div>\n <div className=\"ag-theme-quartz\" style={{height: `${44 * (samples.length + 2)}px`}}>\n <AgGridReact rowData={rowData} columnDefs={colDefs} defaultColDef={defaultColDef}/>\n </div>\n <a href={`https://www.ebi.ac.uk/gxa/experiments/${props.id}`}>EBI Atlas Experiment: {props.id}</a>\n </div>\n );\n};\nexport default connect('selectExpressionSamples', Study);\n"],"names":[],"version":3,"file":"Study.b2ce28e8.js.map"}
|