source: trunk/grails-app/services/nl/tno/metagenomics/SampleExcelService.groovy @ 9

Last change on this file since 9 was 9, checked in by robert@…, 8 years ago
File size: 6.2 KB
Line 
1package nl.tno.metagenomics
2
3class SampleExcelService {
4        def excelService
5        def fuzzySearchService
6       
7    static transactional = true
8
9        // Fields to be edited using excel file and manually
10        def sampleNameName = "Sample name"
11        def runName = "Run"
12        def tagNameName = "Tag name"
13        def tagSequenceName = "Tag sequence"
14        def oligoNumberName = "Oligo number"
15        def possibleFields = [sampleNameName, runName, tagNameName, tagSequenceName, oligoNumberName]
16       
17    def downloadSampleExcel( def assaySamples, boolean includeRun = true ) {
18                def sheetIndex = 0;
19               
20                if( assaySamples == null )
21                        assaySamples = []
22                       
23                def sortedSamples = assaySamples.toList().sort { it.sample.name }
24               
25                // Create an excel sheet
26                def wb = excelService.create();
27
28                def fields = possibleFields
29                if( !includeRun )
30                        fields = fields - runName
31               
32                // Put the headers on the first row
33                excelService.writeHeader( wb, fields, sheetIndex );
34
35                // Adding the next lines
36                ArrayList data = [];
37                sortedSamples.each { assaySample ->
38                        def rowData = [assaySample.sample?.name];
39                        if( includeRun )
40                                rowData << assaySample.run?.name
41                       
42                        rowData << assaySample.tagName
43                        rowData << assaySample.tagSequence
44                        rowData << assaySample.oligoNumber
45                        data << rowData;
46                }
47                excelService.writeData( wb, data, sheetIndex, 1 );
48
49                // Auto resize columns
50                excelService.autoSizeColumns( wb, sheetIndex, 0..2)
51
52                return wb;             
53    }
54       
55        def parseTagsExcel( File file, boolean includeRun = true ) {
56                def sheetIndex = 0
57                def headerRow = 0
58                def dataStartsAtRow = 1
59                def numExampleRows = 5
60               
61                // Create an excel workbook instance of the file
62                def     workbook = excelService.open( file );
63
64                // Read headers from the first row and 5 of the first lines as example data
65                def headers = excelService.readRow( workbook, sheetIndex, headerRow );
66                def exampleData = excelService.readData( workbook, sheetIndex, dataStartsAtRow, -1, numExampleRows ); // -1 means: determine number of rows yourself
67
68                // Try to guess best matches between the excel file and the column names
69                def bestMatches = [:]
70                def fields = possibleFields
71                if( !includeRun )
72                        fields = fields - runName
73                       
74                headers.eachWithIndex { header, idx ->
75                        // Do matching using fuzzy search. The 0.1 treshold makes sure that no match if chosen if
76                        // there is actually no match at all.
77                        bestMatches[idx] = fuzzySearchService.mostSimilar( header, possibleFields, 0.1 );
78                }
79               
80                return [headers: headers, exampleData: exampleData, bestMatches: bestMatches, possibleFields: fields]
81        }
82       
83        def updateTagsByExcel( def matchColumns, def possibleFields, File file, def assaySamples ) {
84                def sheetIndex = 0
85                def headerRow = 0
86                def dataStartsAtRow = 1
87
88                if( !matchColumns ) {
89                        // Now delete the file, since we don't need it anymore
90                        file?.delete()
91
92                        return [ success: false, message: "No column matches found for excel file. Please try again." ]
93                }
94
95                // Determine column numbers
96                def columns = [:]
97                def dataMatches = false;
98                possibleFields.each { columnName ->
99                        columns[ columnName ] = matchColumns.findIndexOf { it.value == columnName }
100
101                        if( columnName != sampleNameName && columns[ columnName ] != -1 )
102                                dataMatches = true
103                }
104
105                // A column to match the sample name must be present
106                if( columns[ sampleNameName ] == -1 ) {
107                        // Now delete the file, since we don't need it anymore
108                        _deleteUploadedFileFromSession()
109
110                        return [ success: false, message: "There must be a column present in the excel file that matches the sample name. Please try again." ]
111                }
112
113                // A column with data should also be present
114                if( !dataMatches ) {
115                        // Now delete the file, since we don't need it anymore
116                        _deleteUploadedFileFromSession()
117
118                        return [ success: false, message: "There are no data columns present in the excel file. No samples are updated." ]
119                }
120
121                // Now loop through the excel sheet and update all samples with the specified data
122                if( !file.exists() || !file.canRead() ) {
123                        return [ success: false, message: "Excel file has been removed since previous step. Please try again." ]
124                }
125
126                def workbook = excelService.open( file )
127                ArrayList data = excelService.readData( workbook, sheetIndex, dataStartsAtRow )
128
129                // Check whether the excel file contains any data
130                if( data.size() == 0 ) {
131                        // Now delete the file, since we don't need it anymore
132                        file.delete()
133
134                        return [ success: false, message: "The excel sheet contains no data to import. Please upload another excel file." ]
135                }
136
137                def numSuccesful = 0
138                def failedRows = []
139
140                // walk through all rows and fill the table with records
141                for( def i = 0; i < data.size(); i++ ) {
142                        def rowData = data[ i ];
143
144                        String sampleName = rowData[ columns[ sampleNameName ] ] as String
145
146                        // Find assay by sample name. Since sample names are unique within an assay (enforced by GSCF),
147                        // this will always work when only using one assay. When multiple assays are used, this might pose
148                        // a problem
149                        AssaySample assaySample = assaySamples.find { it.sample.id == Sample.findByName( sampleName )?.id };
150
151                        // If no assaysample is found, add this row to the failed-row list
152                        if( !assaySample ) {
153                                failedRows << [ row: rowData, sampleName: sampleName ];
154                                continue;
155                        }
156
157                        columns.each {
158                                if( it.value > -1 ) {
159                                        switch( it.key ) {
160                                                case tagNameName:               assaySample.tagName = rowData[ it.value ]; break
161                                                case tagSequenceName:   assaySample.tagSequence = rowData[ it.value ]; break
162                                                case oligoNumberName:   assaySample.oligoNumber = rowData[ it.value ]; break
163                                                case runName:                   assaySample.run = Run.findByName( rowData[ it.value ] ); break
164                                        }
165                                }
166                        }
167
168                        assaySample.save()
169
170                        numSuccesful++;
171                }
172
173                // Now delete the file, since we don't need it anymore
174                file.delete()
175
176                // Return a message to the user
177                if( numSuccesful == 0 ) {
178                        return [success: false, message: "None of the " + failedRows.size() + " row(s) could be imported, because none of the sample names matched. Have you provided the right excel file?" ]
179                } else {
180                        def message = numSuccesful + " samples have been updated. "
181
182                        if( failedRows.size() > 0 )
183                                message += failedRows.size() + " row(s) could not be imported, because the sample names could not be found in the database."
184
185                        return [success: true, message: message, numSuccesful: numSuccesful, failedRows: failedRows ]
186
187                }
188        }
189}
Note: See TracBrowser for help on using the repository browser.