<!-- https://www.createwithdata.com/chartjs-and-csv/ --> <!-- https://towardsdatascience.com/4-ways-to-improve-your-plotly-graphs-517c75947f7e --> <?php $selected_csv = $branch = 'dev'; $season = 'NNBAR2021'; $url = "https://cmd.inp.nsk.su/~compton/gitlist/compton_tables/raw/".$branch."/tables/".$season."/"; $url_total_info = "https://cmd.inp.nsk.su/~compton/gitlist/compton_tables/raw/".$branch."/tables/".$season.".csv"; $text = file_get_contents($url); $arrays = explode("\n", $text); $cleanArrs = array_filter($arrays, function($value) { return end(explode('.', $value)) == "csv"; }); function isSelected($a, $b){ if ($a==$b){ return "selected"; } return ""; } $selected_csv = isset($_GET["csv_file"]) ? $_GET["csv_file"] : reset($cleanArrs); ?> <html> <head> <!--<script src="plotly-2.11.1.min.js"></script> --> <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="main.css"> <title>Compton interactive plots</title> <!-- <script src="chart.js"></script> --> </head> <body> <div id="gd" style="height: max(80vh, 600px); padding-bottom: 20px;"></div> <form name="form" action="" method="get"> <p style="text-align: center;">Select energy point:</p> <select name="csv_file" class="select-css" onchange="this.form.submit()"> <? foreach($cleanArrs as $file){ ?><option value="<?echo $file?>" <?echo isSelected($file, $selected_csv)?>><?echo $file?></option> <? } ?> </select> </form> <script> function makeplot(){ Plotly.d3.csv('<?echo $url_total_info;?>', (allRows)=>{ const {mean_energy, mean_spread} = parseResultsTable(allRows, <?echo reset(explode('_', $selected_csv));?>); Plotly.d3.csv('<?echo $url.$selected_csv;?>', function(data){processData(data, mean_energy, mean_spread)}); } ); } function parseResultsTable(allRows, energy_point){ // Extracts a row following the energy point in the total csv file (or null if energy point is not exists) for (var i=0; i<allRows.length; i++){ if (allRows[i].energy_point == energy_point ){ return allRows[i]; } } return null; } function parseRow(row){ // Parses a row from the detailed csv file row['start_time'] = Date.parse(row['compton_start']); row['stop_time'] = Date.parse(row['compton_stop']); row['center_time'] = new Date((row['start_time'] + row['stop_time'])/2); row['timedelta'] = (row['stop_time'] - row['start_time'])/2/1000; // in seconds text_str = "<b>Compton</b><br>" + "<i>Start: </i>" + row['compton_start'] + "<br><i>Stop: </i>" + row['compton_stop'] + "<br><br>"; row['text_str'] = text_str + "<b>Runs: </b>" + row['run_first'] + " - " + row['run_last'] + "<br><br>"; return row; } function processSpread(data, elementId, mean_value){ let x = [], y = [], std_y = [] for (var i=0; i<data.length; i++){ const {center_time, spread_mean, spread_std} = parseRow(data[i]); x.push(center_time); y.push(spread_mean); std_y.push(spread_std); } makeSpreadPlot(elementId, x, y, std_y, mean_value); } function kde(x, y, w) { const ts = (t) => t.getTime()/1000; const toDateTime = (secs) => { let t = new Date(0); t.setSeconds(secs); return t; }; const steps = 1000; const dt = (ts(x[x.length - 1]) - ts(x[0]))/steps; const kernel = (x, x0, w0, y0) => { if (Math.abs(x-x0)>w0){ return 0; } return y0/w0; //return y0*3*(1-((x-x0)/w0/2)**2)/4; }; const get_est = (timestamp) => { let val = 0 for (var i=0; i<x.length; i++){ val += kernel(timestamp, ts(x[i]), w[i], y[i]); } return val; }; //console.log(x, y); const timestamp_arr = Plotly.d3.range(steps).map(function(i){return ts(x[0])+i*dt;}); let kdex = []; let kdey = []; for (var j=0; j<timestamp_arr.length; j++){ kdex.push(toDateTime(timestamp_arr[j])); kdey.push(get_est(timestamp_arr[j])); } //console.log(kdex, kdey); return [kdex, kdey] } function oldAverage(E, L){ //Averager by the old method with E and L only if (E.length !== L.length){ return null; } let EL = 0; let sL = 0; for (let i = 0; i<E.length; i++){ EL += parseFloat(E[i])*parseFloat(L[i]); sL += parseFloat(L[i]); } return EL/sL; } function processData(allRows, mean_energy, mean_spread) { // Processes all data rows var dict = {}; dict['x'] = []; dict['e_mean'] = []; dict['e_std'] = []; dict['spread_mean'] = []; dict['spread_std'] = []; dict['compton'] = []; dict['lum'] = []; dict['twidth'] = []; for (var i=0; i<allRows.length; i++){ const row = parseRow(allRows[i]); dict['x'].push( row['center_time'] ); dict['e_mean'].push( row['e_mean'] ); dict['e_std'].push( row['e_std'] ); dict['spread_mean'].push( row['spread_mean'] ); dict['spread_std'].push( row['spread_std'] ); dict['compton'].push( row['text_str'] ); dict['lum'].push( row['luminosity'] ); dict['twidth'].push( row['timedelta'] ); } const [a, b] = kde(dict['x'], dict['lum'], dict['twidth']); dict['kdex'] = a; dict['kdey'] = b; //console.log(dict['kdex'], dict['kdey']); //oldAverage(y, dict['lum']); dict['mean_energy_total'] = mean_energy; dict['old_mean_energy_total'] = oldAverage(dict['e_mean'], dict['lum']); dict['mean_spread_total'] = mean_spread; makePlotly(dict, "gd"); } function makePlotly(dict, elementId){ const getYRange = (y, std_y) => { const ys = [...y].sort(); const std_ys = [...std_y].sort(); let idx = Math.floor(ys.length/2); const y0 = parseFloat(ys[idx]); const std0 = parseFloat(std_ys[idx]); return [y0-6*std0, y0+6*std0]; }; var trace1 = { x: dict['x'], y: dict['e_mean'], yaxis: 'y3', mode: 'markers', text: dict['compton'], hovertemplate: "%{text}<br><br>" + "<extra></extra>", hovermode: "x", error_y: { type: 'data', array: dict['e_std'], color: '#260101', }, showlegend: false, marker: { color: '#260101', }, type: "scatter", }; var trace2 = { x: dict['x'], y: dict['spread_mean'], yaxis: 'y2', mode: 'markers', text: dict['compton'], hovertemplate: "%{text}<br><br>" + "<extra></extra>", hovermode: "x", error_y: { type: 'data', array: dict['spread_std'], color: '#260101', }, showlegend: false, marker: { color: '#260101', }, type: "scatter", }; var trace3 = { x: dict['kdex'], y: dict['kdey'], hovertemplate: "%{y}<br><br>" + "<extra></extra>", hovermode: "x", showlegend: false, marker: { color: '#F23030', }, line: { shape: 'hvh', }, type: "scatter", }; var traces = [trace1, trace2, trace3]; var updatemenus = []; if (dict['mean_energy_total']){ updatemenus = [{ buttons: [ { args:[{'shapes[0].visible': true, 'shapes[1].visible': false, 'title': 'Mean energy: ' + parseFloat(dict['mean_energy_total']).toFixed(3) + ' MeV',}], label: 'Current average method', method: 'relayout' }, { args:[{'shapes[0].visible': false, 'shapes[1].visible': true, 'title': 'Mean energy: ' + dict['old_mean_energy_total'].toFixed(3) + ' MeV',}], label: 'Former average method', method: 'relayout' }, ], direction: 'center', showactive: 'true', type: 'dropdown', y: 1.1, xanchor: 'left', yanchor: 'top', active: 0, }]; } var layout = { title: 'Mean energy: ' + dict['mean_energy_total'] + ' MeV', updatemenus: updatemenus, font: { size: 18, }, xaxis: { title: "Time, NSK", automargin: true, }, yaxis3: { domain: [0.6, 1], title: "Mean energy, MeV", automargin: true, //showspikes: true, //spikemode: "across", //spikesnap: "data", }, yaxis2: { domain: [0.3, 0.5], title: "Spread, MeV", autorange: false, range: getYRange(dict['spread_mean'], dict['spread_std']), //showspikes: true, //spikemode: "across", //spikesnap: "data", }, yaxis: { domain: [0, 0.2], automargin: true, zeroline: true, rangemode: 'positive', title: "L, nb<sup>-1</sup>/s", hoverformat: '.2f', }, paper_bgcolor: 'rgba(0,0,0,0)', plot_bgcolor: 'rgba(0,0,0,0)', autosize: true, }; if (dict['mean_energy_total']){ layout['shapes'] = [{ type: 'line', yref: 'y3', xref: 'paper', x0: 0, x1: 1, y0: dict['mean_energy_total'], y1: dict['mean_energy_total'], line: { color: '#590A0A', }, }, { type: 'line', yref: 'y3', xref: 'paper', x0: 0, x1: 1, y0: dict['old_mean_energy_total'], y1: dict['old_mean_energy_total'], line: { color: '#590A0A', }, visible: false, }]; } Plotly.newPlot('gd', traces, layout, {modeBarButtonsToRemove: ['toImage'], responsive: true,}); } makeplot(); </script> </body> </html>