0

I am currently using Flask and Chart.js to generate graphics. Basically I have a database (sqlite) that stores the times obtained in swimming competitions. The times are in format "HH:MM:SS.SSS" For example, in the 50 meters freestyle I have no problem since the times are in "SS.SS" format (example 26.94) and I can generate the graph in Flask with Chart.js because I can convert 26.94 into a number and get a graph with x-axis for months, and y-axis for the times (such as 26.94). However, in the case of times like "00:08:23.78" I need to graph that time on the y-axis with respect to the months on the x-axis in which the time was reached. I still can't imagine the solution with Chart.js. Any guide would be very grateful.enter image description here The source code section in Flask and Python that generates the graph is as follows:

@app.route("/simple_chart")
def chart():
legend = 'Monthly performance at 50m Freestyle'
labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dic"]

values = [26.94, 26.70, 26.80, 27.40, 26.45, 26.43, 26.30, 26.25, 26.20, 26.35, 26.00, 25.00]
return render_template('chart.html', values=values, labels=labels, legend=legend)

The source code of the chart.html file is as follows:

 <!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="utf-8" />
 <title>Chart.js Example</title>
 <!-- import plugin script -->
 <script src='static/Chart.min.js'></script>
 </head>
 <body>
   <h1>50 m. Free Style</h1>
   <!-- bar chart canvas element -->
   <canvas id="myChart" width="600" height="400"></canvas>
   <p id="caption">Data obtained from swimming competitions.</p>

   <script>
     // Global parameters:
     // do not resize the chart canvas when its container does (keep at 600x400px)
     Chart.defaults.global.responsive = false;

     // define the chart data
     var chartData = {
       labels : [{% for item in labels %}
                  "{{item}}",
                 {% endfor %}],
       datasets : [{
        label: '{{ legend }}',
        fill: true,
        lineTension: 0.1,
        backgroundColor: "rgba(75,192,192,0.4)",
        borderColor: "rgba(75,192,192,1)",
        borderCapStyle: 'butt',
        borderDash: [],
        borderDashOffset: 0.0,
        borderJoinStyle: 'miter',
        pointBorderColor: "rgba(75,192,192,1)",
        pointBackgroundColor: "#fff",
        pointBorderWidth: 1,
        pointHoverRadius: 5,
        pointHoverBackgroundColor: "rgba(75,192,192,1)",
        pointHoverBorderColor: "rgba(220,220,220,1)",
        pointHoverBorderWidth: 2,
        pointRadius: 1,
        pointHitRadius: 10,
        data : [{% for item in values %}
                  {{item}},
                {% endfor %}],
        spanGaps: false
       }]
     }

     // get chart canvas
     var ctx = document.getElementById("myChart").getContext("2d");

     // create the chart using the chart canvas
     var myChart = new Chart(ctx, {
       type: 'line',
       data: chartData,
     });
   </script>

 </body>

Ramiro
  • 369
  • 3
  • 14
  • Looks like chart.js supports plotting with dates and times. (https://www.chartjs.org/docs/latest/axes/cartesian/time.html) – noslenkwah Feb 25 '20 at 22:17
  • Can't you convert the minutes to seconds and record them as a number too? For example 00:08:23.78 > 503.78 [8*60+23.78]. You can write a function to do just that. Is there any issue with doing that? – Thaer A Feb 26 '20 at 00:07
  • @noslenkwah - Thanks noslenkwah for guiding me to the chart.js documentation. I have looked closely at the documentation for chart.js and reviewed some implementations on stackoverflow. Finally I have managed to graph the chart as I wanted. I will include the implementation of the code in case it is useful for someone with a similar requirement. – Ramiro Sep 20 '20 at 06:33

1 Answers1

1

Attached is a screenshot of the chart that shows the progression of the records reached in the Women's 800m Freestyle.

enter image description here

The source code includes comments in the most appropriate blocks to clarify the implementation when necessary.

<!DOCTYPE html>

<html>

  <head>
  <meta charset="utf-8" />
  <title></title>
  <link rel="stylesheet" href="/static/style.css" />
  <script data-require="jquery" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script src="https://npmcdn.com/moment@2.14.1"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script> 
    
  <script>
      $(function(){
            const ctx = document.getElementById('myChart').getContext('2d'); 
        
            let years = [
                          "1978", 
                          "1978", 
                          "1987", 
                          "1987", 
                          "1988", 
                          "1989",
                          "2008", 
                          "2013",
                          "2014",
                          "2015",
                          "2016",
                          "2016"
            ];
        
            let times = [
                          "00:08:30.53", 
                          "00:08:24.62", 
                          "00:08:22.44", 
                          "00:08:19.53", 
                          "00:08:17.12", 
                          "00:08:16.22", 
                          "00:08:14.10", 
                          "00:08:13.86",
                          "00:08:11.00",
                          "00:08:07.39",
                          "00:08:06.68",
                          "00:08:04.79"
            ];
        
            let data = years.map((year, index) => ({
              x: moment(`${year}-01-01`), 
              y: moment(`1970-02-01 ${times[index]}`).valueOf()
            }));
        
            let bckColors = [
              "#66FF00", // Bright Green 
              "#1974D2", // Bright Navy Blue 
              "#08E8DE", // Bright Turquoise 
              "#FFF000", // Yellow Rose 
              "#FFAA1D", // Bright Yellow (Crayola)
              "#FF007F", // Bright Pink
              "#91aaff", 
              "#ff9e9e", 
              "#ff80c5", 
              "#7afbff",
              "#8aff9c",
              "#edc065"
            ];
        
            let myChart = new Chart(ctx, {
              type: 'line',
              data: {
              datasets: [{
                      label: "Time progression in the 800m. freestyle Women",
                      // SEE: https://encycolorpedia.com/
                      // to assign rgba() colors
                      // 'backgroundColor' fill color of the area under the curve that joins the points
                      backgroundColor: 'rgba(17, 67, 116, 0.6)',  // Sailboat Blue 0.6 reduce opacity
                                                                  // To reduce opacity SEE: https://stackoverflow.com/questions/45104743/draw-two-plots-using-chartjs-over-one-another-with-transparency
                      // 'borderColor' color of the line connecting the points
                      borderColor: 'rgba(254, 254, 250, 1.0)', // Baby Powder
                      pointBackgroundColor: bckColors,
                      data: data,
                      pointBorderWidth: 2,
                      pointRadius: 5,
                      pointHoverRadius: 7
                      
              }]
             },

             options:{
                 legend:{
                     labels:{
                         fontFamily:'Courier',
                         fontColor: 'black',
                         fontSize: 18
                     }
                 },
                 scales: {
                     xAxes:[{
                         type: 'time',
                         position: 'bottom',
                         time:{
                             displayFormats: {
                                 years: 'YYYY'
                             },
                          
                             unit: 'year'
                         },

                         ticks: {
                             fontFamily:'Courier',
                             fontColor: 'black',
                             fontSize: 12,
                             // Display the labels in x-Axis 
                             // jumping from three years to three years
                            
                             // SEE:https://stackoverflow.com/questions/61847921/chart-js-how-i-change-the-x-axes-ticks-labels-alignment-in-any-sizes
                             autoSkip: true,
                             autoSkipPadding: 75,
                         },
                                                
                         scaleLabel:{ 
                             // x-axis label
                             fontFamily:'Courier',
                             fontColor: 'black',
                             fontSize: 14,
                             display: true,
                             labelString: 'Year'
                         }
                     }],

                     yAxes:[{
                         type: 'linear',
                         position: 'left',
                         ticks:{
                             fontFamily:'Courier',
                             fontColor: 'black',
                             fontSize: 12,
                             // fix y-Axis time interval. 
                             // This interval must go from (mm:ss.SS)
                             // "00:00.00" to (mm:ss.SS) "10:00.00"
                             min: moment('1970-02-01 00:08:00.00').valueOf(),
                             max: moment('1970-02-01 00:08:31.00').valueOf(),                                                          
                                                        
                             beginAtZero:false,

                             callback: value => {
                                 let date = moment(value);                                           
                                                              
                                 if(date.diff(moment('1970-02-01 00:10:00.00'), 'seconds') === 0) {
                                                                                                                                              
                                     return null;
                                 }                                                                               
                                                                            
                             // SEE: https://flaviocopes.com/momentjs/                                               
                             // Moment provides a constant
                             // 'HTML5_FMT.TIME_MS'
                             // to format date as HH:mm:ss.SSS 
                             // Example: 16:34:10.234 
                                                                            
                                return moment(date,'HTML5_FMT.TIME_MS').format('mm:ss.SS')
                             }
                          },
                          scaleLabel:{ 
                              // y-axis label
                              fontFamily:'Courier',
                              fontColor: 'black',
                              fontSize: 14,
                              display: true,
                              labelString: 'Time'
                          }
                     }]
                 },
              
                 tooltips:{ 
                     callbacks:{
                         title: function(tooltipItems, data) {
                             // Return value for title (xlabel)
                             // SEE: callback function to change 
                             // title of tooltip (tooltipItems[0].xLabel)
                             // https://stackoverflow.com/questions/38819171/chart-js-2-0-how-to-change-title-of-tooltip
                                                                        
                                                                        
                             // SEE: https://flaviocopes.com/momentjs/
                             // Moment provides the functions to format
                             // tooltipItems[0].xLabel (Date) to 'YYYY' Example: 2016
                                                                        
                             return moment(tooltipItems[0].xLabel).format("YYYY")
                         },

                         label: function(tooltipItem, data) {
                             // Return value for (yLabel)
                             // SEE: callback function to convert timestamp (tooltipItem.yLabel) to mm:ss.SS
                             // https://stackoverflow.com/questions/19485353/function-to-convert-timestamp-to-human-date-in-javascript/34900794
                                                                        
                             return ' Time : ' + moment(tooltipItem.yLabel).format("mm:ss.SS")
                         },

                 }
            }
          }
        });
      });
   </script>
   </head>

   <body>
       <div class = "container">
           <canvas style = "background-color: grey;" id="myChart"></canvas>
       </div>
   </body>
Ramiro
  • 369
  • 3
  • 14