0
0

plots.php 12 KB

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