Get array values ββin a loop in PHP
I have Array $ data composed like this:
$data[$k]['id'] = $row['iddevice'];
$data[$k]['temp_00'] = $row['temp_00'];
$data[$k]['temp_01'] = $row['temp_01'];
$data[$k]['temp_02'] = $row['temp_02'];
$data[$k]['temp_03'] = $row['temp_03'];
$data[$k]['temp_04'] = $row['temp_04'];
I only have two elements in this array, so echo count($data);
return2
I am using Morris.js to create a line chart, below is a working code example:
$(function() {
Morris.Line({
element: 'morris-area-chart',
data: [
{ y: '00h', 1:57, 2:41},
{ y: '01h', 1:62, 2:98},
{ y: '02h', 1:44, 2:43},
{ y: '03h', 1:67, 2:84},
],
xkey: 'y',
parseTime:false,
ykeys: [1,2,3],
pointSize: 2,
hideHover: 'auto',
labels: ['Capteur X', 'Capteur Y']
});
My problem is as soon as I try to use PHP to use values ββfrom mine $data
, it doesn't work, the chart doesn't load any values.
Morris.Line({
element: 'morris-area-chart',
data: [
{ y: '00h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_00'],2); $i++; }?>},
{ y: '01h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_01'],2); $i++; }?>},
{ y: '02h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_02'],2); $i++; }?>},
{ y: '03h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_03'],2); $i++; }?>},
],
For me, the algorithm is fine:
- $ i equals 0
- while is
$i
less than or equalcount($data)-1
(so 2-1 = 1, so we have to stay in the loop twice) - Display IDs and temperatures for these elements.
- Increment by
$i
one
What am I thinking or doing wrong here?
Also when I initialize $i
to one and not zero, I can get the values ββfor the second entry in my $data
Array
(I prefer to say that I am not a developer, so this code may not be the cleanest I agree)
EDIT:
-
Pastebin for
var_dump
of$data
: http://pastebin.com/dYNtLxqX -
Screenshot when using Forbs solution (diagram not loading at all):
-
The SQL query I'm using to populate the
$data
Array:select iddevice, data.ip, type, description, avg(case when hour(date) = 00 then temp end) as temp_00, avg(case when hour(date) = 01 then temp end) as temp_01, avg(case when hour(date) = 02 then temp end) as temp_02, ... avg(case when hour(date) = 22 then temp end) as temp_22, avg(case when hour(date) = 23 then temp end) as temp_23 from data, device where date >= '2017-03-20' and date < '2017-03-21' and device.ip = data.ip group by ip order by iddevice;
-
The array is filled with this request using a while loop
$results = $conn->query($sql); $k = 0; $data = array(); while ($row = $results->fetch_assoc()) { $data[$k]['temp_00'] = $row['temp_00']; $data[$k]['temp_01'] = $row['temp_01']; $data[$k]['temp_02'] = $row['temp_02']; $data[$k]['temp_03'] = $row['temp_03']; ... $k++; }
source to share
This is my suggestion for another way to do this. It cuts down on repetitive code and minimizes PHP / JS mixing.
First, create your array a little differently when you fetch the strings from your query:
while ($row = $results->fetch_assoc()) {
// Loop over each of the temp_x columns
for ($i=0; $i < 4; $i++) {
$x = str_pad($i, 2, '0', STR_PAD_LEFT);
// add the value for each temp_x to a temporary array, using time for a key
$temp = is_null($row["temp_$x"]) ? 'null' : round($row["temp_$x"], 2);
$times[$x][] = $row['iddevice'] . ':' . $temp;
}
}
Next, format the values ββof each array in a temporary array
foreach ($times as $time => $temps) {
$data[] = "{ y: '{$time}h', " . implode(', ', $temps) . '}';
}
Then convert the array $data
to string:
$data = implode(",\n", $data);
So all the PHP you need in the JS part is as follows:
Morris.Line({
element: 'morris-area-chart',
data: [ <?php echo $data ?> ]
There might be a better way to use json_encode
. If you change the code inside the loop while
that slightly fetches rows from your database:
for ($i=0; $i < 4; $i++) {
$x = str_pad($i, 2, '0', STR_PAD_LEFT);
$temp = is_null($row["temp_$x"]) ? null : round($row["temp_$x"], 2);
$times[$x]['y'] = $x.'h';
$times[$x][$row['iddevice']] = $temp;
}
Then it $data
can be formed using json_encode
. ( array_values
used to override an array with numeric indices so that it appears as an array in the JSON output instead of an object.)
$data = json_encode(array_values($times));
And in JS:
Morris.Line({
element: 'morris-area-chart',
data: <?php echo $data ?>
// note: no [] brackets around $data in this version
Whether or not this will work depends on whether it is okay for all keys to be strings, because JSON keys are strings, so you get an output like
{ "y": "01", "1": 17.62, "2": 19.52 }
instead
{ y: '01', 1: 17.62, 2: 19.52 }
I think this should probably work anyway.
source to share
You can optimize it even more.
Morris.Line({
element: 'morris-area-chart',
data: [
<?php
foreach($data as $sensor) {
foreach($sensor as $key => $value) {
if($key == 'id') {
$id = $value;
} else {
$tempTime[$key][$id] = $value;
}
}
}
$i = 0;
foreach($tempTime as $time) {
echo sprintf("{ y: '%02dh', ",$i);
foreach($time as $key => $value) {
echo sprintf("%d:%d, ",$key, round($value,2);
}
echo "},";
$i++;
}
?>
],
xkey: 'y',
parseTime:false,
ykeys: [1,2,3],
pointSize: 2,
hideHover: 'auto',
labels: ['Capteur X', 'Capteur Y']
});
This way, if your array gets large, you don't have to iterate over yourself.
Explanation
foreach
is a function that iterates through an array. The first foreach loop just reorders the array in such a way that it is easy to use in the last loop foreach
(you would do that when you first create the array from sql, but I could not figure out how you did it from my post) The last loop foreach
just prints out the lines needed for the function Morris.line()
. Hope this makes sense.
source to share