MediaWiki:LipoqualitySearch.js: Difference between revisions

No edit summary
No edit summary
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
// Last-update: 2020/01/20
// Last-update: 2020/02/04
// 対象項目からデータを検索する ////////////////////////////////////////////////////////
// 対象項目からデータを検索する ////////////////////////////////////////////////////////
// param sampleSource - sample source
// param sampleSource - sample source
Line 5: Line 5:
// param lipidClass - lipid class
// param lipidClass - lipid class
// return 検索結果
// return 検索結果
function lipoqualitySearch(sampleCategory, sampleName, lipidClass)
function lipoqualitySearch(sampleCategory, sampleName, lipidClass, dataType)
{
// sample sourceとsample typeはAllがあるため、正規表現を用いてマッチングを行う
var scReg = new RegExp(translateForReg(sampleCategory));// Last-update: 2020/01/20
// 対象項目からデータを検索する ////////////////////////////////////////////////////////
// param sampleSource - sample source
// param sampleType - sample type
// param lipidClass - lipid class
// return 検索結果
function lipoqualitySearch(sampleCategory, sampleName, lipidClass)
{
{
// sample sourceとsample typeはAllがあるため、正規表現を用いてマッチングを行う
// sample sourceとsample typeはAllがあるため、正規表現を用いてマッチングを行う
Line 21: Line 12:
var stReg = new RegExp(translateForReg(sampleName));
var stReg = new RegExp(translateForReg(sampleName));


var unitKey = "Quantification unit";
if(dataType == "height"){
unitKey = "Quantification unit(Ion abundance)";
} else if(dataType == "normalized"){
unitKey = "Quantification unit(Normalized value)";
}
// 検索
// 検索
var result = [];
var result = [];
Line 29: Line 26:


for(var j = 0; j < gAllData[key].length; j ++){
for(var j = 0; j < gAllData[key].length; j ++){
// イオン強度、もしくは濃度の切り分けをする
if(gAllData[key][j][unitKey].length == 0)
continue;
//console.log("length:" + j + "," + gAllData[key].length);
//console.log("length:" + j + "," + gAllData[key].length);
// 対象sample source, sample typeかチェック
// 対象sample source, sample typeかチェック
Line 56: Line 56:


return result;
return result;
}
function getQuantValue(array, flag)
{
value = 0;
if(flag == 'height'){
var keys = Object.keys(array);
for(var i = 0; i < keys.length; i ++){
if(keys[i].startsWith("Ion abundance")){
value = array[keys[i]];
break;
}
}
} else if(flag == 'normalized'){
value = array['Normalized value by internal standard'];
}
if(isNaN(value))
value = 0;
return value;
}
}
// 指定されたID群をもとに、グラフ全般用のデータを取得する ///////////////////////////////
// 指定されたID群をもとに、グラフ全般用のデータを取得する ///////////////////////////////
Line 61: Line 79:
// param chartType - 未使用
// param chartType - 未使用
// return 対象データ
// return 対象データ
function retrieveChartData(ids, chartType)
function retrieveChartData(ids, chartType, dataType)
{
{
// '#7fbfff'がbarchartのデフォルト色と似ているので排除する
// '#7fbfff'がbarchartのデフォルト色と似ているので排除する
var pieColors = ['#ff7f7f','#7f7fff','#7fff7f','#ff7fbf','#bfff7f','#ff7fff','#7fffff','#000000','#bf7fff','#7fffbf','#ffbf7f','#808080'];
var pieColors = ['#ff7f7f','#7f7fff','#7fff7f','#ff7fbf','#bfff7f','#ff7fff','#7fffff','#000000','#bf7fff','#7fffbf','#ffbf7f','#808080'];
var unitKey = "Quantification unit";
if(dataType == "height"){
unitKey = "Quantification unit(Ion abundance)";
} else if(dataType == "normalized"){
unitKey = "Quantification unit(Normalized value)";
}


var result    = {};
var result    = {};
Line 74: Line 99:
result.map = []; // チャートデータ
result.map = []; // チャートデータ
for(var index = 0; index < ids.length; index ++){
for(var index = 0; index < ids.length; index ++){
console.log("id:" + index + "=" + ids[index]);
var w = ids[index].split(" / ");
var w = ids[index].split(" / ");
var sampleCategory = w[0];
var sampleCategory = w[0];
Line 95: Line 121:
continue;
continue;


result.map[index].title = sampleCategory + " / " + sampleName + " / "/* + sampleType + "/"*/ + uniqid;
result.map[index].title = sampleCategory + " / " + sampleName + " / "/* + sampleType + "/"*/ + lipidclass + " / " + uniqid;
result.map[index].meta  = {};
result.map[index].meta  = {};
for(meta in gAllData[key][j]){// 全メタ情報
for(meta in gAllData[key][j]){// 全メタ情報
if(meta != "data")
if(meta != "data"){
result.map[index].meta[meta] = gAllData[key][j][meta];
if(meta.startsWith("Quantification unit")){
result.map[index].meta["Quantification"] = gAllData[key][j][unitKey];
} else
result.map[index].meta[meta] = gAllData[key][j][meta];
}
}
}
// if(sampleType != gAllData[key][j]["SampleType"])
// if(sampleType != gAllData[key][j]["SampleType"])
Line 132: Line 162:
result.map[index].pie[pieKeys[lc]].y = 0;
result.map[index].pie[pieKeys[lc]].y = 0;
}
}
result.map[index].pie[pieKeys[lc]].y += parseFloat(gAllData[key][j]["data"][k]["Quant value"]); // intensity
result.map[index].pie[pieKeys[lc]].y += parseFloat(getQuantValue(gAllData[key][j]["data"][k], dataType)); // intensity


if(lc == lipidclass){ // lipid classが対象のものなら、通常チャート用にデータを格納する
if(lc == lipidclass){ // lipid classが対象のものなら、通常チャート用にデータを格納する
Line 150: Line 180:
}
}
}
}
console.log(result.x);
console.log("result");
console.log("result");
console.log(result);
console.log(result);
Line 180: Line 211:
if(data[result.x[j]][index] == undefined){ // このデータには、対象chainの情報がないため、ダミーを格納しておく
if(data[result.x[j]][index] == undefined){ // このデータには、対象chainの情報がないため、ダミーを格納しておく
data[result.x[j]][index] = {
data[result.x[j]][index] = {
"Quant value"     :"0",
"Quant value"       : "0",
"Formula"         :"",
"Formula"           : "",
"InChIKey"       :"",
"InChIKey"         : "",
"SMILES"         :"",
"SMILES"           : "",
"RT(min)"         :"",
"RT(min)"           : "",
"m/z"             :"",
"m/z"               : "",
"Adduct"         :"",
"Adduct"           : "",
"MSMS"           :""
"MSMS"             : "",
"Internal standard" : "-"
};
};
}
}


// Intensityの処理
// Intensityの処理
var inte = parseFloat(data[result.x[j]][index]["Quant value"]);
var inte = parseFloat(getQuantValue(data[result.x[j]][index], dataType));
if(inte > max)
if(inte > max)
max = inte;
max = inte;
Line 199: Line 231:
// メタ情報の格納
// メタ情報の格納
result.map[index].data[j].meta = {};
result.map[index].data[j].meta = {};
result.map[index].data[j].meta["Formula"]         = data[result.x[j]][index]["Formula"];
result.map[index].data[j].meta["Formula"]           = data[result.x[j]][index]["Formula"];
result.map[index].data[j].meta["InChIKey"]       = data[result.x[j]][index]["InChIKey"];
result.map[index].data[j].meta["InChIKey"]         = data[result.x[j]][index]["InChIKey"];
result.map[index].data[j].meta["SMILES"]         = data[result.x[j]][index]["SMILES"];
result.map[index].data[j].meta["SMILES"]           = data[result.x[j]][index]["SMILES"];
result.map[index].data[j].meta["RT(min)"]         = data[result.x[j]][index]["RT(min)"];
result.map[index].data[j].meta["RT(min)"]           = data[result.x[j]][index]["RT(min)"];
result.map[index].data[j].meta["m/z"]             = data[result.x[j]][index]["m/z"];
result.map[index].data[j].meta["m/z"]               = data[result.x[j]][index]["m/z"];
result.map[index].data[j].meta["Adduct"]         = data[result.x[j]][index]["Adduct"];
result.map[index].data[j].meta["Adduct"]           = data[result.x[j]][index]["Adduct"];
result.map[index].data[j].meta["MSMS"]           = data[result.x[j]][index]["MSMS"];
result.map[index].data[j].meta["MSMS"]             = data[result.x[j]][index]["MSMS"];
if(dataType == 'normalized')
result.map[index].data[j].meta["Internal standard"] = data[result.x[j]][index]["Internal standard"];
else
result.map[index].data[j].meta["Internal standard"] = '-';
}
}
for(var j = 0; j < result.x.length; j ++) // 意味ある?
for(var j = 0; j < result.x.length; j ++) // 意味ある?
Line 250: Line 286:
// param chain - Lipid chain
// param chain - Lipid chain
// return 対象データ
// return 対象データ
function retrieveChainData(samplename, samplesource, sampletype, lipidclass, chain)
function retrieveChainData(samplename, samplesource, sampletype, lipidclass, chain, dataType)
{
{
// sample sourceとsample typeはAllがあるため、正規表現を用いてマッチングを行う
// sample sourceとsample typeはAllがあるため、正規表現を用いてマッチングを行う
Line 256: Line 292:
var stReg = new RegExp(translateForReg(sampletype));
var stReg = new RegExp(translateForReg(sampletype));
// var snReg = new RegExp(translateForReg(samplename), "i");
// var snReg = new RegExp(translateForReg(samplename), "i");
var unitKey = "Quantification unit";
if(dataType == "height"){
unitKey = "Quantification unit(Ion abundance)";
} else if(dataType == "normalized"){
unitKey = "Quantification unit(Normalized value)";
}


var result      = {};
var result      = {};
Line 299: Line 342:
legend = gAllData[key][j]["SampleType"];
legend = gAllData[key][j]["SampleType"];
else*/
else*/
legend = gAllData[key][j]["Sample name"];
legend = gAllData[key][j]["Category"] + " / " + gAllData[key][j]["Sample name"] + " / " + gAllData[key][j]["ID"];
 
if(!legends[legend] && lipidType == chain){ // legend名が複数回被る可能性があるので、すでに格納済みのlegendは処理しない
if(!legends[legend] && lipidType == chain){ // legend名が複数回被る可能性があるので、すでに格納済みのlegendは処理しない
// 対象,,m
// 対象,,m
Line 306: Line 348:
result.ionmode[index]  = gAllData[key][j]["Ion mode"];
result.ionmode[index]  = gAllData[key][j]["Ion mode"];
result.adduct[index]    = gAllData[key][j]["data"][k]["Adduct"];
result.adduct[index]    = gAllData[key][j]["data"][k]["Adduct"];
result.intensity[index] = parseFloat(gAllData[key][j]["data"][k]["Quant value"]); // intensity
result.intensity[index] = parseFloat(getQuantValue(gAllData[key][j]["data"][k], dataType)); // intensity
 
if(quantification.length == 0){
if(quantification.length == 0)
quantification = gAllData[key][j][unitKey];
quantification = gAllData[key][j]["Quantification unit"];
} else if(quantification != gAllData[key][j]["Quantification unit"])
else if(quantification != gAllData[key][j]["Quantification unit"])
quantification = "'Quantification unit's are mixed";
quantification = "?";


if(maxOfAll < result.intensity[index]) // 全体での最大Intensityを調べる
if(maxOfAll < result.intensity[index]) // 全体での最大Intensityを調べる
Line 346: Line 387:
}
}


var snReg = new RegExp(translateForReg(sampleName));
// 指定されたID群をもとに、ダウンロード用データをjson形式で返す ///////////////////////////////
var stReg = new RegExp(translateForReg(sampleName));
// param ids      - 対象データのID。「SampleCategory/Sample name/Lipid subclass/ID」で構成される。
 
// return json形式の文字列
// 検索
function getDownloadData(ids)
var result = [];
var i = 0;
for(key in gAllData){
if(!scReg.test(key)) // sample sourceが合致するか
continue;
 
for(var j = 0; j < gAllData[key].length; j ++){
//console.log("length:" + j + "," + gAllData[key].length);
// 対象sample source, sample typeかチェック
//console.log("st:" + key + ":" + gAllData[key][j]["Sample name"] + ":" + stReg.test(gAllData[key][j]["Sample name"]));
if(!snReg.test(gAllData[key][j]["Sample name"])) // sample typeが合致するか
continue;
 
//console.log("search:" + key + ":" + gAllData[key][j]["Sample name"] + ":" + gAllData[key][j]["data"].length);
var found = false;
for(var k = 0; k < gAllData[key][j]["data"].length; k ++){
// 対象lipid classかチェック
//console.log("hit:" + key + ":" + gAllData[key][j]["data"][k]["Lipid subclass"] + "==" + lipidClass);
if(gAllData[key][j]["data"][k]["Lipid subclass"] == lipidClass){
found = true;
break;
}
}
// 対象だったので結果に格納する
if(found){
result[i] = [];
result[i]["title"]      = key + " / " + gAllData[key][j]["Sample name"] + " / " + /*gAllData[key][j]["SampleType"] + " / " +*/ lipidClass + " / " + gAllData[key][j]["ID"];
result[i]["Method link"] = gAllData[key][j]["Method link"];
i ++;
}
}
}
 
return result;
}
// 指定されたID群をもとに、グラフ全般用のデータを取得する ///////////////////////////////
// param ids      - 対象データのID。「SampleCategory/Sample name/SampleType/LipidClass」で構成される。
// param chartType - 未使用
// return 対象データ
function retrieveChartData(ids, chartType)
{
{
// '#7fbfff'がbarchartのデフォルト色と似ているので排除する
var result = {};
var pieColors = ['#ff7f7f','#7f7fff','#7fff7f','#ff7fbf','#bfff7f','#ff7fff','#7fffff','#000000','#bf7fff','#7fffbf','#ffbf7f','#808080'];
 
var result     = {};
var data      = {};
var colorKeys  = {};
var colorIndex = 0;
// id毎にデータを取得
result.x  = []; // Xラベル
result.map = []; // チャートデータ
for(var index = 0; index < ids.length; index ++){
for(var index = 0; index < ids.length; index ++){
var w = ids[index].split(" / ");
var w = ids[index].split(" / ");
var sampleCategory = w[0];
var sampleCategory = w[0];
var sampleName   = w[1];
var sampleName     = w[1];
// var sampleType  = w[2];
var lipidclass     = w[2];
var lipidclass   = w[2];
var uniqid         = w[3];
var uniqid       = w[3];


result.map[index]    = {}; // 通常チャート用
result.map[index].pie = []; // パイチャート用
var pieKeys = {};
var pieIndex = 0;
for(key in gAllData){ // sample source
for(key in gAllData){ // sample source
if(sampleCategory != key)
if(sampleCategory != key)
Line 418: Line 405:


for(var j = 0; j < gAllData[key].length; j ++){ // sample category
for(var j = 0; j < gAllData[key].length; j ++){ // sample category
if(sampleName != gAllData[key][j]["Sample name"])
continue;
if(uniqid != gAllData[key][j]["ID"])
if(uniqid != gAllData[key][j]["ID"])
continue;
continue;
// if(sampleType != gAllData[key][j]["SampleType"])
// continue;
// 同一のLipidSuperClassのみ対象とする
// 通常チャートは同一LipidClassのみだが、パイチャートにおいて意味を持つ
var targetLipidSuperClass = undefined;
for(var k = 0; k < gAllData[key][j]["data"].length; k ++){
if(gAllData[key][j]["data"][k]["Lipid subclass"] == lipidclass){
targetLipidSuperClass = gAllData[key][j]["data"][k]["Lipid category"];
break;
}
}
// 各lipid classのチェック
for(var k = 0; k < gAllData[key][j]["data"].length; k ++){
if(gAllData[key][j]["data"][k]["Lipid category"] != targetLipidSuperClass) // superクラスが違うものは対象外
continue;
var lc = gAllData[key][j]["data"][k]["Lipid subclass"];
// lipid classごとに色を変える
if(colorKeys[lc] == undefined){
colorKeys[lc] = colorIndex++;
}
// パイチャート用データ
if(pieKeys[lc] == undefined){
pieKeys[lc] = pieIndex++;
result.map[index].pie[pieKeys[lc]] = {};
result.map[index].pie[pieKeys[lc]].name = lc; // type
result.map[index].pie[pieKeys[lc]].color = pieColors[colorKeys[lc]%pieColors.length];
result.map[index].pie[pieKeys[lc]].y = 0;
}
result.map[index].pie[pieKeys[lc]].y += parseFloat(gAllData[key][j]["data"][k]["Quant value"]); // intensity
if(lc == lipidclass){ // lipid classが対象のものなら、通常チャート用にデータを格納する
result.map[index].title = sampleCategory + " / " + sampleName + " / "/* + sampleType + "/"*/ + lipidclass + " / " + uniqid;
result.map[index].meta  = {};
for(meta in gAllData[key][j]){// 全メタ情報
if(meta != "data")
result.map[index].meta[meta] = gAllData[key][j][meta];
}


var lipidType = getLipidType(gAllData[key][j]["data"][k]); // chain文字列を取得する
if(!(key in result))
// すべてのデータでX軸を統一するため、いったんdata配列にデータを格納する
result[key] = [];
if(data[lipidType] == undefined){ // まだ出てきていないchainならばX軸ラベルに追加する
result[key].push(gAllData[key][j]);
data[lipidType] = [];
result.x.push(lipidType);
}
data[lipidType][index] = gAllData[key][j]["data"][k];
 
//Logger.log(filename + "/" + tabname + "/" + type);
}
}
}
}
}
}
}
}
console.log(result);


// chainの小さい順に並べ替える
return JSON.stringify(result, null, 4);
result.x.sort(function(a1, a2){
// chainの数による比較
var lipidClass1 = a1.split("/");
var lipidClass2 = a2.split("/");
if(lipidClass1.length < lipidClass2.length) return -1;
if(lipidClass1.length > lipidClass2.length) return 1;
// chainの長さと二重結合数による比較
for(var i = 0; i < lipidClass1.length; i ++){
var lc1 = parseInt(lipidClass1[i].replace(/:/, ""));
var lc2 = parseInt(lipidClass2[i].replace(/:/, ""));
if(lc1 < lc2) return -1;
if(lc1 > lc2) return 1;
}
return 0;
});
 
// データを整形
var maxOfAll = 0;
for(var index = 0; index < ids.length; index ++){
result.map[index].data = [];
var max = 0;
for(var j = 0; j < result.x.length; j ++){
result.map[index].data[j] = [];
 
if(data[result.x[j]][index] == undefined){ // このデータには、対象chainの情報がないため、ダミーを格納しておく
data[result.x[j]][index] = {
"Quant value"    :"0",
"Formula"        :"",
"InChIKey"        :"",
"SMILES"          :"",
"RT(min)"        :"",
"m/z"            :"",
"Adduct"          :"",
"MSMS"            :""
};
}
 
// Intensityの処理
var inte = parseFloat(data[result.x[j]][index]["Quant value"]);
if(inte > max)
max = inte;
result.map[index].data[j].push(inte);
 
// メタ情報の格納
result.map[index].data[j].meta = {};
result.map[index].data[j].meta["Formula"]        = data[result.x[j]][index]["Formula"];
result.map[index].data[j].meta["InChIKey"]        = data[result.x[j]][index]["InChIKey"];
result.map[index].data[j].meta["SMILES"]          = data[result.x[j]][index]["SMILES"];
result.map[index].data[j].meta["RT(min)"]        = data[result.x[j]][index]["RT(min)"];
result.map[index].data[j].meta["m/z"]            = data[result.x[j]][index]["m/z"];
result.map[index].data[j].meta["Adduct"]          = data[result.x[j]][index]["Adduct"];
result.map[index].data[j].meta["MSMS"]            = data[result.x[j]][index]["MSMS"];
}
for(var j = 0; j < result.x.length; j ++) // 意味ある?
result.map[index].data[j][0] = result.map[index].data[j][0];
 
// 全体での最大Intensityを見つけ出す
result.map[index].max = max;
if(maxOfAll < max)
maxOfAll = max;
}
 
result.maxOfAll = maxOfAll;
 
result.title = lipidclass;
// アルキル、ジアシル用に配列にしておく
// -> 完全に別々になったので、無意味に
var array = [];
array.push(result);
 
return array;
}
// 文字列を正規表現文字列に変換する ////////////////////////////////////////
// param str 対象文字列
// return 正規表現用文字列
function translateForReg(str)
{
// ()はエスケープする
str = str.replace("(","\\(","g");
str = str.replace(")","\\)","g");
 
// Allはすべてが対象
if(str == "All" || str.length == 0)
str = ".*";
else
str = "^" + str + "$";
 
return str;
}
// chainグラフ用データの取得 ///////////////////////////////////////////////
// param samplename - Sample Name
// param samplesource - Sample Source
// param sampletype - Sample Type
// param lipidclass - Lipid class
// param chain - Lipid chain
// return 対象データ
function retrieveChainData(samplename, samplesource, sampletype, lipidclass, chain)
{
// sample sourceとsample typeはAllがあるため、正規表現を用いてマッチングを行う
var ssReg = new RegExp(translateForReg(samplesource));
var stReg = new RegExp(translateForReg(sampletype));
// var snReg = new RegExp(translateForReg(samplename), "i");
 
var result      = {};
var maxOfAll    = 0;
var index        = 0;
var legends      = {};
if(chain.indexOf("/") > 0)
result.title    = lipidclass + "(" + chain + ")";
else
result.title    = lipidclass + " " + chain;
result.lipidclass = lipidclass;
result.chain      = chain;
result.x        = [];
result.ionmode  = [];
result.intensity = [];
result.adduct    = [];
quantification  = "";
for(key in gAllData){
if(!ssReg.test(key)) // sample sourceが合致するか
continue;
for(var j = 0; j < gAllData[key].length; j ++){
if(!stReg.test(gAllData[key][j]["Sample name"])) // sample typeが合致するか
continue;
// if(!snReg.test(gAllData[key][j]["Sample name"])) // samplenameが合致するか
// continue;
 
// 特定のlipid class, lipid chainのみを対象とする
for(var k = 0; k < gAllData[key][j]["data"].length; k ++){
if(gAllData[key][j]["data"][k]["Lipid subclass"] != lipidclass)
continue;
 
if(!gAllData[key][j]["data"][k]["Lipid category"]) // 空データ
continue;
 
var lipidType = getLipidType(gAllData[key][j]["data"][k]);
// var legend = key + "/" + gAllData[key][j]["Sample name"];
var legend;
/* if(gAllData[key][j]["Sample name"] == "Human")
legend = "Human plasma";
else if(gAllData[key][j]["Sample name"] == "Mouse")
legend = gAllData[key][j]["Tissue/Species"];// + "_" + gAllData[key][j]["Sample type"] + "_" + gAllData[key][j]["Treatment"];
else if(gAllData[key][j]["Sample name"] == "Cell")
legend = gAllData[key][j]["SampleType"];
else*/
legend = gAllData[key][j]["Sample name"];
 
if(!legends[legend] && lipidType == chain){ // legend名が複数回被る可能性があるので、すでに格納済みのlegendは処理しない
// 対象,,m
result.x[index]        = legend;
result.ionmode[index]  = gAllData[key][j]["Ion mode"];
result.adduct[index]    = gAllData[key][j]["data"][k]["Adduct"];
result.intensity[index] = parseFloat(gAllData[key][j]["data"][k]["Quant value"]); // intensity
 
if(quantification.length == 0)
quantification = gAllData[key][j]["Quantification unit"];
else if(quantification != gAllData[key][j]["Quantification unit"])
quantification = "?";
 
if(maxOfAll < result.intensity[index]) // 全体での最大Intensityを調べる
maxOfAll = result.intensity[index];
index ++;
legends[legend] = true;
}
}
}
}
 
result.maxOfAll      = maxOfAll;
result.quantification = quantification;
 
return result;
}
// lipid chainを構築して返す。chain情報はSN1~SN4まで分かれており、さらにSN1が空の場合はTotal chainを使用する ///
// param array - 列データ
// return lipid chain文字列。16:0, 16:0/16:0など
function getLipidType(array)
{
// SN1からSN4までのchainを連結させる
var lipidType = array["SN1 chain"];
for(var l = 2; l <= 4; l ++){
if(array["SN" + l + " chain"].length > 0)
lipidType += "/" + array["SN" + l + " chain"];
else
break;
}
// SN1が空だった場合はTotalChainを使用する
if(lipidType.length == 0)
lipidType = array["Total chain"];
return lipidType;
}
}

Latest revision as of 01:43, 23 March 2020

// Last-update: 2020/02/04
// 対象項目からデータを検索する ////////////////////////////////////////////////////////
// param sampleSource - sample source
// param sampleType - sample type
// param lipidClass - lipid class
// return 検索結果
function lipoqualitySearch(sampleCategory, sampleName, lipidClass, dataType)
{
	// sample sourceとsample typeはAllがあるため、正規表現を用いてマッチングを行う
	var scReg = new RegExp(translateForReg(sampleCategory));
	var snReg = new RegExp(translateForReg(sampleName));
	var stReg = new RegExp(translateForReg(sampleName));

	var unitKey = "Quantification unit";
	if(dataType == "height"){
		unitKey = "Quantification unit(Ion abundance)";
	} else if(dataType == "normalized"){
		unitKey = "Quantification unit(Normalized value)";
	}
	// 検索
	var result = [];
	var i = 0;
	for(key in gAllData){
		if(!scReg.test(key)) // sample sourceが合致するか
			continue;

		for(var j = 0; j < gAllData[key].length; j ++){
			// イオン強度、もしくは濃度の切り分けをする
			if(gAllData[key][j][unitKey].length == 0)
				continue;
//console.log("length:" + j + "," + gAllData[key].length);
			// 対象sample source, sample typeかチェック
//console.log("st:" + key + ":" + gAllData[key][j]["Sample name"] + ":" + stReg.test(gAllData[key][j]["Sample name"]));
			if(!snReg.test(gAllData[key][j]["Sample name"])) // sample typeが合致するか
				continue;

//console.log("search:" + key + ":" + gAllData[key][j]["Sample name"] + ":" + gAllData[key][j]["data"].length);
			var found = false;
			for(var k = 0; k < gAllData[key][j]["data"].length; k ++){
				// 対象lipid classかチェック
//console.log("hit:" + key + ":" + gAllData[key][j]["data"][k]["Lipid subclass"] + "==" + lipidClass);
				if(gAllData[key][j]["data"][k]["Lipid subclass"] == lipidClass){
					found = true;
					break;
				}
			}
			// 対象だったので結果に格納する
			if(found){
				result[i] = [];
				result[i]["title"]       = key + " / " + gAllData[key][j]["Sample name"] + " / " + /*gAllData[key][j]["SampleType"] + " / " +*/ lipidClass + " / " + gAllData[key][j]["ID"];
				result[i]["Method link"] = gAllData[key][j]["Method link"];
				i ++;
			}
		}
	}

	return result;
}
function getQuantValue(array, flag)
{
	value = 0;
	if(flag == 'height'){
		var keys = Object.keys(array);
		for(var i = 0; i < keys.length; i ++){
			if(keys[i].startsWith("Ion abundance")){
				value = array[keys[i]];
				break;
			}
		}
	} else if(flag == 'normalized'){
		value = array['Normalized value by internal standard'];
	}
	if(isNaN(value))
		value = 0;
	return value;
}
// 指定されたID群をもとに、グラフ全般用のデータを取得する ///////////////////////////////
// param ids       - 対象データのID。「SampleCategory/Sample name/SampleType/LipidClass」で構成される。
// param chartType - 未使用
// return 対象データ
function retrieveChartData(ids, chartType, dataType)
{
	// '#7fbfff'がbarchartのデフォルト色と似ているので排除する
	var pieColors = ['#ff7f7f','#7f7fff','#7fff7f','#ff7fbf','#bfff7f','#ff7fff','#7fffff','#000000','#bf7fff','#7fffbf','#ffbf7f','#808080'];

	var unitKey = "Quantification unit";
	if(dataType == "height"){
		unitKey = "Quantification unit(Ion abundance)";
	} else if(dataType == "normalized"){
		unitKey = "Quantification unit(Normalized value)";
	}

	var result     = {};
	var data       = {};
	var colorKeys  = {};
	var colorIndex = 0;
	// id毎にデータを取得
	result.x   = []; // Xラベル
	result.map = []; // チャートデータ
	for(var index = 0; index < ids.length; index ++){
console.log("id:" + index + "=" + ids[index]);
		var w = ids[index].split(" / ");
		var sampleCategory = w[0];
		var sampleName   = w[1];
//		var sampleType   = w[2];
		var lipidclass   = w[2];
		var uniqid       = w[3];

		result.map[index]     = {}; // 通常チャート用
		result.map[index].pie = []; // パイチャート用
		var pieKeys = {};
		var pieIndex = 0;
		for(key in gAllData){ // sample source
			if(sampleCategory != key)
				continue;

			for(var j = 0; j < gAllData[key].length; j ++){ // sample category
				if(sampleName != gAllData[key][j]["Sample name"])
					continue;
				if(uniqid != gAllData[key][j]["ID"])
					continue;

				result.map[index].title = sampleCategory + " / " + sampleName + " / "/* + sampleType + "/"*/ + lipidclass + " / " + uniqid;
				result.map[index].meta  = {};
				for(meta in gAllData[key][j]){// 全メタ情報
					if(meta != "data"){
						if(meta.startsWith("Quantification unit")){
							result.map[index].meta["Quantification"] = gAllData[key][j][unitKey];
						} else
							result.map[index].meta[meta] = gAllData[key][j][meta];
					}
				}
//				if(sampleType != gAllData[key][j]["SampleType"])
//					continue;

				// 同一のLipidSuperClassのみ対象とする
				// 通常チャートは同一LipidClassのみだが、パイチャートにおいて意味を持つ
				var targetLipidSuperClass = undefined;
				for(var k = 0; k < gAllData[key][j]["data"].length; k ++){
					if(gAllData[key][j]["data"][k]["Lipid subclass"] == lipidclass){
						targetLipidSuperClass = gAllData[key][j]["data"][k]["Lipid category"];
						break;
					}
				}

				// 各lipid classのチェック
				for(var k = 0; k < gAllData[key][j]["data"].length; k ++){
					if(gAllData[key][j]["data"][k]["Lipid category"] != targetLipidSuperClass) // superクラスが違うものは対象外
						continue;

					var lc = gAllData[key][j]["data"][k]["Lipid subclass"];
					// lipid classごとに色を変える
					if(colorKeys[lc] == undefined){
						colorKeys[lc] = colorIndex++;
					}
					// パイチャート用データ
					if(pieKeys[lc] == undefined){
						pieKeys[lc] = pieIndex++;
						result.map[index].pie[pieKeys[lc]] = {};
						result.map[index].pie[pieKeys[lc]].name = lc; // type
						result.map[index].pie[pieKeys[lc]].color = pieColors[colorKeys[lc]%pieColors.length];
						result.map[index].pie[pieKeys[lc]].y = 0;
					}
					result.map[index].pie[pieKeys[lc]].y += parseFloat(getQuantValue(gAllData[key][j]["data"][k], dataType)); // intensity

					if(lc == lipidclass){ // lipid classが対象のものなら、通常チャート用にデータを格納する

						var lipidType = getLipidType(gAllData[key][j]["data"][k]); // chain文字列を取得する
						// すべてのデータでX軸を統一するため、いったんdata配列にデータを格納する
						if(data[lipidType] == undefined){ // まだ出てきていないchainならばX軸ラベルに追加する
							data[lipidType] = [];
							result.x.push(lipidType);
						}
						data[lipidType][index] = gAllData[key][j]["data"][k];

						//Logger.log(filename + "/" + tabname + "/" + type);
					}
				}
			}
		}
	}
console.log(result.x);
console.log("result");
console.log(result);

	// chainの小さい順に並べ替える
	result.x.sort(function(a1, a2){
		// chainの数による比較
		var lipidClass1 = a1.split("/");
		var lipidClass2 = a2.split("/");
		if(lipidClass1.length < lipidClass2.length) return -1;
		if(lipidClass1.length > lipidClass2.length) return 1;
		// chainの長さと二重結合数による比較
		for(var i = 0; i < lipidClass1.length; i ++){
			var lc1 = parseInt(lipidClass1[i].replace(/:/, ""));
			var lc2 = parseInt(lipidClass2[i].replace(/:/, ""));
			if(lc1 < lc2) return -1;
			if(lc1 > lc2) return 1;
		}
		return 0;
	});

	// データを整形
	var maxOfAll = 0;
	for(var index = 0; index < ids.length; index ++){
		result.map[index].data = [];
		var max = 0;
		for(var j = 0; j < result.x.length; j ++){
			result.map[index].data[j] = [];

			if(data[result.x[j]][index] == undefined){ // このデータには、対象chainの情報がないため、ダミーを格納しておく
				data[result.x[j]][index] = {
					"Quant value"       : "0",
					"Formula"           : "",
					"InChIKey"          : "",
					"SMILES"            : "",
					"RT(min)"           : "",
					"m/z"               : "",
					"Adduct"            : "",
					"MSMS"              : "",
					"Internal standard" : "-"
				};
			}

			// Intensityの処理
			var inte = parseFloat(getQuantValue(data[result.x[j]][index], dataType));
			if(inte > max)
				max = inte;
			result.map[index].data[j].push(inte);

			// メタ情報の格納
			result.map[index].data[j].meta = {};
			result.map[index].data[j].meta["Formula"]           = data[result.x[j]][index]["Formula"];
			result.map[index].data[j].meta["InChIKey"]          = data[result.x[j]][index]["InChIKey"];
			result.map[index].data[j].meta["SMILES"]            = data[result.x[j]][index]["SMILES"];
			result.map[index].data[j].meta["RT(min)"]           = data[result.x[j]][index]["RT(min)"];
			result.map[index].data[j].meta["m/z"]               = data[result.x[j]][index]["m/z"];
			result.map[index].data[j].meta["Adduct"]            = data[result.x[j]][index]["Adduct"];
			result.map[index].data[j].meta["MSMS"]              = data[result.x[j]][index]["MSMS"];
			if(dataType == 'normalized')
				result.map[index].data[j].meta["Internal standard"] = data[result.x[j]][index]["Internal standard"];
			else
				result.map[index].data[j].meta["Internal standard"] = '-';
		}
		for(var j = 0; j < result.x.length; j ++) // 意味ある?
			result.map[index].data[j][0] = result.map[index].data[j][0];

		// 全体での最大Intensityを見つけ出す
		result.map[index].max = max;
		if(maxOfAll < max)
			maxOfAll = max;
	}

	result.maxOfAll = maxOfAll;

	result.title = lipidclass;
	// アルキル、ジアシル用に配列にしておく
	// -> 完全に別々になったので、無意味に
	var array = [];
	array.push(result);

	return array;
}
// 文字列を正規表現文字列に変換する ////////////////////////////////////////
// param str 対象文字列
// return 正規表現用文字列
function translateForReg(str)
{
	// ()はエスケープする
	str = str.replace("(","\\(","g");
	str = str.replace(")","\\)","g");

	// Allはすべてが対象
	if(str == "All" || str.length == 0)
		str = ".*";
	else
		str = "^" + str + "$";

	return str;
}
// chainグラフ用データの取得 ///////////////////////////////////////////////
// param samplename - Sample Name
// param samplesource - Sample Source
// param sampletype - Sample Type
// param lipidclass - Lipid class
// param chain - Lipid chain
// return 対象データ
function retrieveChainData(samplename, samplesource, sampletype, lipidclass, chain, dataType)
{
	// sample sourceとsample typeはAllがあるため、正規表現を用いてマッチングを行う
	var ssReg = new RegExp(translateForReg(samplesource));
	var stReg = new RegExp(translateForReg(sampletype));
//	var snReg = new RegExp(translateForReg(samplename), "i");

	var unitKey = "Quantification unit";
	if(dataType == "height"){
		unitKey = "Quantification unit(Ion abundance)";
	} else if(dataType == "normalized"){
		unitKey = "Quantification unit(Normalized value)";
	}

	var result       = {};
	var maxOfAll     = 0;
	var index        = 0;
	var legends      = {};
	if(chain.indexOf("/") > 0)
		result.title     = lipidclass + "(" + chain + ")";
	else
		result.title     = lipidclass + " " + chain;
	result.lipidclass = lipidclass;
	result.chain      = chain;
	result.x         = [];
	result.ionmode   = [];
	result.intensity = [];
	result.adduct    = [];
	quantification   = "";
	for(key in gAllData){
		if(!ssReg.test(key)) // sample sourceが合致するか
			continue;
		for(var j = 0; j < gAllData[key].length; j ++){
			if(!stReg.test(gAllData[key][j]["Sample name"])) // sample typeが合致するか
				continue;
//			if(!snReg.test(gAllData[key][j]["Sample name"])) // samplenameが合致するか
//				continue;

			// 特定のlipid class, lipid chainのみを対象とする
			for(var k = 0; k < gAllData[key][j]["data"].length; k ++){
				if(gAllData[key][j]["data"][k]["Lipid subclass"] != lipidclass)
					continue;

				if(!gAllData[key][j]["data"][k]["Lipid category"]) // 空データ
					continue;

				var lipidType = getLipidType(gAllData[key][j]["data"][k]);
//				var legend = key + "/" + gAllData[key][j]["Sample name"];
				var legend;
/*				if(gAllData[key][j]["Sample name"] == "Human")
					legend = "Human plasma";
				else if(gAllData[key][j]["Sample name"] == "Mouse")
					legend = gAllData[key][j]["Tissue/Species"];// + "_" + gAllData[key][j]["Sample type"] + "_" + gAllData[key][j]["Treatment"];
				else if(gAllData[key][j]["Sample name"] == "Cell")
					legend = gAllData[key][j]["SampleType"];
				else*/
					legend = gAllData[key][j]["Category"] + " / " + gAllData[key][j]["Sample name"] + " / " + gAllData[key][j]["ID"];
				if(!legends[legend] && lipidType == chain){ // legend名が複数回被る可能性があるので、すでに格納済みのlegendは処理しない
					// 対象,,m
					result.x[index]         = legend;
					result.ionmode[index]   = gAllData[key][j]["Ion mode"];
					result.adduct[index]    = gAllData[key][j]["data"][k]["Adduct"];
					result.intensity[index] = parseFloat(getQuantValue(gAllData[key][j]["data"][k], dataType)); // intensity
					if(quantification.length == 0){
						quantification = gAllData[key][j][unitKey];
					} else if(quantification != gAllData[key][j]["Quantification unit"])
						quantification = "'Quantification unit's are mixed";

					if(maxOfAll < result.intensity[index]) // 全体での最大Intensityを調べる
						maxOfAll = result.intensity[index];
					index ++;
					legends[legend] = true;
				}
			}
		}
	}

	result.maxOfAll       = maxOfAll;
	result.quantification = quantification;

	return result;
}
// lipid chainを構築して返す。chain情報はSN1~SN4まで分かれており、さらにSN1が空の場合はTotal chainを使用する ///
// param array - 列データ
// return lipid chain文字列。16:0, 16:0/16:0など
function getLipidType(array)
{
	// SN1からSN4までのchainを連結させる
	var lipidType = array["SN1 chain"];
	for(var l = 2; l <= 4; l ++){
		if(array["SN" + l + " chain"].length > 0)
			lipidType += "/" + array["SN" + l + " chain"];
		else
			break;
	}
	// SN1が空だった場合はTotalChainを使用する
	if(lipidType.length == 0)
		lipidType = array["Total chain"];
	return lipidType;
}

// 指定されたID群をもとに、ダウンロード用データをjson形式で返す ///////////////////////////////
// param ids       - 対象データのID。「SampleCategory/Sample name/Lipid subclass/ID」で構成される。
// return json形式の文字列
function getDownloadData(ids)
{
	var result = {};
	for(var index = 0; index < ids.length; index ++){
		var w = ids[index].split(" / ");
		var sampleCategory = w[0];
		var sampleName     = w[1];
		var lipidclass     = w[2];
		var uniqid         = w[3];

		for(key in gAllData){ // sample source
			if(sampleCategory != key)
				continue;

			for(var j = 0; j < gAllData[key].length; j ++){ // sample category
				if(uniqid != gAllData[key][j]["ID"])
					continue;

				if(!(key in result))
					result[key] = [];
				result[key].push(gAllData[key][j]);
			}
		}
	}
	console.log(result);

	return JSON.stringify(result, null, 4);
}