1915 |
06 Feb 06 |
nicklas |
1 |
/* |
1915 |
06 Feb 06 |
nicklas |
$Id$ |
1915 |
06 Feb 06 |
nicklas |
3 |
|
4889 |
06 Apr 09 |
nicklas |
Copyright (C) 2006 Jari Häkkinen, Nicklas Nordborg, Gregory Vincic |
1915 |
06 Feb 06 |
nicklas |
5 |
|
2304 |
22 May 06 |
jari |
This file is part of BASE - BioArray Software Environment. |
2304 |
22 May 06 |
jari |
Available at http://base.thep.lu.se/ |
1915 |
06 Feb 06 |
nicklas |
8 |
|
1915 |
06 Feb 06 |
nicklas |
BASE is free software; you can redistribute it and/or |
1915 |
06 Feb 06 |
nicklas |
modify it under the terms of the GNU General Public License |
4479 |
05 Sep 08 |
jari |
as published by the Free Software Foundation; either version 3 |
1915 |
06 Feb 06 |
nicklas |
of the License, or (at your option) any later version. |
1915 |
06 Feb 06 |
nicklas |
13 |
|
1915 |
06 Feb 06 |
nicklas |
BASE is distributed in the hope that it will be useful, |
1915 |
06 Feb 06 |
nicklas |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
1915 |
06 Feb 06 |
nicklas |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1915 |
06 Feb 06 |
nicklas |
GNU General Public License for more details. |
1915 |
06 Feb 06 |
nicklas |
18 |
|
1915 |
06 Feb 06 |
nicklas |
You should have received a copy of the GNU General Public License |
4515 |
11 Sep 08 |
jari |
along with BASE. If not, see <http://www.gnu.org/licenses/>. |
1915 |
06 Feb 06 |
nicklas |
21 |
*/ |
1915 |
06 Feb 06 |
nicklas |
22 |
package net.sf.basedb.util.jep; |
1915 |
06 Feb 06 |
nicklas |
23 |
|
1915 |
06 Feb 06 |
nicklas |
24 |
import net.sf.basedb.core.DbControl; |
1915 |
06 Feb 06 |
nicklas |
25 |
import net.sf.basedb.core.RawBioAssay; |
1915 |
06 Feb 06 |
nicklas |
26 |
import net.sf.basedb.core.DynamicResultIterator; |
1915 |
06 Feb 06 |
nicklas |
27 |
import net.sf.basedb.core.DynamicRawDataQuery; |
1915 |
06 Feb 06 |
nicklas |
28 |
import net.sf.basedb.core.RawDataUtil; |
1915 |
06 Feb 06 |
nicklas |
29 |
import net.sf.basedb.core.BaseException; |
1915 |
06 Feb 06 |
nicklas |
30 |
import net.sf.basedb.core.data.RawData; |
1915 |
06 Feb 06 |
nicklas |
31 |
import net.sf.basedb.core.query.Aggregations; |
1915 |
06 Feb 06 |
nicklas |
32 |
import net.sf.basedb.core.query.Dynamic; |
2726 |
12 Oct 06 |
nicklas |
33 |
import net.sf.basedb.core.query.Expression; |
1915 |
06 Feb 06 |
nicklas |
34 |
import net.sf.basedb.core.query.Selects; |
1915 |
06 Feb 06 |
nicklas |
35 |
|
1915 |
06 Feb 06 |
nicklas |
36 |
import java.util.Stack; |
1915 |
06 Feb 06 |
nicklas |
37 |
import java.util.Map; |
1915 |
06 Feb 06 |
nicklas |
38 |
import java.util.HashMap; |
1915 |
06 Feb 06 |
nicklas |
39 |
import java.sql.SQLException; |
2726 |
12 Oct 06 |
nicklas |
40 |
|
2726 |
12 Oct 06 |
nicklas |
41 |
import org.nfunk.jep.Node; |
1915 |
06 Feb 06 |
nicklas |
42 |
import org.nfunk.jep.ParseException; |
1915 |
06 Feb 06 |
nicklas |
43 |
|
1915 |
06 Feb 06 |
nicklas |
44 |
|
1915 |
06 Feb 06 |
nicklas |
45 |
/** |
1915 |
06 Feb 06 |
nicklas |
A JEP function class that adds a <code>mean(string)</code> function to a |
1915 |
06 Feb 06 |
nicklas |
JEP expression parser. The function will calculate the mean value of the raw data |
1915 |
06 Feb 06 |
nicklas |
property with the given name. For example: |
1915 |
06 Feb 06 |
nicklas |
<code>mean('ch1BgMean')</code> |
1915 |
06 Feb 06 |
nicklas |
<p> |
1915 |
06 Feb 06 |
nicklas |
To be able to use this function it must be registered with the JEP |
1915 |
06 Feb 06 |
nicklas |
parser and, before the expression is evaluated, a rawbioassay object must be set. |
1915 |
06 Feb 06 |
nicklas |
For example we can evaluate an expression for every raw data object |
1915 |
06 Feb 06 |
nicklas |
in a raw bioassay: |
1915 |
06 Feb 06 |
nicklas |
55 |
|
1915 |
06 Feb 06 |
nicklas |
<pre class="code"> |
1915 |
06 Feb 06 |
nicklas |
DbControl dc = ... |
1915 |
06 Feb 06 |
nicklas |
RawBioAssay assay = ... |
1915 |
06 Feb 06 |
nicklas |
String expression = "raw('ch1FgMean') - mean('ch1BgMean')"; |
1915 |
06 Feb 06 |
nicklas |
RawFunction raw = new RawFunction(assay.getRawDataType()); |
1915 |
06 Feb 06 |
nicklas |
MeanFunction mean = new MeanFunction(assay); |
1915 |
06 Feb 06 |
nicklas |
JEP jep = JepUtil.newJep(expression, raw, mean); |
1915 |
06 Feb 06 |
nicklas |
DataResultIterator<RawData> result = |
1915 |
06 Feb 06 |
nicklas |
assay.getRawData().iterate(dc); |
1915 |
06 Feb 06 |
nicklas |
while (result.hasNext()) |
1915 |
06 Feb 06 |
nicklas |
66 |
{ |
1915 |
06 Feb 06 |
nicklas |
raw.setRawData(result.next()); |
1915 |
06 Feb 06 |
nicklas |
double value = jep.getValue(); |
1915 |
06 Feb 06 |
nicklas |
// Do something with the value |
1915 |
06 Feb 06 |
nicklas |
70 |
} |
1915 |
06 Feb 06 |
nicklas |
result.close(); |
1915 |
06 Feb 06 |
nicklas |
</pre> |
1915 |
06 Feb 06 |
nicklas |
73 |
|
1915 |
06 Feb 06 |
nicklas |
@author Nicklas |
1915 |
06 Feb 06 |
nicklas |
@version 2.0 |
1915 |
06 Feb 06 |
nicklas |
@base.modified $Date$ |
1915 |
06 Feb 06 |
nicklas |
@see Jep |
1915 |
06 Feb 06 |
nicklas |
78 |
*/ |
1915 |
06 Feb 06 |
nicklas |
79 |
public class MeanFunction |
2726 |
12 Oct 06 |
nicklas |
80 |
implements JepExpressionFunction |
1915 |
06 Feb 06 |
nicklas |
81 |
{ |
1915 |
06 Feb 06 |
nicklas |
82 |
/** |
1915 |
06 Feb 06 |
nicklas |
Holds a cache of the values. |
1915 |
06 Feb 06 |
nicklas |
84 |
*/ |
1915 |
06 Feb 06 |
nicklas |
85 |
private final Map<String, Float> means; |
1915 |
06 Feb 06 |
nicklas |
86 |
private final DbControl dc; |
1915 |
06 Feb 06 |
nicklas |
87 |
private int numParameters; |
1915 |
06 Feb 06 |
nicklas |
88 |
private RawBioAssay rawBioAssay; |
1915 |
06 Feb 06 |
nicklas |
89 |
private RawData rawData; |
1915 |
06 Feb 06 |
nicklas |
90 |
|
1915 |
06 Feb 06 |
nicklas |
91 |
/** |
1915 |
06 Feb 06 |
nicklas |
Create a new instance of this function working with raw data of |
1915 |
06 Feb 06 |
nicklas |
the specified raw bio assay. |
1958 |
09 Feb 06 |
gregory |
@param dc DbControl used in this function |
1915 |
06 Feb 06 |
nicklas |
95 |
*/ |
1915 |
06 Feb 06 |
nicklas |
96 |
public MeanFunction(DbControl dc) |
1915 |
06 Feb 06 |
nicklas |
97 |
{ |
1915 |
06 Feb 06 |
nicklas |
98 |
this.dc = dc; |
1915 |
06 Feb 06 |
nicklas |
99 |
this.means = new HashMap<String, Float>(); |
1915 |
06 Feb 06 |
nicklas |
100 |
} |
1915 |
06 Feb 06 |
nicklas |
101 |
|
1915 |
06 Feb 06 |
nicklas |
102 |
/* |
1915 |
06 Feb 06 |
nicklas |
From the JepFunction interface |
1915 |
06 Feb 06 |
nicklas |
104 |
------------------------------------------- |
1915 |
06 Feb 06 |
nicklas |
105 |
*/ |
1915 |
06 Feb 06 |
nicklas |
106 |
/** |
1915 |
06 Feb 06 |
nicklas |
@return The string "mean" |
1915 |
06 Feb 06 |
nicklas |
108 |
*/ |
6127 |
14 Sep 12 |
nicklas |
109 |
@Override |
1915 |
06 Feb 06 |
nicklas |
110 |
public String getFunctionName() |
1915 |
06 Feb 06 |
nicklas |
111 |
{ |
1915 |
06 Feb 06 |
nicklas |
112 |
return "mean"; |
1915 |
06 Feb 06 |
nicklas |
113 |
} |
1915 |
06 Feb 06 |
nicklas |
114 |
// ------------------------------------------- |
1915 |
06 Feb 06 |
nicklas |
115 |
/* |
2726 |
12 Oct 06 |
nicklas |
From the JepExpressionFunction interface |
2726 |
12 Oct 06 |
nicklas |
117 |
------------------------------------------- |
2726 |
12 Oct 06 |
nicklas |
118 |
*/ |
2726 |
12 Oct 06 |
nicklas |
119 |
/** |
2981 |
30 Nov 06 |
nicklas |
Use the {@link Dynamic#meanRawData(String)} method to create an |
2726 |
12 Oct 06 |
nicklas |
expression for the mean of the given raw data property. |
2726 |
12 Oct 06 |
nicklas |
122 |
*/ |
6127 |
14 Sep 12 |
nicklas |
123 |
@Override |
2726 |
12 Oct 06 |
nicklas |
124 |
public Expression toExpression(Node node) |
2726 |
12 Oct 06 |
nicklas |
125 |
{ |
2726 |
12 Oct 06 |
nicklas |
126 |
int numChildren = node.jjtGetNumChildren(); |
2726 |
12 Oct 06 |
nicklas |
127 |
if (numChildren != 1) |
2726 |
12 Oct 06 |
nicklas |
128 |
{ |
2726 |
12 Oct 06 |
nicklas |
129 |
throw new BaseException("Invalid number of arguments for 'mean' function: " + numChildren); |
2726 |
12 Oct 06 |
nicklas |
130 |
} |
2726 |
12 Oct 06 |
nicklas |
131 |
return Dynamic.meanRawData(Jep.nodeToString(node.jjtGetChild(0))); |
2726 |
12 Oct 06 |
nicklas |
132 |
} |
2726 |
12 Oct 06 |
nicklas |
133 |
// ------------------------------------------- |
2726 |
12 Oct 06 |
nicklas |
134 |
/* |
1915 |
06 Feb 06 |
nicklas |
From the PostfixMathCommandI interface |
1915 |
06 Feb 06 |
nicklas |
136 |
------------------------------------------- |
1915 |
06 Feb 06 |
nicklas |
137 |
*/ |
1915 |
06 Feb 06 |
nicklas |
138 |
/** |
1915 |
06 Feb 06 |
nicklas |
@return Always 1 |
1915 |
06 Feb 06 |
nicklas |
140 |
*/ |
6127 |
14 Sep 12 |
nicklas |
141 |
@Override |
1915 |
06 Feb 06 |
nicklas |
142 |
public int getNumberOfParameters() |
1915 |
06 Feb 06 |
nicklas |
143 |
{ |
1915 |
06 Feb 06 |
nicklas |
144 |
return 1; |
1915 |
06 Feb 06 |
nicklas |
145 |
} |
6127 |
14 Sep 12 |
nicklas |
146 |
@Override |
1915 |
06 Feb 06 |
nicklas |
147 |
public void setCurNumberOfParameters(int n) |
1915 |
06 Feb 06 |
nicklas |
148 |
{ |
1915 |
06 Feb 06 |
nicklas |
149 |
this.numParameters = n; |
1915 |
06 Feb 06 |
nicklas |
150 |
} |
6127 |
14 Sep 12 |
nicklas |
151 |
@Override |
2474 |
31 Jul 06 |
nicklas |
152 |
public boolean checkNumberOfParameters(int n) |
2474 |
31 Jul 06 |
nicklas |
153 |
{ |
2474 |
31 Jul 06 |
nicklas |
154 |
return n == 1; |
2474 |
31 Jul 06 |
nicklas |
155 |
} |
6127 |
14 Sep 12 |
nicklas |
156 |
@Override |
6875 |
20 Apr 15 |
nicklas |
157 |
@SuppressWarnings({"unchecked", "rawtypes"}) |
1915 |
06 Feb 06 |
nicklas |
158 |
public void run(Stack stack) |
1915 |
06 Feb 06 |
nicklas |
159 |
throws ParseException |
1915 |
06 Feb 06 |
nicklas |
160 |
{ |
1915 |
06 Feb 06 |
nicklas |
161 |
if (stack == null || stack.empty()) |
1915 |
06 Feb 06 |
nicklas |
162 |
{ |
1915 |
06 Feb 06 |
nicklas |
163 |
throw new ParseException("Stack is empty"); |
1915 |
06 Feb 06 |
nicklas |
164 |
} |
1915 |
06 Feb 06 |
nicklas |
165 |
Object propertyName = stack.pop(); |
1915 |
06 Feb 06 |
nicklas |
166 |
if (propertyName instanceof String) |
1915 |
06 Feb 06 |
nicklas |
167 |
{ |
1915 |
06 Feb 06 |
nicklas |
168 |
stack.push(mean((String)propertyName)); |
1915 |
06 Feb 06 |
nicklas |
169 |
} |
1915 |
06 Feb 06 |
nicklas |
170 |
else |
1915 |
06 Feb 06 |
nicklas |
171 |
{ |
1915 |
06 Feb 06 |
nicklas |
172 |
throw new ParseException("Invalid parameter type: " + propertyName + "; expected string"); |
1915 |
06 Feb 06 |
nicklas |
173 |
} |
1915 |
06 Feb 06 |
nicklas |
174 |
} |
1915 |
06 Feb 06 |
nicklas |
175 |
// ------------------------------------------- |
1915 |
06 Feb 06 |
nicklas |
176 |
|
1915 |
06 Feb 06 |
nicklas |
177 |
/** |
1915 |
06 Feb 06 |
nicklas |
Set a new raw data object that will be used the next time the |
1915 |
06 Feb 06 |
nicklas |
JEP expression is evaluated. |
1915 |
06 Feb 06 |
nicklas |
@param rawData The raw data object to use |
1915 |
06 Feb 06 |
nicklas |
181 |
*/ |
1915 |
06 Feb 06 |
nicklas |
182 |
public void setRawData(RawData rawData) |
1915 |
06 Feb 06 |
nicklas |
183 |
{ |
1915 |
06 Feb 06 |
nicklas |
184 |
this.rawData = rawData; |
1915 |
06 Feb 06 |
nicklas |
185 |
} |
1915 |
06 Feb 06 |
nicklas |
186 |
/** |
1915 |
06 Feb 06 |
nicklas |
Get the current raw data object used when evaluating the JEP expression. |
1915 |
06 Feb 06 |
nicklas |
188 |
*/ |
1915 |
06 Feb 06 |
nicklas |
189 |
public RawData getRawData() |
1915 |
06 Feb 06 |
nicklas |
190 |
{ |
1915 |
06 Feb 06 |
nicklas |
191 |
return rawData; |
1915 |
06 Feb 06 |
nicklas |
192 |
} |
1915 |
06 Feb 06 |
nicklas |
193 |
|
1915 |
06 Feb 06 |
nicklas |
194 |
|
1915 |
06 Feb 06 |
nicklas |
195 |
/** |
1915 |
06 Feb 06 |
nicklas |
Get the value of the specified property of the current raw data object. |
1915 |
06 Feb 06 |
nicklas |
This method uses Hibernate metadata to find the value. |
4020 |
29 Nov 07 |
martin |
@param propertyName The name of the raw data property. Null is not allowed. |
4020 |
29 Nov 07 |
martin |
@return The mean value as a float. |
4020 |
29 Nov 07 |
martin |
@throws ParseException If the property name is null or |
4020 |
29 Nov 07 |
martin |
if there is another error. |
1915 |
06 Feb 06 |
nicklas |
202 |
*/ |
2726 |
12 Oct 06 |
nicklas |
203 |
public float mean(String propertyName) |
1915 |
06 Feb 06 |
nicklas |
204 |
throws ParseException |
1915 |
06 Feb 06 |
nicklas |
205 |
{ |
1915 |
06 Feb 06 |
nicklas |
206 |
if (propertyName == null) |
1915 |
06 Feb 06 |
nicklas |
207 |
{ |
1915 |
06 Feb 06 |
nicklas |
208 |
throw new ParseException("No property name has been specified for function mean()"); |
1915 |
06 Feb 06 |
nicklas |
209 |
} |
1915 |
06 Feb 06 |
nicklas |
210 |
if (rawData == null) |
1915 |
06 Feb 06 |
nicklas |
211 |
{ |
1915 |
06 Feb 06 |
nicklas |
212 |
throw new ParseException("No raw data object has been specified for function mean('"+propertyName+"')"); |
1915 |
06 Feb 06 |
nicklas |
213 |
} |
1915 |
06 Feb 06 |
nicklas |
214 |
Float theMean = null; |
1915 |
06 Feb 06 |
nicklas |
215 |
try |
1915 |
06 Feb 06 |
nicklas |
216 |
{ |
1915 |
06 Feb 06 |
nicklas |
217 |
RawBioAssay rba = RawDataUtil.getRawBioAssay(dc, rawData); |
1915 |
06 Feb 06 |
nicklas |
218 |
if (rawBioAssay == null || rba.getId() != rawBioAssay.getId()) |
1915 |
06 Feb 06 |
nicklas |
219 |
{ |
1915 |
06 Feb 06 |
nicklas |
// Raw data from is from a different RawBioAssay. Clean cache. |
1915 |
06 Feb 06 |
nicklas |
221 |
rawBioAssay = rba; |
1915 |
06 Feb 06 |
nicklas |
222 |
means.clear(); |
1915 |
06 Feb 06 |
nicklas |
223 |
} |
1915 |
06 Feb 06 |
nicklas |
224 |
theMean = means.get(propertyName); |
1915 |
06 Feb 06 |
nicklas |
225 |
if (theMean == null) |
1915 |
06 Feb 06 |
nicklas |
226 |
{ |
1915 |
06 Feb 06 |
nicklas |
// Value not found in cache, query the database |
1915 |
06 Feb 06 |
nicklas |
228 |
DynamicRawDataQuery rawQuery = rawBioAssay.getDynamicRawData(); |
1915 |
06 Feb 06 |
nicklas |
229 |
rawQuery.select(Selects.expression(Aggregations.mean(Dynamic.rawData(propertyName)), "mean")); |
1915 |
06 Feb 06 |
nicklas |
230 |
DynamicResultIterator result = rawQuery.iterate(rawBioAssay.getDbControl()); |
1915 |
06 Feb 06 |
nicklas |
231 |
theMean = result.next().getFloat(1); |
1915 |
06 Feb 06 |
nicklas |
232 |
means.put(propertyName, theMean); |
1915 |
06 Feb 06 |
nicklas |
233 |
} |
1915 |
06 Feb 06 |
nicklas |
234 |
} |
1915 |
06 Feb 06 |
nicklas |
235 |
catch (SQLException ex) |
1915 |
06 Feb 06 |
nicklas |
236 |
{ |
1915 |
06 Feb 06 |
nicklas |
237 |
throw new ParseException(ex.getMessage()); |
1915 |
06 Feb 06 |
nicklas |
238 |
} |
1915 |
06 Feb 06 |
nicklas |
239 |
catch (BaseException ex) |
1915 |
06 Feb 06 |
nicklas |
240 |
{ |
1915 |
06 Feb 06 |
nicklas |
241 |
throw new ParseException(ex.getMessage()); |
1915 |
06 Feb 06 |
nicklas |
242 |
} |
1915 |
06 Feb 06 |
nicklas |
243 |
return theMean; |
1915 |
06 Feb 06 |
nicklas |
244 |
} |
1915 |
06 Feb 06 |
nicklas |
245 |
} |