Render php graph

Hi!

I'm trying to render a graph with PHP5 but so far i have been unsuccessful.

I've been trying two different ways to do this, the first was with jpgraph and the second was lavacharts.
With jpgraph i was never able to render the image, always ended up with the broken image symbol (no syntax errors reported in the log) and with lavacharts i haven't been able to render the graph.

Therefore i would appreciate some help or some new ideas of a neat way to render the graph :)

The graph will be based on data from a sqlite database.

Lavacharts code:
<?php // content="text/plain; charset=utf-8"
require('/var/www/html/vendor/autoload.php');
use Khill\Lavacharts\Lavacharts;
$lava = new Lavacharts;
$powertable = $lava->DataTable();
$powertable ->addDateColumn('Datestamp')
->addNumberColumn('power');

   class MyDB extends SQLite3
   {
      function __construct()
      {
         $this->open('/home/pi/Documents/Projects/ArduinoSerialImport/solartracker.db');
      }
   }
   $db = new MyDB();
   if(!$db){
      echo $db->lastErrorMsg();
   } else {
      echo "Opened database successfully\n";
   }

$sql =<<<EOF
SELECT voltage, current, datestamp FROM stuffToPlot;
EOF;

$voltage = array();
$current = array();
$datestamp = array();

$ret = $db->query($sql);
while ($row = $ret->fetchArray(SQLITE3_ASSOC)){
        $voltage[] = $row['voltage'];
        $current[] = $row['current'];
        $datestamp[] = $row['datestamp'];
}

$unixtimestamp = array();
foreach ($datestamp as $nebulosa){
        $unixtimestamp[] = strtotime($nebulosa);
}

$power = array();
foreach ($voltage as $key => $door){
        $power[] = $door * $current[$key];
}

$lava->AreaChart('Power over time', $powertable, [   
    'areaOpacity'        => 0.5,
    'axisTitlesPosition' => 'Hej',
    'hAxis'              => [$datestamp],   //HorizontalAxis Options
    'interpolateNulls'   => FALSE,
    'lineWidth'          => 12,
    'pointSize'          => 12,
    'vAxis'              => [$power],   //VerticalAxis Options
]);

echo $lava->render('AreaChart', 'Power over time', 'power_div')
?>

Jpgraph code:

<?php // content="text/plain; charset=utf-8"
   class MyDB extends SQLite3
   {
      function __construct()
      {
         $this->open('/home/pi/Documents/Projects/ArduinoSerialImport/solartracker.db');
      }
   }
   $db = new MyDB();
   if(!$db){
      echo $db->lastErrorMsg();
   } else {
      echo "Opened database successfully\n";
   }

$sql =<<<EOF
SELECT voltage, current, datestamp FROM stuffToPlot;
EOF;

$voltage = array();
$current = array();
$datestamp = array();

$ret = $db->query($sql);
while ($row = $ret->fetchArray(SQLITE3_ASSOC)){
        $voltage[] = $row['voltage'];
        $current[] = $row['current'];
        $datestamp[] = $row['datestamp'];
}

$unixtimestamp = array();
foreach ($datestamp as $nebulosa){
        $unixtimestamp[] = strtotime($nebulosa);
}

$power = array();
foreach ($voltage as $key => $door){
        $power[] = $door * $current[$key];
}

require_once ('/var/www/html/jpgraph/src/jpgraph.php');
require_once ('/var/www/html/jpgraph/src/jpgraph_line.php');
require_once ('/var/www/html/jpgraph/src/jpgraph_date.php');

// Create the new graph
$graph = new Graph(540,300);

// Slightly larger than normal margins at the bottom to have room for
// the x-axis labels
$graph->SetMargin(40,40,30,130);

// Fix the Y-scale to go between [0,100] and use date for the x-axis
$graph->SetScale('datlin',0,25);
$graph->title->Set("Power over time");

// Set the angle for the labels to 90 degrees
$graph->xaxis->SetLabelAngle(90);

$line = new LinePlot($power, $unixtimestamp);
$line->SetLegend('Year 2005');
$line->SetFillColor('[email protected]');
$graph->Add($line);
$graph->Stroke();


?>

Many thanks!
/JHCJ

I haven't tried those before but have you considered using a JavaScript library? If I remember correctly google has a charts library which was quite easy to use a few years back.

Lavacharts is based on the google graphs api, i just couldn't get the rendering to work.
In the documentation it says that i should render it with this code:
<?php

<div id="pop_div"></div>
// With the lava object
<?= $lava->render('AreaChart', 'Population', 'pop_div') ?>

But i can't figure out how to use it.

Which i guess leads me to learn some javascript then :)

Highly recommend using PDO instead of SQLite3.

What happened when you tried?

I have just started programming and there are some parts which i don't fully understand yet and rendering is one of them. In the documentation it says that i should create some kind of a view file but i don't understand how to connect the files together and get them "talking". The php code in the view file always results in a syntax error on line 2 <div id ="pop_div"></div> telling me that "<" is unexpected. If i run the code directly in the same script the same error occurs.

The reason for choosing a database over PDO was due to the amount of information i plan on storing. I have an Arduino shoving sensor values over serial to a raspberry pi. The pi runs a python script that saves the data in the db.
The php script is intended for visualization of some sensor data.

/J

that sounds like you're putting the <div> directly into your php code. it's not php; it's html. e.g.,

<div><?php echo "this is fine"; ?></div>

vs.

<?php <div> echo "this is a big mess of syntax errors"; </div> ?>

Yep. highly recommend you learn the language before you try to write code with it.
http://php.net

This does not make sense. PDO is a tool for accessing databases. It can use sqlite just fine, and has a much nicer api + learning curve for doing so.


If you'd like more help, I'll ask that you take the time to learn about the basics — but totally willing to help you. You'd also need to share your attempts (e.g., in a pastebin).

I really appreciate your help! I just created a paste bin account as suggested. Seems to be a neat way to post code.

I thought it was html code but I couldn't understand why there was an opening php tag. Can I write and execute php in a html file?

You are of course right about learning things properly rather than stressing through multiple as I have done now. I've been trying to get an understanding for arduino, html, python, php and Java all att the same time which is obviously stupid... Think i wanted to do a bit more than I currently was capable of. But time to change that and do things properly!

I will try to come up with some code suggestions during this weekend and once again thank you for helping me!

well, because they want to write php code at that point. But if you put the whole thing inside php tags, then it causes problems. I don't know if that's what you did; just what it sounds like based on the error.

You can put html markup in a php script, yes. you write the html outside the <?php ?> tags, and it is output as-is.

People usually describe this as "putting php in a html file," but this is wrong and more than a little misleading. If the script is executed as php, it is not a "html file." it is a php script. Describing it as a "html file" is backwards thinking and will only confuse you in the long run.

no problem!

Hi again _adrian!

It's been a while since i last posted but i think i have made some progress.

I dropped the idea to use lavacharts and went for the full google charts library which seemed more flexible. I'm currently trying to export the data to a json file which the google library later uses to draw the graph.

If you haven't given upon me totally i'd like some more help with my current code :)

You can find the new code here

I have two issues:
1. Whenever i run the script, the entire file gets overwritten which results in the date stamps being overwritten with the current time. I would only like the latest data point to get the new date stamp.
2. The $power array and its values doesn't show up in the json file, only the date stamps do. Otherwise the formatting seems to be correct.

/JHCJ

2) you're casting $power as a float on :41 (makes it 0).

1) the entire file is overwritten because… you're overwriting it. but appending would leave you with invalid json. what is the expected structure for the json?

just about everything you're doing with dates in that code confuses me. can you explain what it is you need to end up with?

I don't understand why i shouldn't use a float? The database values are float values (x.yz) and i want to keep them as decimal values.

Googles documentation can be found here as well as here

I have stolen the last bit of code since i had no idea how to do it. Found this explanation at stackoverflow.

to use an actual Date column in the JSON, gets a little tricky

primarily because month numbers in JavaScript are zero-based, unlike php

so if you format a Date in php, need to reduce the month number by 1

which makes for a lengthy format statement

to pass a date in JSON, you can use the following format, note that it is passed as a string...

"Date(2016, 8, 28, 15, 34, 40)" --> which equates to today's date
again, the month is zero-based (8 = September)

so to build a date in this format in php, you can use the following...

> $date1 = new DateTime();
> $date2 = "Date(".date_format($date1, 'Y').", ".((int) date_format($date1, 'm') - 1).", ".date_format($date1, 'd').", ".date_format($date1, 'H').", ".date_format($date1, 'i').", ".date_format($date1, 's').")";

Tanks for your reply!

/JHCJ

the items in the array should be floats, sure. but the array is not a float. casting the array as a float turns the array into 0 (the array is now gone).

also, datatype ≠ display format. for example, 1.0 (a float) will be displayed as "1". the solution here is not to do some weird trick in php, but to simply pass the appropriate option to json_encode (in this case, JSON_PRESERVE_ZERO_FRACTION).

see http://php.net/json_encode

to pass a date in JSON, you can use the following format, note that it is passed as a string...

to be clear, this is not "passing a date in json." json has no Date type, and this "format" is NOT a format. you're passing javascript code, and the only was this will make a date in javascript is if it is eval'd as code (which is bad; it is a deliberate security hole: json is data, NOT code).

A much, much better approach is to format the date in a format that js understands, which can then be passed to the Date constructor. If you're controlling how this data is consumed, then you should absolutely be taking this approach instead.

edit

ugh, they want it like that.
that's awful.

Found this explanation at stackoverflow

apparently, whoever wrote that "explanation" didn't know that DateTime has a format() method : p but, as noted above, simply using a date format known to js (e.g., ISO8601) is much better and is readable/usable in more situations.

i'll look at this after work or maybe tomorrow. i don't think you're getting the right structure for your json either.

Much appreciated!

To solve the array problem would a solution be just to ignore the data formatting?

/JHCJ

i looked briefly at the links you gave; it seems there is a "f" property which you should use if you want the data displayed in a specific format. I started an example earlier but work stuff pulled me away. i'll probably be able to look more tomorrow.

but in the meantime, re-read through those docs; your json structure is definitely off. you're putting all your data under cols and you're not putting column metadata at all.