Oliver Trampleasure
Oliver Trampleasure

Reputation: 3293

Output array of hashes from Ruby on Rails to chart.js

I'm having some trouble preparing data from my Ruby on Rails project for use in chart.js, when using time as a second axis.

I've looked at various other questions and managed to get very close, but am having issues with exporting the data in a format that chart.js can recognise.

Thanks for your help!


Issue

I need the data to be printed in this form:

data: [
  {"x":1567006282000,"y":145},        
  {"x":1567009767000,"y":120},
  {"x":1567009838000,"y":130}
]

But am currently getting the following:

data: [
    {"x":1567006282000,"y":145}, 
    {"x":1567009767000,"y":120}, 
    {"x":1567009838000,"y":130}
]

Current Attempt

I am creating the array as follows from within my controller, where reading_time and obs.heart_rate are integers, I think this is creating an array of hashes:

...
@hr.push ( { :x => reading_time, :y => obs.heart_rate  } )
...

I then print this in my view, converting to json so that it would in theory work with the javascript library chart.js:

...
data: <%= @hr.to_json %>,
...

Pretty sure my issue is somewhere in the two lines above, but the full code is below in case it is needed.


Full Code

This is how I am creating (what I think) is an array of hashes within my controller:

def chart 

    # Load observations for specific patient
    @observations = Observation.where(:patient_id => params[:patient_id]);

    # Prep arrays
    @readings = []
    @hr = []

    # Cycle through all observations for this patient
    @observations.each do |obs| 

        # Convert created time to integer
        # Multiple by 1000 as chart.js expects milliseconds while ruby uses seconds from UNIX epoch
        reading_time = obs.created_at.to_i * 1000

        # Add time to array so we can use this for the labels
        @readings.push(reading_time)

        # Create hash of time and observation value
        hr_temp = {:x => reading_time , :y => obs.heart_rate }

        # Push hash to the array
        @hr.push( hr_temp )

        # Repeat for other obserations - blood pressure, oxygen sats, etc

    end

end

And finally how I am then printing that within my view:

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js" integrity="sha256-xKeoJ50pzbUGkpQxDYHD7o7hxe0LaOGeguUidbq6vis=" crossorigin="anonymous"></script>

<canvas id="myChart" width="400" height="400"></canvas>
<script>

var ctx = document.getElementById('myChart').getContext('2d');
var scatterChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: <%= @readings %>,
        datasets: [{
            label: 'Heart Rate',
            data: <%= @hr.to_json %>,
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            xAxes: [{
                type: 'time',
                time: {
                    parser: 'X', // parse x values as unix timestamp
                    tooltipFormat: 'MMM Do, \'YY'
                },
            }]
        }
    }
});
</script>

Working Example

This is a working hard coded example showing what I am aiming for.

var ctx = document.getElementById('myChart').getContext('2d');
var scatterChart = new Chart(ctx, {
    type: 'line',
    data: {
        datasets: [{
            label: 'Heart Rate',
            data: [
              {"x":1567006282000,"y":145},        
              {"x":1567009767000,"y":120},
              {"x":1567009838000,"y":130}
            ]
        }]
    },
    options: {
        scales: {
		xAxes: [{
			type: 'time',
			time: {
				parser: 'X', // parse x values as unix timestamp
				tooltipFormat: 'MMM Do, \'YY'
			},
		}]
	}
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js" integrity="sha256-xKeoJ50pzbUGkpQxDYHD7o7hxe0LaOGeguUidbq6vis=" crossorigin="anonymous"></script>

<canvas id="myChart" width="400" height="400"></canvas>

Upvotes: 1

Views: 551

Answers (1)

Minato
Minato

Reputation: 4533

Due to rendering, which uses to_s under the hood which could cause some encoding issues while rendering from a string type object. You should try using using html_safe method on the object returned by @hr.to_json like @hr.to_json.html_safe

Upvotes: 2

Related Questions