504 lines
35 KiB
Ruby
504 lines
35 KiB
Ruby
class Cancerpredictfields
|
||
require "pathname"
|
||
require 'json'
|
||
include Mongoid::Document
|
||
include Mongoid::Timestamps
|
||
Field_relations = {"number_field"=>"Fixnum","text_area"=>"String"}
|
||
FIELDINFO = {"variable"=>"String","name"=>"String","is_num"=>"Fixnum","hint"=>"String","comment_text"=>"String","choice_fields"=>"Array","range"=>"Array","right"=>"Fixnum","is_float"=>"Fixnum","revert_value"=>"Fixnum","map_values"=>"Array","cancer_predict_mapping_file"=>"String","lpv_impact"=>"Float","active_choice"=>"number_field","disable_condition"=>"text_area"}
|
||
NonLoclaized = ["variable","is_num","range","right","is_float","revert_value","map_values","cancer_predict_mapping_file","lpv_impact","active_choice","disable_condition"]
|
||
AdvanceFields = ["revert_value","map_values","cancer_predict_mapping_file"]
|
||
TherapyFields = ["variable","name","hint","comment_text","choice_fields","lpv_impact","active_choice","disable_condition"]
|
||
TherapyOnly = ["lpv_impact","active_choice","disable_condition"]
|
||
JSFileName = "public/cancer_tool_js_filename.txt".freeze
|
||
ToolTablePrefix = "public/cancer_tool_table_tmp_".freeze
|
||
field :title ,type:String ,default:""
|
||
field :advance_mode, type: Boolean, default: false
|
||
field :form_show , :type=> Hash ,default:{
|
||
"0"=>{"variable"=>"age", "name"=>{"zh_tw"=>"年齡<br/>(Age)", "en"=>"Age"}, "is_num"=>1, "hint"=>{"zh_tw"=>"從 18 歲(含)開始至 93 歲", "en"=>"Age must be between 18 and 93"}, "comment_text"=>{"zh_tw"=>"年齡為該婦女於確診罹患乳癌時之年齡", "en"=>"Age at diagnosis"}, "choice_fields"=>{"zh_tw"=>[], "en"=>[]}, "range"=>[18, 93], "right"=>0, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"1"=>{"variable"=>"size", "name"=>{"zh_tw"=>"腫瘤大小(單位:mm)<br/>(Tumor size)", "en"=>"Tumor size"}, "is_num"=>1, "hint"=>{"zh_tw"=>"", "en"=>"The unit of tumor size is millimeter (mm)"}, "comment_text"=>{"zh_tw"=>"若有多個原發腫瘤,請輸入最大尺寸之原發腫瘤", "en"=>"If there was more than one primary tumor, please enter the size of the largest one."}, "choice_fields"=>{"zh_tw"=>[], "en"=>[]}, "range"=>[1, 300], "right"=>0, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"2"=>{"variable"=>"lymph_nodes_examined", "name"=>{"zh_tw"=>"區域淋巴結檢查數目<br/>(Regional lymph nodes examined)", "en"=>"Regional lymph nodes examined"}, "is_num"=>1, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"", "en"=>""}, "choice_fields"=>{"zh_tw"=>["未知"], "en"=>["unknown"]}, "range"=>[0, 90], "right"=>0, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"3"=>{"variable"=>"lymph_nodes_positive", "name"=>{"zh_tw"=>"區域淋巴結侵犯數目<br/>(Regional lymph nodes positive)", "en"=>"Regional lymph nodes positive"}, "is_num"=>1, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"此變項為預測重要變數,若無此資訊預測容易失真。", "en"=>"Regional lymph nodes positive is a key predictive variable. If this information is omitted, the prediction result would be biased."}, "choice_fields"=>{"zh_tw"=>["未知"], "en"=>["unknown"]}, "range"=>[0, 90], "right"=>0, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"4"=>{"variable"=>"grade", "name"=>{"zh_tw"=>"腫瘤分化程度<br/>(Tumor grade)", "en"=>"Tumor grade"}, "is_num"=>0, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"腫瘤級數代表腫瘤組織與正常組織間的分化程度,若無分化級數資訊,請選擇“未知”選項,將以級數 2 進行預測。", "en"=>"The grade refers to how different the cancer cells are from normal cells. Please select “unknown” if there is no information about grade. The prediction model would use “grade 2” as the alternative variable."}, "choice_fields"=>{"zh_tw"=>["1", "2", "3", "未知"], "en"=>["1", "2", "3", "unknown"]}, "range"=>[], "right"=>0, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"5"=>{"variable"=>"ER_status", "name"=>{"zh_tw"=>"ER 狀態<br/>(ER status)", "en"=>"ER status"}, "is_num"=>0, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"ER:雌激素受體,若無 ER 資訊請選擇未知,將以佔多數比例陽 性作為後續預測。", "en"=>"ER status describes the status of estrogen receptor. Please select “unknown” if there is no information about ER status. The prediction model would use “Positive” (the majority class) as the alternative variable."}, "choice_fields"=>{"zh_tw"=>["陽性", "陰性", "未知"], "en"=>["positive", "negative", "unknown"]}, "range"=>[], "right"=>0, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"6"=>{"variable"=>"PR_status", "name"=>{"zh_tw"=>"PR 狀態<br/>(PR status)", "en"=>"PR status"}, "is_num"=>0, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"PR:黃體素受體, 若無 PR 資訊請選擇未知,將以佔多數比例陽性作為後續預測。", "en"=>"PR status describes the status of progesterone receptor. Please select “unknown” if there is no information about PR status. The prediction model would use “Positive” (the majority class) as the alternative variable."}, "choice_fields"=>{"zh_tw"=>["陽性", "陰性", "未知"], "en"=>["positive", "negative", "unknown"]}, "range"=>[], "right"=>1, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"7"=>{"variable"=>"HER2_status", "name"=>{"zh_tw"=>"HER2 狀態<br/>(HER2 status)", "en"=>"HER2 status"}, "is_num"=>0, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"HER2:第二型人類上皮成長因子接受器蛋白,若無 HER2 資訊請選擇未知,將以佔多數比例陰性作為後續預測。", "en"=>"HER2 status describes the status of human epidermal growth factor receptor 2. Please select “unknown” if there is no information about HER2 status. The prediction model would use “Negative” (the majority class) as the alternative variable."}, "choice_fields"=>{"zh_tw"=>["陽性", "陰性", "未知"], "en"=>["positive", "negative", "unknown"]}, "range"=>[], "right"=>1, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"8"=>{"variable"=>"Distant_Metastasis", "name"=>{"zh_tw"=>"遠端轉移<br/>(Distant Metastasis)", "en"=>"Distant Metastasis"}, "is_num"=>0, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"若無遠端轉移資訊請選擇未知,將以佔多數比例未遠端轉移作為後續預測。", "en"=>"Please select “unknown” if there is no information about distant Metastasis. The prediction model would use “No” (the majority class) as the alternative variable."}, "choice_fields"=>{"zh_tw"=>["是", "否", "未知"], "en"=>["yes", "no", "unknown"]}, "range"=>[], "right"=>1, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"9"=>{"variable"=>"micrometastasis", "name"=>{"zh_tw"=>"淋巴結顯微轉移<br/>(Lymph nodes micrometastasis)", "en"=>"Micrometastasis"}, "is_num"=>0, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"若無顯微移資訊請選擇未知,將以無顯微轉移作為後續預測。", "en"=>"Please select “unknown” if there is no information about lymph nodes micrometastasis. The prediction model would use “No” as the alternative variable."}, "choice_fields"=>{"zh_tw"=>["是", "否", "未知"], "en"=>["yes", "no", "unknown"]}, "range"=>[], "right"=>1, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"10"=>{"variable"=>"tumor_direct_extension", "name"=>{"zh_tw"=>"腫瘤浸潤至胸壁和/或皮膚<br/>(Tumor direct extension to the chest wall and/or to the skin)", "en"=>"Tumor direct extension to the chest wall and/or to the skin"}, "is_num"=>0, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"若無腫瘤浸潤至胸壁或皮膚資訊請選擇未知,將以佔多數比例無腫瘤浸潤至胸壁作為後續預測。", "en"=>"Please select “unknown” if there is no information about tumor direct extension to the chest wall and/or to the skin. The prediction model would use “No” (the majority class) as the alternative variable"}, "choice_fields"=>{"zh_tw"=>["是", "否", "未知"], "en"=>["yes", "no", "unknown"]}, "range"=>[], "right"=>1, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]},
|
||
"11"=>{"variable"=>"lvi", "name"=>{"zh_tw"=>"淋巴管或血管侵犯<br/>(Lymph vessel or vascular invasion, LVI)", "en"=>"Lymph vessel or vascular invasion, LVI"}, "is_num"=>0, "hint"=>{"zh_tw"=>"", "en"=>"Lymph vessel or vascular invasion"}, "comment_text"=>{"zh_tw"=>"若無淋巴管或血管侵犯資訊,請選擇“未知”選項,將以佔多數比例的淋巴管或血管未侵犯進行預測", "en"=>"Please select “unknown” if there is no information about Lymph vessel or vascular invasion. The prediction model would use “No” (the majority class) as the alternative variable."}, "choice_fields"=>{"zh_tw"=>["是", "否", "未知"], "en"=>["yes", "no", "unknown"]}, "range"=>[], "right"=>1, "is_float"=>0, "need_map_values"=>0, "revert_value"=>0, "map_values"=>[]}
|
||
}
|
||
field :form_show_in_result , :type=> Hash ,default: {
|
||
"0"=>{"variable"=>"hormone_therapy", "name"=>{"zh_tw"=>"賀爾蒙治療", "en"=>"Hormone/Steroid therapy"}, "is_num"=>0, "hint"=>{"zh_tw"=>"適用賀爾蒙受體陽性病人", "en"=>"Hormone/ steroid therapy is available when ER status is positive"}, "comment_text"=>{"zh_tw"=>"", "en"=>""}, "choice_fields"=>{"zh_tw"=>["否", "是"], "en"=>["No", "Yes"]}, "range"=>[], "right"=>0, "is_float"=>0, "revert_value"=>0, "map_values"=>"", "active_choice"=>2, "disable_condition"=>"ER_status == 2 && PR_status == 2", "lpv_impact"=>-0.8397},
|
||
"1"=>{"variable"=>"Chemotherapy", "name"=>{"zh_tw"=>"化學治療", "en"=>"Chemotherapy"}, "is_num"=>0, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"", "en"=>""}, "choice_fields"=>{"zh_tw"=>["否", "是"], "en"=>["No", "Yes"]}, "range"=>[], "right"=>0, "is_float"=>0, "revert_value"=>0, "map_values"=>"", "active_choice"=>2, "disable_condition"=>"", "lpv_impact"=>-0.4147},
|
||
"2"=>{"variable"=>"Radiotherapy", "name"=>{"zh_tw"=>"放射治療", "en"=>"Radiotherapy"}, "is_num"=>0, "hint"=>{"zh_tw"=>"", "en"=>""}, "comment_text"=>{"zh_tw"=>"", "en"=>""}, "choice_fields"=>{"zh_tw"=>["否", "是"], "en"=>["No", "Yes"]}, "range"=>[], "right"=>0, "is_float"=>0, "revert_value"=>0, "map_values"=>"", "active_choice"=>2, "disable_condition"=>"", "lpv_impact"=>-0.3203},
|
||
"3"=>{"variable"=>"Targeted_therapy", "name"=>{"zh_tw"=>"標靶治療", "en"=>"Targeted therapy"}, "is_num"=>0, "hint"=>{"zh_tw"=>"抗HER2治療", "en"=>""}, "comment_text"=>{"zh_tw"=>"", "en"=>""}, "choice_fields"=>{"zh_tw"=>["否", "是"], "en"=>["No", "Yes"]}, "range"=>[], "right"=>0, "is_float"=>0, "revert_value"=>0, "map_values"=>"", "active_choice"=>2, "disable_condition"=>"HER2_status != 1", "lpv_impact"=>-0.4687}
|
||
}
|
||
field :form_result_is_right , :type=> Integer ,default: 0
|
||
field :text_descibe ,type:Hash ,default: {
|
||
"zh_tw"=>"歡迎使用台灣準備乳癌預後系統!<br />\r\n本預測系統由台灣癌症登記資料庫2011至2015年間共20,997位乳癌病人所建立<br />\r\n並驗證美國流行病學癌症資料庫59,271位病人所建立 。<br />\r\n若要開始 請在下方選擇相關資訊",
|
||
"en"=>"Welcome to the Taiwan Breast Cancer Prediction System!<br />\r\nThe prediction system is constructed using clinical data from 90,841 breast cancer patients in the Taiwan Cancer Registry database between 2011 to 2015, and validated using clinical data from 49,374 breast cancer patients in the U.S.-based Surveillance, Epidemiology and End Results (SEER) database.<br />\r\nTo start, please select the information below."
|
||
}
|
||
field :small ,type:Hash ,default:{'font_size'=>"0.825em",'active'=>0}
|
||
field :medium ,type:Hash ,default:{'font_size'=>"1em",'active'=>1}
|
||
field :large ,type:Hash ,default:{'font_size'=>"1.25em",'active'=>0}
|
||
field :head_images_id ,type:Array , default: [BSON::ObjectId('5df62cfc8cd8924e79000009'), BSON::ObjectId('5df745a58cd8924491000006'), BSON::ObjectId('5e7848c98cd8924f8d00004a'), BSON::ObjectId('5ea8f3e48cd892760b000011')]
|
||
field :title_images_id ,type:Array , default: [BSON::ObjectId('5df87cd88cd8924491000036')]
|
||
field :title_texts ,type:Hash ,default: {"zh_tw"=>"華人癌症存活預測", "en"=>"Asian breast cancer prediction"}
|
||
field :table_above_texts ,type:Hash ,default: {"zh_tw"=>"下表之分析為針對手術後病人,根據選定的術後治療,分別估計在第1年、3 及5年的存活率。", "en"=>"The analysis is for women who had undergone surgery.The table shows the 1-, 3- and 5-year survival rates,based on the treatment you have selected."}
|
||
field :text_above_texts ,type:Hash ,default: {"zh_tw"=>"此研究分析來自已接受根除性手術後之婦女所得之結果,根據您所輸入的資訊以及治療方式,在術後<br/>第{{years}}年,", "en"=>"The analysis is for women who had undergone surgery. Base on the information and the treatment you have selected, the predictions of survival status<br/>{{years}}"}
|
||
field :surgery_only_texts ,type:Hash ,default: {"zh_tw"=>"100 位只接受根除性手術的婦女中,有{{Surgery_only}}位婦女,術後{{surgery_year}}年仍為存活", "en"=>"after surgery are as follows:<br/>{{Surgery_only}} out of 100 women treated with surgery only are alive at {{surgery_year}} years."}
|
||
field :extra_texts ,type:Hash ,default: {"zh_tw"=>",此外", "en"=>""}
|
||
field :extra_therapy_texts ,type:Hash ,default: {"zh_tw"=>"100 位在術後有接受{{extra_therapy}}的婦女中,有{{survival_num}}位婦女,術後{{surgery_year}}年仍為存活(多了{{Additional_Benefit}}位)", "en"=>"{{survival_num}} out of 100 women treated with {{extra_therapy}} are alive (an extra {{Additional_Benefit}})"}
|
||
field :danger_texts ,type:Hash ,default: {"zh_tw"=>"請注意紅框的輸入資料是否符合要求!", "en"=>"Please check whether input data in red blocks are correct!"}
|
||
field :years ,type:Array ,default:[1,3,5]
|
||
field :texts_between_Result_and_result_block ,type:Hash ,default: {"zh_tw"=>"如果欲將預測結果應用於臨床上,請務必與您的主治醫師討論後再做最後決定。", "en"=>"Please note that the patients need to consult with their medical doctors before making any decision."}
|
||
#field :image_uploader ,type:Object
|
||
field :prediction_formula , type: String ,default: "lpv = ((age1-0.7276655)*(-10.87)+(age2+0.4540707)*8.968+(size1-0.643632)*0.7678+(nposit-1.346932)*0.5339+
|
||
grade_2*0.4795+grade_3*0.818+subtype_HER2*0.1806+subtype_triple*0.6457+pstage_2*0.5311+
|
||
pstage_3*1.134+pstage_4*2.172+lvi_yes*0.3321-0.04+chemo*(-0.4147)+radio*(-0.3203)+hormone*(-0.8397)+target*(0.3321)
|
||
)"
|
||
field :years_settings , type: Array , default: ["exp(-0.001476145)^( exp(lpv) )","exp(-0.01261639)^( exp(lpv) )","exp(-0.02519608)^( exp(lpv) )"]
|
||
field :tmp_years_settings , type: Array , default: []
|
||
field :tmp_years_settings_for_ruby , type: Array , default: []
|
||
field :hidden_variables, type: String, default: "age1 = (age / 100.0) ^ (0.5)
|
||
age2 = age1 * log(age / 100.0)
|
||
size1 = log(size / 10.0)
|
||
ratio = (lymph_nodes_examined == 0 ? 0 : (1.0 * lymph_nodes_positive / lymph_nodes_examined))
|
||
ratio = (ratio > 1 ? 1 : ratio)
|
||
T4 = (tumor_direct_extension == 1)
|
||
T1 = !T4 && (size <= 20)
|
||
T2 = !T4 && !T1 && (size > 20 && size <= 50)
|
||
T = (T4 ? 'T4' : (T1 ? 'T1' : (T2 ? 'T2' : 'T3')))
|
||
N0 = (lymph_nodes_positive == 0)
|
||
N1_or_N1mi = !N0 && (lymph_nodes_positive >= 1 && lymph_nodes_positive <= 3)
|
||
N1 = N1_or_N1mi && micrometastasis != 1
|
||
N1mi = N1_or_N1mi && micrometastasis == 1
|
||
N2 = !N0 && !N1_or_N1mi && (lymph_nodes_positive <= 9)
|
||
N = (N0 ? 'N0' : (N1 ? 'N1' : (N1mi ? 'N1mi' : (N2 ? 'N2' : 'N3'))))
|
||
M = (Distant_Metastasis != 1) ? 'M0' : 'M1'
|
||
pstage = (M == 'M1' ? 4 : ((T == 'T1' && (N == 'N0' || N == 'N1mi')) ? 1 : (((T == 'T2' || T == 'T3') && (N == 'N0')) || ((T == 'T1' || T == 'T2') && (N == 'N1')) ? 2 : 3)) )
|
||
nposit = ((ratio + 0.1) / 0.1) ^ 0.5
|
||
grade_2 = (grade == 2 || grade == 4) ? 1 : 0
|
||
grade_3 = (grade == 3) ? 1 : 0
|
||
subtype_1 = (ER_status != 2 || PR_status != 2) && (HER2_status != 1)
|
||
subtype_2 = !subtype_1 && (HER2_status == 1)
|
||
subtype_3 = !subtype_1 && !subtype_2 && (ER_status == 2 && PR_status == 2 && HER2_status != 1)
|
||
subtype_HER2 = subtype_2 ? 1 : 0
|
||
subtype_triple = subtype_3 ? 1 : 0
|
||
pstage_2 = (pstage == 2) ? 1 : 0
|
||
pstage_3 = (pstage == 3) ? 1 : 0
|
||
pstage_4 = (pstage == 4) ? 1 : 0
|
||
lvi_yes = (lvi == 1) ? 1 : 0
|
||
chemo = (Chemotherapy == 2) ? 1 : 0
|
||
radio = (Radiotherapy == 2) ? 1 : 0
|
||
hormone = (hormone_therapy == 2) ? 1 : 0
|
||
target = (Targeted_therapy == 2) ? 1 : 0
|
||
"
|
||
field :fix_hidden_variables, type: Array, default: []
|
||
field :tmp_hidden_variables_for_ruby, type: String, default: ""
|
||
field :tmp_hidden_variables_for_js, type: String, default: ""
|
||
field :lpv_calc, type: Hash, default: {} #for js code
|
||
field :tmp_lpv_ruby_code, type: String, default: ""
|
||
field :tmp_lpv_variables, type: Array, default: []
|
||
field :mapping_data_from_csv , type: String ,default: ""
|
||
field :all_variables, type: Array, default: []
|
||
field :treatment_method, type: Array, default: ['Surgery_only']
|
||
field :treatment_method_active_indices, type: Array, default: [1]
|
||
field :result_table, type: String, default: "", localize: true
|
||
field :result_text, type: String, default: "", localize: true
|
||
field :therapy_lpv, type: Array, default: [0]
|
||
#before_create :set_expire
|
||
before_save do
|
||
self.form_show.each do |num,property|
|
||
property[:need_map_values] = (property[:map_values].class == Array && property[:choice_fields].class == Array && property[:map_values].length == property[:choice_fields].length) ? 1 : 0
|
||
end
|
||
result_keys = []
|
||
self.form_show.each do |num,property|
|
||
variable_name = property[:variable]
|
||
if variable_name.present?
|
||
result_keys << variable_name
|
||
end
|
||
end
|
||
self.form_show_in_result.each do |num,property|
|
||
variable_name = property[:variable]
|
||
if variable_name.present?
|
||
result_keys << variable_name
|
||
end
|
||
end
|
||
mapping_data = JSON.parse(self.mapping_data_from_csv) rescue {}
|
||
if self.advance_mode && mapping_data.present?
|
||
mapping_data.each do |k,v|
|
||
result_keys += (v.keys rescue [])
|
||
end
|
||
end
|
||
result_keys = result_keys.uniq
|
||
self.all_variables = result_keys
|
||
formula = text_to_math(self.prediction_formula)
|
||
tmp_hidden_variables = text_to_math(self.hidden_variables)
|
||
result_keys.each do |k|
|
||
formula = formula.gsub(/(\A|[^\w])#{k}($|[^\w])/){|f| "#{$1}result[\"#{k.strip}\"]#{$2}" }
|
||
tmp_hidden_variables = tmp_hidden_variables.gsub(/(\A|[^\w])#{k}($|[^\w])/){|f| "#{$1}result[\"#{k.strip}\"]#{$2}" }
|
||
end
|
||
self.tmp_hidden_variables_for_js = tmp_hidden_variables.rstrip.gsub(/\n\s+/,"\n ").gsub("\n",";\n") + ";"
|
||
self.fix_hidden_variables = []
|
||
self.tmp_hidden_variables_for_ruby = tmp_hidden_variables.split(/^([^=!]+)=([^=!])/).select{|s| s.present?}.each_slice(2).map do |a,b|
|
||
a = a.strip
|
||
self.fix_hidden_variables << a
|
||
if b
|
||
("result[\"#{a}\"]=" + b.gsub("\n",""))
|
||
else
|
||
a
|
||
end
|
||
end.join("\n")
|
||
self.fix_hidden_variables = self.fix_hidden_variables.uniq
|
||
formula = formula.split(/^([^=!]+)=([^=!])/).select{|s| s.present?}.each_slice(2).map do |a,b|
|
||
a = a.strip
|
||
if b
|
||
("result[\"#{a}\"]=" + b.gsub("\n",""))
|
||
else
|
||
a
|
||
end
|
||
end.join("\n")
|
||
self.fix_hidden_variables.each do |v|
|
||
formula = formula.gsub(/(\A|[^\w\"])#{v}($|[^\w])/){|f| "#{$1}result[\"#{v.strip}\"]#{$2}"}
|
||
self.tmp_hidden_variables_for_ruby = self.tmp_hidden_variables_for_ruby.gsub(/(\A|[^\w\"])#{v}($|[^\w])/){|f| "#{$1}result[\"#{v.strip}\"]#{$2}"}
|
||
end
|
||
self.tmp_lpv_ruby_code = formula
|
||
formula_variables = formula.enum_for(:scan,/([^\=\(\)]+)?=[^=]/).map {|x| x[-1] }.compact.map{|s| s.strip[8..-3]}
|
||
self.tmp_lpv_variables = formula_variables
|
||
self.tmp_years_settings = self.years_settings.map do |s|
|
||
text_to_math(s)
|
||
end
|
||
self.tmp_years_settings_for_ruby = self.tmp_years_settings.clone
|
||
formula_variables.each do |variable_name|
|
||
self.tmp_years_settings_for_ruby = self.tmp_years_settings_for_ruby.map do |y|
|
||
y.gsub(variable_name,"result[\"#{variable_name}\"]")
|
||
end
|
||
end
|
||
self.treatment_method = ['Surgery_only']
|
||
self.form_show_in_result.values.each do |choice|
|
||
variable = choice["variable"]
|
||
if variable.present?
|
||
self.treatment_method << variable
|
||
end
|
||
end
|
||
tmp_table_translations = {}
|
||
tmp_text_translations = {}
|
||
@years = self.years
|
||
@head_name = ['Treatment','Additional_Benefit','Overall_Survival']
|
||
# @head_name = ['Treatment','Overall_Survival']
|
||
@therapy_names = self.treatment_method
|
||
I18n.available_locales.each do |locale|
|
||
I18n.with_locale(locale) do
|
||
@table_head = @head_name.map{|name| I18n.t('cancerpredict.table.'+name)}
|
||
@therapy_choices = [I18n.t('cancerpredict.table.Surgeryonly')]
|
||
self.form_show_in_result.values.each{|choice| @therapy_choices.push choice["name"][locale].to_s}
|
||
tmp_table = "<span class=\"result_title print_only\">#{I18n.t("cancerpredict.table.table")}</span><div style=\"clear: both\"></div>"
|
||
tmp_table += '<input id="current_year" type="hidden" value="'+@years[-1].to_s+'" index="0"/><p id="cancer_table_texts">'+self.table_above_texts[locale].to_s+'</p>'
|
||
tmp_table += ('<a style="display: inline-block;">'+(locale.to_s == 'zh_tw' ? '第' : '')+'</a><a style="display: inline-block;">')
|
||
@years.each{|year| tmp_table += ('<button class="cancer_years cancer_table_btn btn btn-default btn-sm">'+year.to_s+'</button>')}
|
||
tmp_table += ('</a><a style="display: inline-block;">'+(locale == 'zh_tw' ? '年' : '')+'</a>')
|
||
tmp_table += '<table><thead><tr>'
|
||
@table_head.each_with_index{|head,index| tmp_table += ('<th class="cancer_th '+@head_name[index]+'">' + head + '</th>')}
|
||
tmp_table += '</tr></thead><tbody>'
|
||
@therapy_choices.each_with_index do |choice,i|
|
||
tmp_table += '<tr class="'+@therapy_names[i].to_s+'">'
|
||
@table_head.each_with_index do |head,index|
|
||
tmp_table += ('<td class="cancer_td '+ @head_name[index]+'">' + ((index == 0) ? (((i==0)? '' : '+') + choice) : '-') + '</td>')
|
||
end
|
||
tmp_table += '</tr>'
|
||
end
|
||
tmp_table_translations[locale] = tmp_table
|
||
@texts = self.text_above_texts[locale].to_s.gsub('<br/>','</span><br/><span>').gsub('{{Surgery_only}}','<span class="'+@therapy_names[0]+' Overall_Survival"></span>')
|
||
@texts = @texts.split('{{years}}')
|
||
@texts.delete('')
|
||
tmp_text = "<span class=\"result_title print_only\">#{I18n.t("cancerpredict.table.text")}</span><div style=\"clear: both\"></div>"
|
||
tmp_text += ('<span>'+@texts[0].to_s)
|
||
@years.each{|year| tmp_text += ('<button class="cancer_years cancer_table_btn btn btn-default btn-sm" style="float:none;">'+year.to_s+'</button>')}
|
||
if @texts.count > 1
|
||
tmp_text += (@texts[1]+'</span>') if @texts.count > 1
|
||
else
|
||
tmp_text += '</span>'
|
||
end
|
||
if !self.surgery_only_texts[locale].blank?
|
||
@surgery_only_texts = self.surgery_only_texts[locale]
|
||
@surgery_only_texts.insert(0,'<p class="show"><span>')
|
||
@surgery_only_texts = @surgery_only_texts.gsub('{{Surgery_only}}','<span class="'+@therapy_names[0]+' Overall_Survival"></span><span>')
|
||
@surgery_only_texts = @surgery_only_texts.gsub('{{surgery_year}}','</span><span class="surgery_year">'+@years[-1].to_s+'</span><span>')
|
||
@surgery_only_texts += '</span>'
|
||
else
|
||
@surgery_only_texts = ''
|
||
end
|
||
tmp_text += @surgery_only_texts
|
||
tmp_text += '<span class="addition">'+(self.extra_texts[locale].to_s rescue '')+'</span><div class="extra-text" style="display:none;"><div class="texts_show" style="clear:both;"></div></div></p>'
|
||
tmp_text_translations[locale] = tmp_text
|
||
end
|
||
end
|
||
self.result_table_translations = tmp_table_translations
|
||
self.result_text_translations = tmp_text_translations
|
||
self.treatment_method_active_indices = [1]
|
||
self.form_show_in_result.each do |num, property|
|
||
v = property[:active_choice]
|
||
if v.present?
|
||
self.treatment_method_active_indices << (v - 1)
|
||
else
|
||
self.treatment_method_active_indices << 1
|
||
end
|
||
end
|
||
self.lpv_calc = get_years_settings_dict
|
||
self.generate_eval_formula
|
||
end
|
||
def reload_any_asset(path, type=nil, force_reload=false)
|
||
env = Rails.application.assets
|
||
new_env = Sprockets::Environment.new(Rails.root.to_s) do |env|
|
||
env.version = ::Rails.env
|
||
tmp_path = "#{Rails.application.config.root}/tmp/cache/assets/#{::Rails.env}"
|
||
env.cache = ::Sprockets::Cache::FileStore.new(tmp_path)
|
||
env.context_class.class_eval do
|
||
include ::Sprockets::Rails::Helper
|
||
end
|
||
end
|
||
new_env.config = env.config
|
||
stats = env.cached.instance_variable_get(:@stats)
|
||
new_path = path.sub(/\.erb$/,'')
|
||
if force_reload || (stats && stats[path]) #Need reload asset
|
||
if type.nil?
|
||
ext = File.extname(new_path)
|
||
env.mime_types.each do |t, h|
|
||
if h[:extensions].include?(ext)
|
||
type = t
|
||
break
|
||
end
|
||
end
|
||
end
|
||
if type
|
||
full_path = 'file://'+path+'?type='+type
|
||
uris = env.cached.instance_variable_get(:@uris)
|
||
keys = uris.keys.select{|k| k.include?(full_path)}
|
||
asset = new_env.load(full_path)
|
||
if keys.count != 0
|
||
keys.each do |k|
|
||
uris[k] = asset
|
||
end
|
||
end
|
||
new_path = new_path.sub(/\.[^.]+$/){|ext| '-' + asset.digest + ext}
|
||
File.binwrite(new_path, asset.to_s)
|
||
yield new_path if block_given?
|
||
end
|
||
end
|
||
end
|
||
def reload_js_asset(path, force_reload=false)
|
||
reload_any_asset(path, 'application/javascript', force_reload) do |new_path|
|
||
File.open(JSFileName, 'w+'){|f| f.write(new_path)}
|
||
end
|
||
end
|
||
def generate_eval_formula
|
||
eval_hidden_variables = "def eval_hidden_variables(result); #{self.tmp_hidden_variables_for_ruby}; end"
|
||
CancerpredictsController.module_eval(eval_hidden_variables)
|
||
eval_formula = "def eval_formula(result); #{self.tmp_lpv_ruby_code}; end"
|
||
CancerpredictsController.module_eval(eval_formula)
|
||
end
|
||
def generate_jscode
|
||
js_code = "var map_values , mapping_hash , temp_index ,temp_value , index , closest_value;\r\n"
|
||
mapping_data_from_csv = JSON.parse(self.mapping_data_from_csv) rescue {}
|
||
tmp_hash = self.form_show.values + self.form_show_in_result.values
|
||
tmp_hash.each do |property|
|
||
@variable = property[:variable]
|
||
if @variable.present?
|
||
if property[:is_num] == 1
|
||
js_code += " result['#{@variable}'] = Number(result_json['#{@variable}']);\r\n"
|
||
elsif property[:choice_fields].present?
|
||
if !(self.advance_mode)
|
||
js_code += " result['#{@variable}'] = Number(result_json['#{@variable}']);\r\n"
|
||
else
|
||
if property[:need_map_values] == 1
|
||
js_code += " map_values = #{property[:map_values]};\r\n"
|
||
js_code += " result['#{@variable}'] = map_values[Number(result_json['#{@variable}'']) - 1];\r\n"
|
||
else
|
||
if property[:revert_value] != 1
|
||
js_code += " result['#{@variable}'] = Number(result_json['#{@variable}']) - 1;\r\n"
|
||
else
|
||
js_code += " result['#{@variable}'] = (#{property[:choice_fields].length} - Number(result_json['#{@variable}']));\r\n"
|
||
end
|
||
end
|
||
end
|
||
end
|
||
if self.advance_mode && property[:cancer_predict_mapping_file].present?
|
||
if (mapping_data_from_csv != {} && !mapping_data_from_csv[@variable].blank?)
|
||
js_code += " mapping_hash = mapping_data_from_csv['#{@variable}'];\r\n"
|
||
js_code += " temp_index = 0;\r\n"
|
||
js_code += " temp_value = result['#{@variable}'];\r\n"
|
||
js_code += " index = 0;
|
||
$.each(mapping_hash,function(k,v){
|
||
if( index == 0 ){
|
||
var index_val = v.indexOf(temp_value);
|
||
if( index_val != -1 ){
|
||
temp_index = index_val;
|
||
}else{
|
||
closest_value = v.get_nearest_value(temp_value);
|
||
temp_index = v.indexOf(closest_value)
|
||
}
|
||
}
|
||
result[k] = v[temp_index];
|
||
index++;
|
||
});\r\n"
|
||
end
|
||
end
|
||
end
|
||
end
|
||
js_code += "\n Object.keys(result).forEach(function(k){
|
||
if(Number.isNaN(result[k])){
|
||
result[k] = 0;
|
||
}
|
||
})"
|
||
js_code += "\n #{self.tmp_hidden_variables_for_js}"
|
||
formula = text_to_math(self.prediction_formula)
|
||
self.all_variables.each do |k|
|
||
formula = formula.gsub(/(\A|[^\w])#{k}($|[^\w])/){|f| "#{$1}result[\"#{k.strip}\"]#{$2}" }
|
||
end
|
||
formula_variables = self.tmp_lpv_variables.map{|v| v}
|
||
js_code = "\n function calculate_first_lpv(result_json){
|
||
result = {};
|
||
#{js_code}
|
||
try{
|
||
#{formula.gsub(/\s{2,10}/," ").gsub("\n","\n ")}
|
||
}catch(e){console.log(e)};
|
||
result['lpv_variable'] = {};
|
||
#{formula_variables.map{|v| "result['lpv_variable']['#{v}'] = #{v};"}.join("\n ") }
|
||
result['lpv'] = #{formula_variables.count == 0 ? 0 : formula_variables.last};
|
||
result['lpv_variable']['lpv'] = result['lpv'];
|
||
return result;
|
||
};
|
||
function calculate_and_change_result_value(obj){
|
||
obj.servive_ratio_arr = [];
|
||
for(var i = 0;i<obj.active_treatment.length;i++){
|
||
var servive_ratio = round(calculate_servive_ratio(obj.year,obj.lpv_real[i])*100,2);
|
||
var benefit = servive_ratio - obj.servive_ratio_arr[obj.servive_ratio_arr.length-1];
|
||
obj.servive_ratio_arr.push(servive_ratio);
|
||
$('tr.'+obj.active_treatment[i]+' td.Overall_Survival').html(servive_ratio+'%');
|
||
$('.'+obj.active_treatment[i]+'.Overall_Survival').html(Math.round(servive_ratio));
|
||
if(i != 0){
|
||
$('tr.'+obj.active_treatment[i]+' td.Additional_Benefit').html(round(benefit,2)+'%');
|
||
$('.'+obj.active_treatment[i]+'.Additional_Benefit').html(Math.round(benefit));
|
||
}
|
||
}
|
||
//$('.'+obj.active_treatment[0]+'.Overall_Survival').html(Math.round(obj.servive_ratio_arr[0]));
|
||
};"
|
||
@years = self.years
|
||
switch_texts = "
|
||
#{formula_variables.map{|v| "var #{v} = obj['#{v}'];"}.join("\n ")}
|
||
switch(year) {"
|
||
@years.each do |year|
|
||
year_index = @years.index(year)
|
||
switch_texts +=
|
||
"
|
||
case '#{year}':
|
||
servive_ratio = #{text_to_math(self.years_settings[year_index])};
|
||
break;"
|
||
end
|
||
switch_texts += "
|
||
default:
|
||
console.log('not found year.');
|
||
}"
|
||
js_code = js_code +"
|
||
|
||
function calculate_servive_ratio(year,obj){
|
||
var servive_ratio;#{switch_texts}
|
||
return servive_ratio;
|
||
}
|
||
"
|
||
return js_code
|
||
end
|
||
def text_to_math(text)
|
||
text.gsub("\r\n","\n").gsub('^','**').gsub('exp','Math.exp').gsub('log','Math.log')
|
||
end
|
||
def replace_str_with_idx(org_str,st, ed, replace_str)
|
||
org_str.slice!(st, ed - st + 1)
|
||
org_str.insert(st, replace_str)
|
||
org_str
|
||
end
|
||
def auto_write_predict_js(force_reload=true)
|
||
js_codes = generate_jscode
|
||
module_app_path = Pathname.new(File.expand_path(__dir__)).dirname.dirname.to_s
|
||
save_path = module_app_path + '/app/assets/javascripts/cancer_predict.js'
|
||
file_texts = File.read(save_path)
|
||
need_write = false
|
||
str1 = "/* auto add start */"
|
||
index1 = file_texts.index(str1)
|
||
str2 = "/* auto add end */"
|
||
index2 = file_texts.index(str2)
|
||
if (!index1.nil? && !index2.nil?)
|
||
file_texts = replace_str_with_idx(file_texts, index1 + str1.length, index2 - 1, js_codes)
|
||
need_write = true
|
||
end
|
||
str3 = "/*lpv_calc_formula_start*/"
|
||
index3 = file_texts.index(str3)
|
||
str4 = "/*lpv_calc_formula_end*/"
|
||
index4 = file_texts.index(str4)
|
||
if (!index3.nil? && !index4.nil?)
|
||
file_texts = replace_str_with_idx(file_texts, index3 + str3.length, index4 - 1, self.lpv_calc.to_json.gsub("@",".") + ';')
|
||
need_write = true
|
||
end
|
||
tmp_disable_jscodes = ""
|
||
str5 = "/*disable_condition start*/"
|
||
index5 = file_texts.index(str5)
|
||
str6 = "/*disable_condition end*/"
|
||
index6 = file_texts.index(str6)
|
||
self.form_show_in_result.each do |num,property|
|
||
if property[:disable_condition].present?
|
||
tmp = property[:disable_condition].clone
|
||
self.all_variables.each do |k|
|
||
tmp = tmp.gsub(/(\A|[^\w])#{k}($|[^\w])/){|f| "#{$1}post_json[\"#{k}\"]#{$2}" }
|
||
end
|
||
variable = property[:variable]
|
||
tmp_disable_jscodes += "\n if(#{tmp}){
|
||
$('##{variable} .cancer_table_btn').attr('disabled','disabled');
|
||
$('[for=\"#{variable}\"]').css('color','rgb(204, 204, 204)');
|
||
}else{
|
||
$('##{variable} .cancer_table_btn').removeAttr('disabled');
|
||
$('[for=\"#{variable}\"]').css('color','');
|
||
}"
|
||
end
|
||
end
|
||
if (!index5.nil? && !index6.nil?)
|
||
tmp_disable_jscodes += "\n\t\t\t"
|
||
file_texts = replace_str_with_idx(file_texts, index5 + str5.length, index6 - 1, tmp_disable_jscodes)
|
||
need_write = true
|
||
end
|
||
str7 = "/*therapy_lpv start*/"
|
||
index7 = file_texts.index(str7)
|
||
str8 = "/*therapy_lpv end*/"
|
||
index8 = file_texts.index(str8)
|
||
self.therapy_lpv = [0]
|
||
self.form_show_in_result.each do |num,property|
|
||
if property[:lpv_impact].present?
|
||
self.therapy_lpv << property[:lpv_impact]
|
||
else
|
||
self.therapy_lpv << 0
|
||
end
|
||
end
|
||
if (!index7.nil? && !index8.nil?)
|
||
file_texts = replace_str_with_idx(file_texts, index7 + str7.length, index8 - 1, self.therapy_lpv.to_s + ';')
|
||
need_write = true
|
||
end
|
||
if need_write
|
||
File.write(save_path,file_texts)
|
||
reload_js_asset(save_path, force_reload)
|
||
elsif !(File.exist?(JSFileName))
|
||
File.open(JSFileName, 'w+'){|f| f.write(save_path)}
|
||
end
|
||
end
|
||
def get_years_settings_dict
|
||
lpv_variable_name = (prediction_formula.include?("=") ? prediction_formula.split("=")[0].strip : "" rescue "")
|
||
res = self.years.map.with_index do |y, i|
|
||
tmp_formula = self.tmp_years_settings[i]
|
||
if lpv_variable_name.present?
|
||
tmp_formula = tmp_formula.gsub(lpv_variable_name, "lpv_current")
|
||
else
|
||
tmp_formula = tmp_formula.gsub("lpv", "lpv_current")
|
||
end
|
||
[y.to_s.sub(".","@"), tmp_formula]
|
||
end
|
||
res.to_h
|
||
end
|
||
end |