@weng-lab/genomebrowser-ui 0.2.6 → 0.2.8

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.
@@ -5,11 +5,12 @@ import {
5
5
  useGridApiContext,
6
6
  } from "@mui/x-data-grid-premium";
7
7
  import { Stack, capitalize } from "@mui/material";
8
- import Check from "@mui/icons-material/Check";
9
8
  import { AssayIcon, ontologyTypes, assayTypes, lifeStages } from "./constants";
10
- import { BiosampleRowInfo } from "./types";
9
+ import { BiosampleRowInfo, CollectionType } from "./types";
11
10
 
12
- function CoreCollectionCell(params: GridRenderCellParams<BiosampleRowInfo>) {
11
+ const collectionTypes: CollectionType[] = ["Core", "Ancillary", "Partial"];
12
+
13
+ function CollectionCell(params: GridRenderCellParams<BiosampleRowInfo>) {
13
14
  const apiRef = useGridApiContext();
14
15
 
15
16
  if (params.rowNode.type !== "group") {
@@ -30,11 +31,7 @@ function CoreCollectionCell(params: GridRenderCellParams<BiosampleRowInfo>) {
30
31
  childIds[0],
31
32
  ) as BiosampleRowInfo | null;
32
33
 
33
- if (firstChildRow?.coreCollection) {
34
- return <Check color="primary" />;
35
- }
36
-
37
- return null;
34
+ return firstChildRow?.collection ?? null;
38
35
  }
39
36
 
40
37
  const displayNameCol: GridColDef<BiosampleRowInfo> = {
@@ -140,12 +137,13 @@ const lifeStageCol: GridColDef<BiosampleRowInfo> = {
140
137
  valueFormatter: (value) => value && capitalize(value),
141
138
  };
142
139
 
143
- const coreCollectionCol: GridColDef<BiosampleRowInfo> = {
144
- field: "coreCollection",
145
- headerName: "Core Collection",
146
- type: "boolean",
147
- width: 120,
148
- renderCell: (params) => <CoreCollectionCell {...params} />,
140
+ const collectionCol: GridColDef<BiosampleRowInfo> = {
141
+ field: "collection",
142
+ headerName: "Collection",
143
+ type: "singleSelect",
144
+ valueOptions: collectionTypes,
145
+ width: 100,
146
+ renderCell: (params) => <CollectionCell {...params} />,
149
147
  };
150
148
 
151
149
  const experimentCol: GridColDef<BiosampleRowInfo> = {
@@ -167,7 +165,7 @@ const idCol: GridColDef<BiosampleRowInfo> = {
167
165
  export const sortedByAssayColumns: GridColDef<BiosampleRowInfo>[] = [
168
166
  displayNameCol,
169
167
  sortedByAssayOntologyCol,
170
- coreCollectionCol,
168
+ collectionCol,
171
169
  sampleTypeCol,
172
170
  lifeStageCol,
173
171
  sortedByAssayAssayCol,
@@ -179,7 +177,7 @@ export const sortedByAssayColumns: GridColDef<BiosampleRowInfo>[] = [
179
177
  /** Default columns (ontology as top-level grouping) */
180
178
  export const defaultColumns: GridColDef<BiosampleRowInfo>[] = [
181
179
  defaultAssayCol,
182
- coreCollectionCol,
180
+ collectionCol,
183
181
  sampleTypeCol,
184
182
  lifeStageCol,
185
183
  defaultOntologyCol,
@@ -24,7 +24,7 @@ import { BiosampleTreeItem } from "./BiosampleTreeItem";
24
24
  * @returns Array of flattened BiosampleRowInfo objects, one per assay
25
25
  */
26
26
  function flattenTrackIntoRows(track: BiosampleTrackInfo): BiosampleRowInfo[] {
27
- const { ontology, lifeStage, sampleType, displayName, core } = track;
27
+ const { ontology, lifeStage, sampleType, displayName, collection } = track;
28
28
 
29
29
  // Sort assays so cCRE comes first, then maintain original order for the rest
30
30
  const sortedAssays = [...track.assays].sort((a, b) => {
@@ -46,7 +46,7 @@ function flattenTrackIntoRows(track: BiosampleTrackInfo): BiosampleRowInfo[] {
46
46
  experimentAccession,
47
47
  fileAccession,
48
48
  url,
49
- coreCollection: core ?? false,
49
+ collection,
50
50
  }),
51
51
  );
52
52
  }
@@ -2,6 +2,8 @@
2
2
  * Types for biosample folder data
3
3
  */
4
4
 
5
+ export type CollectionType = "Core" | "Ancillary" | "Partial";
6
+
5
7
  /**
6
8
  * Assay information from the JSON data
7
9
  */
@@ -23,7 +25,7 @@ export type BiosampleTrackInfo = {
23
25
  sampleType: string;
24
26
  displayName: string;
25
27
  assays: BiosampleAssayInfo[];
26
- core?: boolean;
28
+ collection: CollectionType;
27
29
  };
28
30
 
29
31
  /**
@@ -39,7 +41,7 @@ export type BiosampleRowInfo = {
39
41
  experimentAccession: string;
40
42
  fileAccession: string;
41
43
  url: string;
42
- coreCollection: boolean;
44
+ collection: CollectionType;
43
45
  };
44
46
 
45
47
  /**
@@ -1,254 +0,0 @@
1
- package main
2
-
3
- import (
4
- "encoding/json"
5
- "fmt"
6
- "os"
7
- "path"
8
- "strings"
9
- )
10
-
11
- type RNASeqTrack struct {
12
- ID string `json:"id"`
13
- Title string `json:"title"`
14
- URL string `json:"url"`
15
- RNASeqExperimentAccession string `json:"rnaseq_experiment_accession"`
16
- RNASeqFileAccession string `json:"rnaseq_file_accession"`
17
- }
18
-
19
- type OldBiosample struct {
20
- Name string `json:"name"`
21
- Ontology string `json:"ontology"`
22
- LifeStage string `json:"lifeStage"`
23
- SampleType string `json:"sampleType"`
24
- DisplayName string `json:"displayName"`
25
- DNaseExperimentAccession *string `json:"dnase_experiment_accession"`
26
- H3K4Me3ExperimentAccession *string `json:"h3k4me3_experiment_accession"`
27
- H3K27AcExperimentAccession *string `json:"h3k27ac_experiment_accession"`
28
- CTCFExperimentAccession *string `json:"ctcf_experiment_accession"`
29
- ATACExperimentAccession *string `json:"atac_experiment_accession"`
30
- DNaseFileAccession *string `json:"dnase_file_accession"`
31
- H3K4Me3FileAccession *string `json:"h3k4me3_file_accession"`
32
- H3K27AcFileAccession *string `json:"h3k27ac_file_accession"`
33
- CTCFFileAccession *string `json:"ctcf_file_accession"`
34
- ATACFileAccession *string `json:"atac_file_accession"`
35
- DNaseSignalURL string `json:"dnase_signal_url,omitempty"`
36
- H3K4Me3SignalURL string `json:"h3k4me3_signal_url,omitempty"`
37
- H3K27AcSignalURL string `json:"h3k27ac_signal_url,omitempty"`
38
- CTCFSignalURL string `json:"ctcf_signal_url,omitempty"`
39
- ATACSignalURL string `json:"atac_signal_url,omitempty"`
40
- ChromHMM string `json:"chromhmm,omitempty"`
41
- ChromHMMURL string `json:"chromhmm_url,omitempty"`
42
- RNASeqTracks []RNASeqTrack `json:"rna_seq_tracks"`
43
- BigBedURL string `json:"bigbedurl,omitempty"`
44
- }
45
-
46
- type Assay struct {
47
- ID string `json:"id"`
48
- Assay string `json:"assay"`
49
- URL string `json:"url"`
50
- ExperimentAccession string `json:"experimentAccession"`
51
- FileAccession string `json:"fileAccession"`
52
- }
53
-
54
- type NewBiosample struct {
55
- Name string `json:"name"`
56
- Ontology string `json:"ontology"`
57
- LifeStage string `json:"lifeStage"`
58
- SampleType string `json:"sampleType"`
59
- DisplayName string `json:"displayName"`
60
- Assays []Assay `json:"assays"`
61
- }
62
-
63
- func main() {
64
- if len(os.Args) < 3 {
65
- fmt.Println("Usage: go run format.go <input.json> <output.json>")
66
- os.Exit(1)
67
- }
68
-
69
- inputFile := os.Args[1]
70
- outputFile := os.Args[2]
71
-
72
- data, err := os.ReadFile(inputFile)
73
- if err != nil {
74
- fmt.Printf("Error reading input file: %v\n", err)
75
- os.Exit(1)
76
- }
77
-
78
- var inputWrapper struct {
79
- Data struct {
80
- CCREBiosampleQuery struct {
81
- Biosamples []OldBiosample `json:"biosamples"`
82
- } `json:"ccREBiosampleQuery"`
83
- } `json:"data"`
84
- }
85
- if err := json.Unmarshal(data, &inputWrapper); err != nil {
86
- fmt.Printf("Error parsing JSON: %v\n", err)
87
- os.Exit(1)
88
- }
89
- oldSamples := inputWrapper.Data.CCREBiosampleQuery.Biosamples
90
-
91
- var newSamples []NewBiosample
92
- for _, old := range oldSamples {
93
- newSample := NewBiosample{
94
- Name: old.Name,
95
- Ontology: old.Ontology,
96
- LifeStage: old.LifeStage,
97
- SampleType: old.SampleType,
98
- DisplayName: old.DisplayName,
99
- Assays: []Assay{},
100
- }
101
-
102
- // Add DNase assay if present
103
- if old.DNaseFileAccession != nil {
104
- url := old.DNaseSignalURL
105
- if url == "" {
106
- url = "https://downloads.wenglab.org/Registry-V4/" + *old.DNaseFileAccession + ".bigWig"
107
- }
108
- newSample.Assays = append(newSample.Assays, Assay{
109
- ID: "dnase-" + *old.DNaseFileAccession,
110
- Assay: "dnase",
111
- URL: url,
112
- ExperimentAccession: ptrToString(old.DNaseExperimentAccession),
113
- FileAccession: *old.DNaseFileAccession,
114
- })
115
- }
116
-
117
- // Add H3K4me3 assay if present
118
- if old.H3K4Me3FileAccession != nil {
119
- url := old.H3K4Me3SignalURL
120
- if url == "" {
121
- url = "https://downloads.wenglab.org/Registry-V4/" + *old.H3K4Me3FileAccession + ".bigWig"
122
- }
123
- newSample.Assays = append(newSample.Assays, Assay{
124
- ID: "h3k4me3-" + *old.H3K4Me3FileAccession,
125
- Assay: "h3k4me3",
126
- URL: url,
127
- ExperimentAccession: ptrToString(old.H3K4Me3ExperimentAccession),
128
- FileAccession: *old.H3K4Me3FileAccession,
129
- })
130
- }
131
-
132
- // Add H3K27ac assay if present
133
- if old.H3K27AcFileAccession != nil {
134
- url := old.H3K27AcSignalURL
135
- if url == "" {
136
- url = "https://downloads.wenglab.org/Registry-V4/" + *old.H3K27AcFileAccession + ".bigWig"
137
- }
138
- newSample.Assays = append(newSample.Assays, Assay{
139
- ID: "h3k27ac-" + *old.H3K27AcFileAccession,
140
- Assay: "h3k27ac",
141
- URL: url,
142
- ExperimentAccession: ptrToString(old.H3K27AcExperimentAccession),
143
- FileAccession: *old.H3K27AcFileAccession,
144
- })
145
- }
146
-
147
- // Add CTCF assay if present
148
- if old.CTCFFileAccession != nil {
149
- url := old.CTCFSignalURL
150
- if url == "" {
151
- url = "https://downloads.wenglab.org/Registry-V4/" + *old.CTCFFileAccession + ".bigWig"
152
- }
153
- newSample.Assays = append(newSample.Assays, Assay{
154
- ID: "ctcf-" + *old.CTCFFileAccession,
155
- Assay: "ctcf",
156
- URL: url,
157
- ExperimentAccession: ptrToString(old.CTCFExperimentAccession),
158
- FileAccession: *old.CTCFFileAccession,
159
- })
160
- }
161
-
162
- // Add ATAC assay if present
163
- if old.ATACFileAccession != nil {
164
- url := old.ATACSignalURL
165
- if url == "" {
166
- url = "https://downloads.wenglab.org/Registry-V4/" + *old.ATACFileAccession + ".bigWig"
167
- }
168
- newSample.Assays = append(newSample.Assays, Assay{
169
- ID: "atac-" + *old.ATACFileAccession,
170
- Assay: "atac",
171
- URL: url,
172
- ExperimentAccession: ptrToString(old.ATACExperimentAccession),
173
- FileAccession: *old.ATACFileAccession,
174
- })
175
- }
176
-
177
- // Add ChromHMM assay if present
178
- if old.ChromHMMURL != "" {
179
- chromhmmAccession := extractAccessionFromURL(old.ChromHMMURL)
180
- newSample.Assays = append(newSample.Assays, Assay{
181
- ID: "chromhmm-" + chromhmmAccession,
182
- Assay: "chromhmm",
183
- URL: old.ChromHMMURL,
184
- FileAccession: chromhmmAccession,
185
- })
186
- }
187
-
188
- // Add RNA-seq tracks
189
- for _, rna := range old.RNASeqTracks {
190
- url := rna.URL
191
- if url == "" {
192
- url = "https://downloads.wenglab.org/Registry-V4/" + rna.RNASeqFileAccession + ".bigWig"
193
- }
194
- newSample.Assays = append(newSample.Assays, Assay{
195
- ID: "rnaseq-" + rna.RNASeqFileAccession,
196
- Assay: "rnaseq",
197
- URL: url,
198
- ExperimentAccession: rna.RNASeqExperimentAccession,
199
- FileAccession: rna.RNASeqFileAccession,
200
- })
201
- }
202
-
203
- // Add cCRE bigBed as an assay
204
- if old.BigBedURL != "" {
205
- ccreAccession := extractAccessionFromURL(old.BigBedURL)
206
- newSample.Assays = append(newSample.Assays, Assay{
207
- ID: "ccre-" + ccreAccession,
208
- Assay: "ccre",
209
- URL: old.BigBedURL,
210
- FileAccession: ccreAccession,
211
- })
212
- }
213
-
214
- newSamples = append(newSamples, newSample)
215
- }
216
-
217
- // Wrap in object with "tracks" key to match expected format
218
- wrapper := struct {
219
- Tracks []NewBiosample `json:"tracks"`
220
- }{
221
- Tracks: newSamples,
222
- }
223
-
224
- output, err := json.MarshalIndent(wrapper, "", " ")
225
- if err != nil {
226
- fmt.Printf("Error marshaling JSON: %v\n", err)
227
- os.Exit(1)
228
- }
229
-
230
- if err := os.WriteFile(outputFile, output, 0644); err != nil {
231
- fmt.Printf("Error writing output file: %v\n", err)
232
- os.Exit(1)
233
- }
234
-
235
- fmt.Printf("Successfully converted %d biosamples to %s\n", len(newSamples), outputFile)
236
- }
237
-
238
- func ptrToString(s *string) string {
239
- if s == nil {
240
- return ""
241
- }
242
- return *s
243
- }
244
-
245
- // extractAccessionFromURL extracts the file accession from a URL
246
- // e.g., "https://downloads.wenglab.org/Registry-V4/ENCFF170YYM.bigBed" -> "ENCFF170YYM"
247
- // e.g., "https://downloads.wenglab.org/Registry-V4/ENCFF606INL_ENCFF501ILD.bigBed" -> "ENCFF606INL_ENCFF501ILD"
248
- func extractAccessionFromURL(url string) string {
249
- // Get the filename from the URL
250
- filename := path.Base(url)
251
- // Remove the extension
252
- ext := path.Ext(filename)
253
- return strings.TrimSuffix(filename, ext)
254
- }
@@ -1,158 +0,0 @@
1
- //go:build ignore
2
-
3
- package main
4
-
5
- import (
6
- "bufio"
7
- "encoding/json"
8
- "fmt"
9
- "os"
10
- "regexp"
11
- "strings"
12
- )
13
-
14
- type Assay struct {
15
- ID string `json:"id"`
16
- Assay string `json:"assay"`
17
- URL string `json:"url"`
18
- ExperimentAccession string `json:"experimentAccession"`
19
- FileAccession string `json:"fileAccession"`
20
- }
21
-
22
- type Track struct {
23
- Name string `json:"name"`
24
- Core bool `json:"core,omitempty"`
25
- Ontology string `json:"ontology"`
26
- LifeStage string `json:"lifeStage"`
27
- SampleType string `json:"sampleType"`
28
- DisplayName string `json:"displayName"`
29
- Assays []Assay `json:"assays"`
30
- }
31
-
32
- type BiosampleData struct {
33
- Tracks []Track `json:"tracks"`
34
- }
35
-
36
- // CoreSample represents a sample to be marked as core, with donor ID and display name
37
- type CoreSample struct {
38
- DonorID string
39
- DisplayName string
40
- }
41
-
42
- func main() {
43
- // Extract core samples from test.txt (donor ID + display name pairs)
44
- coreSamples, err := extractCoreSamples("test.txt")
45
- if err != nil {
46
- fmt.Fprintf(os.Stderr, "Error reading test.txt: %v\n", err)
47
- os.Exit(1)
48
- }
49
- fmt.Printf("Found %d core samples to mark\n", len(coreSamples))
50
-
51
- // Load human.json
52
- data, err := os.ReadFile("human.json")
53
- if err != nil {
54
- fmt.Fprintf(os.Stderr, "Error reading human.json: %v\n", err)
55
- os.Exit(1)
56
- }
57
-
58
- var biosampleData BiosampleData
59
- if err := json.Unmarshal(data, &biosampleData); err != nil {
60
- fmt.Fprintf(os.Stderr, "Error parsing human.json: %v\n", err)
61
- os.Exit(1)
62
- }
63
- fmt.Printf("Loaded %d tracks\n", len(biosampleData.Tracks))
64
-
65
- // Mark tracks as core if they match both donor ID and display name
66
- markedCount := 0
67
- alreadyCore := 0
68
- for i := range biosampleData.Tracks {
69
- track := &biosampleData.Tracks[i]
70
- for _, sample := range coreSamples {
71
- // Check if track name ends with the donor ID AND display name matches (case-insensitive)
72
- if strings.HasSuffix(track.Name, "_"+sample.DonorID) &&
73
- strings.EqualFold(track.DisplayName, sample.DisplayName) {
74
- if track.Core {
75
- alreadyCore++
76
- } else {
77
- track.Core = true
78
- markedCount++
79
- }
80
- break
81
- }
82
- }
83
- }
84
- fmt.Printf("Marked %d tracks as core (already core: %d)\n", markedCount, alreadyCore)
85
-
86
- // Write to temp file
87
- output, err := json.MarshalIndent(biosampleData, "", " ")
88
- if err != nil {
89
- fmt.Fprintf(os.Stderr, "Error marshaling JSON: %v\n", err)
90
- os.Exit(1)
91
- }
92
-
93
- if err := os.WriteFile("human_updated.json", output, 0644); err != nil {
94
- fmt.Fprintf(os.Stderr, "Error writing human_updated.json: %v\n", err)
95
- os.Exit(1)
96
- }
97
- fmt.Println("Wrote updated data to human_updated.json")
98
- }
99
-
100
- // extractCoreSamples parses test.txt and extracts donor ID + display name pairs
101
- // Format: "Organ \t Type \t ENCDO... \t DisplayName: (1) cCREs \t Data format"
102
- func extractCoreSamples(filename string) ([]CoreSample, error) {
103
- file, err := os.Open(filename)
104
- if err != nil {
105
- return nil, err
106
- }
107
- defer file.Close()
108
-
109
- var samples []CoreSample
110
- donorRe := regexp.MustCompile(`ENCDO\w+`)
111
-
112
- scanner := bufio.NewScanner(file)
113
- for scanner.Scan() {
114
- line := scanner.Text()
115
- if strings.TrimSpace(line) == "" {
116
- continue
117
- }
118
-
119
- // Find the donor ID
120
- donorMatch := donorRe.FindString(line)
121
- if donorMatch == "" {
122
- continue
123
- }
124
-
125
- // Extract display name: it's after the donor ID, before ": (1)"
126
- // Split by donor ID to get the part after it
127
- parts := strings.SplitN(line, donorMatch, 2)
128
- if len(parts) < 2 {
129
- continue
130
- }
131
-
132
- afterDonor := parts[1]
133
- // Remove leading tab/whitespace
134
- afterDonor = strings.TrimLeft(afterDonor, " \t")
135
-
136
- // Extract the display name (before ": (1)" or ":(1)")
137
- displayName := afterDonor
138
- if idx := strings.Index(afterDonor, ": ("); idx != -1 {
139
- displayName = afterDonor[:idx]
140
- } else if idx := strings.Index(afterDonor, ":("); idx != -1 {
141
- displayName = afterDonor[:idx]
142
- }
143
-
144
- displayName = strings.TrimSpace(displayName)
145
- if displayName != "" {
146
- samples = append(samples, CoreSample{
147
- DonorID: donorMatch,
148
- DisplayName: displayName,
149
- })
150
- }
151
- }
152
-
153
- if err := scanner.Err(); err != nil {
154
- return nil, err
155
- }
156
-
157
- return samples, nil
158
- }