init.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. <!-- https://www.createwithdata.com/chartjs-and-csv/ -->
  2. <!-- https://towardsdatascience.com/4-ways-to-improve-your-plotly-graphs-517c75947f7e -->
  3. <?php
  4. $branch = 'dev';
  5. function getsmth($branch){
  6. $url = "https://cmd.inp.nsk.su/~compton/gitlist/compton_tables/raw/".$branch."/tables/";
  7. $text = file_get_contents($url);
  8. $arrays = explode("\n", $text);
  9. $clean_arrs = array_filter($arrays, function($value){
  10. $temp_arr = explode('/', $value);
  11. return preg_match("/[A-Z]+[0-9]+\//", $value);
  12. });
  13. foreach($clean_arrs as &$val){
  14. $val = substr($val, 0, -1);
  15. }
  16. return $clean_arrs;
  17. }
  18. $availableSeasons = getsmth($branch);
  19. $season = isset($_GET["season"])&&in_array($_GET["season"], $availableSeasons) ? $_GET["season"] : reset($availableSeasons);
  20. $url = "https://cmd.inp.nsk.su/~compton/gitlist/compton_tables/raw/".$branch."/tables/".$season."/";
  21. $url_total_info = "https://cmd.inp.nsk.su/~compton/gitlist/compton_tables/raw/".$branch."/tables/".$season.".csv";
  22. $text = file_get_contents($url);
  23. $arrays = explode("\n", $text);
  24. $cleanArrs = array_filter($arrays, function($value) {
  25. return end(explode('.', $value)) == "csv";
  26. });
  27. function isSelected($a, $b){
  28. if ($a==$b){
  29. return "selected";
  30. }
  31. return "";
  32. }
  33. $selected_csv = isset($_GET["csv_file"])&&in_array($_GET["csv_file"], $cleanArrs) ? $_GET["csv_file"] : reset($cleanArrs);
  34. ?>
  35. <html>
  36. <head>
  37. <script src="plotly-latest.min.js"></script>
  38. <!-- <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> -->
  39. <meta name="viewport" content="width=device-width, initial-scale=1">
  40. <link rel="stylesheet" href="main.css">
  41. <title>Compton interactive plots</title>
  42. <!-- <script src="chart.js"></script> -->
  43. </head>
  44. <body>
  45. <div id="gd" style="height: max(80vh, 600px); padding-bottom: 20px;"></div>
  46. <form name="form" action="" method="get">
  47. <p style="text-align: center;">Select energy point:</p>
  48. <div style="margin: 0 auto; display: flex; justify-content: center;">
  49. <select name="season" class="select-css" style="margin: 0;" onchange="this.form.submit()">
  50. <? foreach($availableSeasons as $s){ ?>
  51. <option value="<?echo $s?>" <?echo isSelected($s, $season)?>><?echo $s?></option>
  52. <? } ?>
  53. </select>
  54. <select name="csv_file" class="select-css" style="margin: 0;" onchange="this.form.submit()">
  55. <? foreach($cleanArrs as $file){ ?>
  56. <option value="<?echo $file?>" <?echo isSelected($file, $selected_csv)?>><?echo $file?></option>
  57. <? } ?>
  58. </select>
  59. </div>
  60. </form>
  61. <script>
  62. function makeplot(){
  63. Plotly.d3.csv('<?echo $url_total_info;?>', (allRows)=>{
  64. const {mean_energy, mean_spread, mean_energy_stat_err} = parseResultsTable(allRows, "<?echo $selected_csv;?>");
  65. Plotly.d3.csv('<?echo $url.$selected_csv;?>', function(data){processData(data, mean_energy, mean_spread, mean_energy_stat_err)});
  66. }
  67. );
  68. }
  69. function parseResultsTable(allRows, energy_point){
  70. // Extracts a row following the energy point in the total csv file (or null if energy point is not exists)
  71. data = energy_point.slice(0, -4).split('_');
  72. for (var i=0; i<allRows.length; i++){
  73. if (allRows[i].first_run == data[1] ){
  74. return allRows[i];
  75. }
  76. }
  77. return null;
  78. }
  79. function parseRow(row){
  80. // Parses a row from the detailed csv file
  81. row['start_time'] = Date.parse(row['compton_start']);
  82. row['stop_time'] = Date.parse(row['compton_stop']);
  83. row['center_time'] = new Date((row['start_time'] + row['stop_time'])/2);
  84. row['timedelta'] = (row['stop_time'] - row['start_time'])/2/1000; // in seconds
  85. text_energy = "E = " + parseFloat(row['e_mean']).toFixed(2) + "±" + parseFloat(row['e_std']).toFixed(2) + " MeV<br>";
  86. text_spread = "spread = " + parseFloat(row['spread_mean']).toFixed(2) + "±" + parseFloat(row['spread_std']).toFixed(2) + " MeV<br>";
  87. text_str = text_energy + text_spread + "<b>Compton</b><br>" + "<i>Start: </i>" +
  88. row['compton_start'] + "<br><i>Stop: </i>" + row['compton_stop'] + "<br><br>";
  89. row['text_str'] = text_str + "<b>Runs: </b>" + row['run_first'] + " - " + row['run_last'] + "<br><br>";
  90. return row;
  91. }
  92. function processSpread(data, elementId, mean_value){
  93. let x = [], y = [], std_y = []
  94. for (var i=0; i<data.length; i++){
  95. const {center_time, spread_mean, spread_std} = parseRow(data[i]);
  96. x.push(center_time);
  97. y.push(spread_mean);
  98. std_y.push(spread_std);
  99. }
  100. makeSpreadPlot(elementId, x, y, std_y, mean_value);
  101. }
  102. function kde(x, y, w) {
  103. const ts = (t) => t.getTime()/1000;
  104. const toDateTime = (secs) => {
  105. let t = new Date(0);
  106. t.setSeconds(secs);
  107. return t;
  108. };
  109. const steps = 1000;
  110. const dt = (ts(x[x.length - 1]) - ts(x[0]))/steps;
  111. const kernel = (x, x0, w0, y0) => {
  112. if (Math.abs(x-x0)>w0){
  113. return 0;
  114. }
  115. return y0/w0;
  116. //return y0*3*(1-((x-x0)/w0/2)**2)/4;
  117. };
  118. const get_est = (timestamp) => {
  119. let val = 0
  120. for (var i=0; i<x.length; i++){
  121. val += kernel(timestamp, ts(x[i]), w[i], y[i]);
  122. }
  123. return val;
  124. };
  125. //console.log(x, y);
  126. const timestamp_arr = Plotly.d3.range(steps).map(function(i){return ts(x[0])+i*dt;});
  127. let kdex = [];
  128. let kdey = [];
  129. for (var j=0; j<timestamp_arr.length; j++){
  130. kdex.push(toDateTime(timestamp_arr[j]));
  131. kdey.push(get_est(timestamp_arr[j]));
  132. }
  133. //console.log(kdex, kdey);
  134. return [kdex, kdey]
  135. }
  136. function oldAverage(E, L){
  137. //Averager by the old method with E and L only
  138. if (E.length !== L.length){
  139. return null;
  140. }
  141. let EL = 0;
  142. let sL = 0;
  143. for (let i = 0; i<E.length; i++){
  144. EL += parseFloat(E[i])*parseFloat(L[i]);
  145. sL += parseFloat(L[i]);
  146. }
  147. return EL/sL;
  148. }
  149. function processData(allRows, mean_energy, mean_spread, mean_energy_stat_err) {
  150. // Processes all data rows
  151. var dict = {};
  152. dict['x'] = [];
  153. dict['e_mean'] = [];
  154. dict['e_std'] = [];
  155. dict['spread_mean'] = [];
  156. dict['spread_std'] = [];
  157. dict['compton'] = [];
  158. dict['lum'] = [];
  159. dict['twidth'] = [];
  160. for (var i=0; i<allRows.length; i++){
  161. const row = parseRow(allRows[i]);
  162. dict['x'].push( row['center_time'] );
  163. dict['e_mean'].push( row['e_mean'] );
  164. dict['e_std'].push( row['e_std'] );
  165. dict['spread_mean'].push( row['spread_mean'] );
  166. dict['spread_std'].push( row['spread_std'] );
  167. dict['compton'].push( row['text_str'] );
  168. dict['lum'].push( row['luminosity'] );
  169. dict['twidth'].push( row['timedelta'] );
  170. }
  171. const [a, b] = kde(dict['x'], dict['lum'], dict['twidth']);
  172. dict['kdex'] = a;
  173. dict['kdey'] = b;
  174. //console.log(dict['kdex'], dict['kdey']);
  175. //oldAverage(y, dict['lum']);
  176. dict['mean_energy_total'] = mean_energy;
  177. dict['old_mean_energy_total'] = oldAverage(dict['e_mean'], dict['lum']);
  178. dict['mean_spread_total'] = mean_spread;
  179. dict['mean_energy_stat_err'] = mean_energy_stat_err;
  180. makePlotly(dict, "gd");
  181. }
  182. function makePlotly(dict, elementId){
  183. const getYRange = (y, std_y) => {
  184. const ys = [...y].sort();
  185. const std_ys = [...std_y].sort();
  186. let idx = Math.floor(ys.length/2);
  187. const y0 = parseFloat(ys[idx]);
  188. const std0 = parseFloat(std_ys[idx]);
  189. return [y0-6*std0, y0+6*std0];
  190. };
  191. var trace1 = {
  192. x: dict['x'],
  193. y: dict['e_mean'],
  194. yaxis: 'y3',
  195. mode: 'markers',
  196. text: dict['compton'],
  197. hovertemplate: "%{text}<br><br>" + "<extra></extra>",
  198. hovermode: "x",
  199. error_y: {
  200. type: 'data',
  201. array: dict['e_std'],
  202. color: '#260101',
  203. },
  204. showlegend: false,
  205. marker: {
  206. color: '#260101',
  207. },
  208. type: "scatter",
  209. };
  210. var trace2 = {
  211. x: dict['x'],
  212. y: dict['spread_mean'],
  213. yaxis: 'y2',
  214. mode: 'markers',
  215. text: dict['compton'],
  216. hovertemplate: "%{text}<br><br>" + "<extra></extra>",
  217. hovermode: "x",
  218. error_y: {
  219. type: 'data',
  220. array: dict['spread_std'],
  221. color: '#260101',
  222. },
  223. showlegend: false,
  224. marker: {
  225. color: '#260101',
  226. },
  227. type: "scatter",
  228. };
  229. var trace3 = {
  230. x: dict['kdex'],
  231. y: dict['kdey'],
  232. hovertemplate: "%{y}<br><br>" + "<extra></extra>",
  233. hovermode: "x",
  234. showlegend: false,
  235. marker: {
  236. color: '#F23030',
  237. },
  238. line: {
  239. shape: 'hvh',
  240. },
  241. type: "scatter",
  242. };
  243. var traces = [trace1, trace2, trace3];
  244. var updatemenus = [];
  245. console.log(dict);
  246. if (dict['mean_energy_total']){
  247. updatemenus = [{
  248. buttons: [
  249. {
  250. args:[{'shapes[0].visible': true, 'shapes[1].visible': false, 'title': '<E> = ' + parseFloat(dict['mean_energy_total']).toFixed(3) + '±' + parseFloat(dict['mean_energy_stat_err']).toFixed(3) + ' MeV, ' + '<Spread> = ' + parseFloat(dict['mean_spread_total']).toFixed(3) + ' MeV',}],
  251. label: 'Current average method',
  252. method: 'relayout'
  253. }, {
  254. args:[{'shapes[0].visible': false, 'shapes[1].visible': true, 'title': '<E> = ' + parseFloat(dict['old_mean_energy_total']).toFixed(3) + ' MeV, ' + '<Spread> = ' + parseFloat(dict['mean_spread_total']).toFixed(3) + ' MeV',}],
  255. label: 'Former average method',
  256. method: 'relayout'
  257. },
  258. ],
  259. direction: 'center',
  260. showactive: 'true',
  261. type: 'dropdown',
  262. y: 1.1,
  263. xanchor: 'left',
  264. yanchor: 'top',
  265. active: 0,
  266. }];
  267. }
  268. var layout = {
  269. title: '<E> = ' + parseFloat(dict['mean_energy_total']).toFixed(3) + '±' + parseFloat(dict['mean_energy_stat_err']).toFixed(3) + ' MeV, ' + '<Spread> = ' + parseFloat(dict['mean_spread_total']).toFixed(3) + ' MeV',
  270. updatemenus: updatemenus,
  271. font: {
  272. size: 16,
  273. },
  274. xaxis: {
  275. title: "Time, NSK",
  276. automargin: true,
  277. },
  278. yaxis3: {
  279. domain: [0.6, 1],
  280. title: "Mean energy, MeV",
  281. automargin: true,
  282. //showspikes: true,
  283. //spikemode: "across",
  284. //spikesnap: "data",
  285. },
  286. yaxis2: {
  287. domain: [0.3, 0.5],
  288. title: "Spread, MeV",
  289. autorange: false,
  290. range: getYRange(dict['spread_mean'], dict['spread_std']),
  291. //showspikes: true,
  292. //spikemode: "across",
  293. //spikesnap: "data",
  294. },
  295. yaxis: {
  296. domain: [0, 0.2],
  297. automargin: true,
  298. zeroline: true,
  299. rangemode: 'positive',
  300. title: "L, nb<sup>-1</sup>/s",
  301. hoverformat: '.2f',
  302. },
  303. paper_bgcolor: 'rgba(0,0,0,0)',
  304. plot_bgcolor: 'rgba(0,0,0,0)',
  305. autosize: true,
  306. };
  307. if (dict['mean_energy_total']){
  308. layout['shapes'] = [{
  309. type: 'line',
  310. yref: 'y3',
  311. xref: 'paper',
  312. x0: 0,
  313. x1: 1,
  314. y0: dict['mean_energy_total'],
  315. y1: dict['mean_energy_total'],
  316. line: {
  317. color: '#590A0A',
  318. },
  319. },
  320. {
  321. type: 'line',
  322. yref: 'y3',
  323. xref: 'paper',
  324. x0: 0,
  325. x1: 1,
  326. y0: dict['old_mean_energy_total'],
  327. y1: dict['old_mean_energy_total'],
  328. line: {
  329. color: '#590A0A',
  330. },
  331. visible: false,
  332. },
  333. {
  334. type: 'line',
  335. yref: 'y2',
  336. xref: 'paper',
  337. x0: 0,
  338. x1: 1,
  339. y0: dict['mean_spread_total'],
  340. y1: dict['mean_spread_total'],
  341. line: {
  342. color: '#590A0A',
  343. },
  344. visible: true,
  345. }];
  346. }
  347. Plotly.newPlot('gd', traces, layout, {modeBarButtonsToRemove: ['toImage'], responsive: true,});
  348. }
  349. makeplot();
  350. </script>
  351. </body>
  352. </html>