I am trying to pull financial stock data of multiple companies from CSVs and display the data as separate series in a Highcharts/Highstocks line chart. I have the sources setup and I am able to pull data + convert to JSON, but I am having trouble passing the data off to Highcharts. I believe I am not using the most efficient method of preparing the data for Highcharts use, and I am hoping someone can give me direction on what I've done incorrectly. Please take a look at my code and make me aware of any inefficiencies or glaring errors you see.
PHP code:
date_default_timezone_set('America/Los_Angeles');
$stocks = array('MSFT' => 'http://ichart.finance.yahoo.com/table.csv?s=MSFT', 'AAPL' => 'http://ichart.finance.yahoo.com/table.csv?s=AAPL', 'FB' => 'http://ichart.finance.yahoo.com/table.csv?s=FB');
$stocks_data = array();
foreach ($stocks as $key=>$stock) {
$fh = fopen($stock, 'r');
$header = fgetcsv($fh);
$varname = $key . '_data';
$$varname = array();
while ($line = fgetcsv($fh)) {
${$varname}[count($$varname)] = array_combine($header, $line);
}
fclose($fh);
}
foreach($MSFT_data as $val){
$MSFT[] = strtotime($val['Date']) * 1000 . ', ' . (float)$val['Close']; //sets the date as a javascript timestamp
}
$MSFT = json_encode($MSFT);
foreach($AAPL_data as $val){
$AAPL[] = strtotime($val['Date']) * 1000 . ', ' . (float)$val['Close']; //sets the date as a javascript timestamp
}
$AAPL = json_encode($AAPL);
foreach($FB_data as $val){
$FB[] = strtotime($val['Date']) * 1000 . ', ' . (float)$val['Close']; //sets the date as a javascript timestamp
}
$FB = json_encode($FB);
JS code:
$(function () {
var seriesOptions = [],
yAxisOptions = [],
colors = Highcharts.getOptions().colors;
seriesOptions[0] = {
name: 'MSFT',
data: <? php echo $MSFT; ?>
};
seriesOptions[1] = {
name: 'AAPL',
data: <? php echo $AAPL; ?>
};
seriesOptions[2] = {
name: 'FB',
data: <? php echo $FB; ?>
};
function createChart() {
chart = new Highcharts.StockChart({
chart: {
renderTo: 'container'
},
rangeSelector: {
selected: 4
},
yAxis: {
labels: {
formatter: function () {
return (this.value > 0 ? '+' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent'
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2
},
series: seriesOptions
});
}
});
If you have any questions or need further information, please let me know with a comment.
Thanks
BTW: I have all necessary assets included for Highcharts to work; when I replace my JS + PHP with example code from the Highcharts site, it works beautifully. So the problem clearly lies in my JS + PHP code.
Alright, I believe I found the problem, it lies in the way that you are storing each individual point in the array.
Instead of this (which is passing a string x,y separated by a comma):
strtotime($val['Date']) * 1000 . ', ' . (float)$val['Close'];
You are going to want to use something like this (Highcharts accepts arrays or associative arrays):
array((strtotime($val['Date']) * 1000), ((float)$val['Close']));
That will store the X and Y variables as an array instead of comma separated string for the javascript to pass as data.
Related
This question already has answers here:
Is storing a delimited list in a database column really that bad?
(10 answers)
How to count items in comma separated list MySQL
(6 answers)
Closed 1 year ago.
I want to count the number of mechanics in a chart, but some data has multiple data which I use with implode (comma). how to separate data?
I'm taking data from one of my tables, where a column has a value that is implode. the problem here, I just want to explode **nama_tmp **(EKO PAMBUDI, MURNO, ARDI PRASETYO) separately so I can count each name.
The following query I use to display the table:
var chart4;
$(document).ready(function() {
chart4 = new Highcharts.Chart({
chart: {
renderTo: 'mygraph4',
type: 'column'
},
title: {
text: 'Grafik Mekanik'
},
xAxis: {
categories: ['Mekanik']
},
yAxis: {
title: {
text: 'Total Perbaikan'
}
},
series:
[
<?php
include "system/koneksi.php";
$sql = "SELECT nama_tmp FROM tb_tmp GROUP by nama_tmp";
$query = mysqli_query($connect, $sql) or die(mysqli_error());
while($temp = mysqli_fetch_array($query))
{
$namatmp=$temp['nama_tmp'];
$sql_total = "SELECT COUNT(nama_tmp) as 'total' from tb_tmp GROUP by nama_tmp = '$namatmp'";
$query_total = mysqli_query($connect,$sql_total) or die(mysql_error());
while($data = mysqli_fetch_array( $query_total))
{
$total = $data['total'];
}
?>
{
name: '<?php echo $namatmp; ?>',
data: [<?php echo $total; ?>]
},
<?php
} ?>
]
});
});
my database:
After looking at the image again, I can understand your problem. You basically need to prepare your data, instead of printing the PDF directly.
You could use a map to calculate your output like so:
$total = array("freq" => 0, "menit" => 0, "jam" => 0);
$groups = array();
while ($data = mysqli_fetch_array($query)) {
$names = explode(",",$data['nama_tmp']);
foreach ($names as $name) {
if (!array_key_exists($name, $groups)) {
$groups[$name] = array("freq" => 0, "menit" => 0, "jam" => 0);
}
$groups[$name]["freq"] += $data["freq"];
$groups[$name]["menit"] += $data["menit"];
$groups[$name]["jam"] += $data["jam"];
$total["freq"] += $data["freq"];
$total["menit"] += $data["menit"];
$total["jam"] += $data["jam"];
}
}
Now you should have all your data in $groups and you can generate your PDF from that.
foreach ($groups as $name => $group) {
$pdf->Ln();
$pdf->Cell(90,5,$name,1,0,'L',0);
$pdf->Cell(20,5,$group['freq'],1,0,'C',0);
$pdf->Cell(25,5,$group['menit'],1,0,'C',0);
$pdf->Cell(25,5,$group['jam'],1,0,'C',0);
}
$pdf->Ln(5);
$pdf->SetFillColor(255, 235, 255);
$pdf->SetFont('times','B',8);
$pdf->Cell(90,5,'TOTAL',1,0,'C',1);
$pdf->Cell(20,5,$total["freq"],1,0,'C',1);
$pdf->Cell(25,5,$total["menit"],1,0,'C',1);
$pdf->Cell(25,5,$total["jam"],1,0,'C',1);
Note: Instead of using a variable for every column sum, I have used a $total map array instead. This makes it more readable. Also you should consider using some functions for each part of your script.
The main function could then be as simple as this:
$data = readData();
$groups= calculateSums($data);
$pdf = generatePDF($groups);
Trying to group tow columns and and populate it as a particular series on highcharts. my code not grouping columns, And showing all data as a single series.
$query = $db->Prepare("SELECT class, SUM(marks), DATE(date_column) as
dates FROM classes GROUP BY class,DATE(date_column)");
$query->execute();
while ( $row = $query->fetch(PDO:: FETCH_ASSOC)) {
$date = $row['dates'];
$dates[] = $row['dates'];
$class[] = $row['class'];
$marks[] = $row['SUM(marks)'];
$output[] = array($date,(int)$marks);
}
echo json_encode(array('date'=>$dates,'marks'=>$marks, 'name' => $class));
JS
<script>
$(document).ready(function () {
$(function() {
$.getJSON('data.php', function(data) {
// Create the chart
Highcharts.chart('container', {
title: {
text: 'class Marks'
},
xAxis: {
categories: data.dates
},
series : [{
"name" : data.name,
"data": data.marks
}],
});
});
});
});
</script>
Table
Expected output in JSFiddle
data response
date: ["2019-02-07", "2019-02-09", "2019-02-12", "2019-02-08", "2019-02-12",
"2019-02-13", "2019-03-13",…]
marks: ["45", "166", "78", "64", "64", "627", "87", "352"]
name: ["claas 1", "claas 1", "claas 1", "class 2", "class 2", "class 2", "class 3", "class 3"]
By seeing your fiddle the expected output you want for HighCharts is as follow:
1: Category Data:
It should be an array of dates.
Make sure you remove duplicates and order them in ascending/descending order whichever you want, to see a continuous graph.
"categories":["2019-02-07", "2019-02-08", "2019-02-09", "2019-02-12", "2019-02-13", "2019-02-14"]
2: Series Data:
It would be an array of object, where each object contains two properties name and data.
Data should have n no of values if your categories array has n values and each corresponds to same index.
As we don't have data for each date for each class, we would add 0 there.
So data would look like
"series":[
{
"name":"class 1",
"data":[45,0,166,78,0,0]
},
{
"name":"class 2",
"data":[0,64,0,64,627,0]
},
{
"name":"class 3",
"data":[0,0,0,0,87,352]
}
]
Final Fiddle which can be achieved by PHP using below code:
$arrDates = [];
$arrClass = [];
$arrData = [];
while ( $row = $query->fetch(PDO:: FETCH_ASSOC)) {
$arrDates[] = $row['dates'];
$arrClass[] = $row['class'];
$arrData[$row['class'] . ':' . $row['dates']] = $row['marks']; // to identify for which date & class this marks belong to, we can directly search for index.
}
$arrDates = array_unique($arrDates);
sort($arrDates);
$arrClass = array_unique($arrClass);
// Create series data
$arrSeriesData = [];
foreach($arrClass as $strClass){
$tempArr = ['name' => $strClass];
foreach($arrDates as $strDate){
$tempArr['data'][] = isset($arrData[$strClass . ':' . $strDate]) ? intval($arrData[$strClass . ':' . $strDate]) : 0;
}
$arrSeriesData[] = $tempArr;
}
$response = ['categories' => $arrDates, 'series' => $arrSeriesData];
echo json_encode($response);
Output:
{"categories":["2019-02-07","2019-02-08","2019-02-09","2019-02-12","2019-02-13","2019-02-14"],"series":[{"name":"class 1","data":[45,0,166,78,0,0]},{"name":"class 2","data":[0,64,0,64,627,0]},{"name":"class 3","data":[0,0,0,0,87,352]}]}
Update your javascript code to reflect the above
$(document).ready(function() {
$(function() {
$.getJSON('data.php', function(data) {
// Create the chart
Highcharts.chart('container', {
title: {
text: 'class Marks'
},
xAxis: {
categories: data.categories
},
series: data.series,
});
});
});
});
I have problems to create an array which is evaluated correctly by jqplot.
If i try it like this, i have an x-axis range from -5 to 95 but with the correct line.
Actually i would expect a chart with x-axis from 0 to 30.
With firebug i can check with typeof that params is an object (array).
Where is the failure?
Here is my getPlotData.php with some dummy data:
$temp = array();
for( $i=0; $i<30; $i++ ){
$temp[] = "[" . $i . "," . ($i*5) . "]";
}
$return['line'] = "[" . implode(',', $temp . "]";
die(json_encode($return));
And here is my ajax function which is calling the createPlot-function:
$.ajax({
type: "GET",
dataType: "json",
url: "getPlotData.php?rand=" + new Date(),
data: data,
cache: false,
success: function(data) {
var params = eval(data['line']);
createPlot(params);
}
});
function createPlot(params){
plot1 = $.jqplot('plot_data', [params], {
series:[{showMarker:true}],
markerOptions: { style:'circle' },
axesDefaults:{
tickRenderer: $.jqplot.CanvasAxisTickRenderer ,
tickOptions: {
fontSize: '14px',
textColor: "#fff"
}
},
axes:{
xaxis:{
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
label:'Tag',
tickOptions:{
},
labelOptions: {
fontSize: '13pt',
textColor: '#FFFFFF'
}
},
yaxis:{
label:'Anzahl',
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
tickOptions:{
},
labelOptions: {
fontSize: '13pt',
textColor: '#FFFFFF'
}
}
}
});
Currently you are using implode and json_encode. I guess, that manually creating JSON might produce some kind of error in the output. (Like double encoding the JSON data.)
It should work if you only add the data to the array first and then json_encode whole dataset.
<?php
$temp = array();
for( $i=0; $i < 30; $i++ ) {
$temp[] = array( $i, $i*5 );
}
$return['line'] = $temp;
die( json_encode( $return ) );
I tried finding a well explained example or at least a definition, but had no luck.
So basically I have a data-table, I want to fetch some values from it and display it using jquery high-chart.
So far, I have this:
<?php
include("connect.php"); //script for connecting to database and defining the $connection
$query = "SELECT * FROM meetings";
$result = mysql_query($query, $connection);
$numberOfMeetings = 25; //this is mocked here so you can better understand the code
echo '<table>
<tbody>';
while ($row = mysql_fetch_array($result)) {
echo '<tr>';
echo '<td>' . $row['memberName'] . '</td>';
echo '<td>' . ($row['timesPresent'] / $numberOfMeetings) * 100 . '%</td>';
echo '</tr>';
}
?>
I get a nice simple table with a lot of rows and 2 columns. First column is showing the name of the member and the second one is showing the percentage how many times he has been present on a meeting.
My question is now that I have this data-table and those values (I can always put the values in arrays if needed) how can I display it like this done on the fiddle: http://jsfiddle.net/uDrQq/3/
I somehow need to pass the categories and the data from php values to the jquery code,but how?
To use this you have to pass DB values from PHP to Javascript
use php on same page or get the values from AJAX
here is the demo how to use on same page
<?php
include("connect.php"); //script for connecting to database and defining the $connection
$query = "SELECT * FROM meetings";
$result = mysql_query($query, $connection);
$numberOfMeetings = 25; //this is mocked here so you can better understand the code
$membername=array();
$timepresent=array();
while ($row = mysql_fetch_array($result)) {
$membername[]=$row['memberName'];
$timepresent[]=($row['timesPresent'] / $numberOfMeetings) * 100;
}
$membername="'".implode("','", $membername)."'";
$timepresent=implode(",", $timepresent);
?>
//pass values in Javascript
$(function () {
$('#container').highcharts({
chart: {
type: 'bar'
},
title: {
text: 'Percentage of members on meetings'
},
xAxis: {
categories: [<?php echo $membername?>],
title: {
text: "Members"
}
},
yAxis: {
min: 0,
title: {
text: 'Percentage',
align: 'middle'
},
labels: {
overflow: 'justify'
}
},
tooltip: {
valueDecimals: 2,
valueSuffix: ' %'
},
plotOptions: {
bar: {
dataLabels: {
enabled: true
}
}
},
credits: {
enabled: false
},
series: [{
name: 'Present: ',
data: [<?php echo $timepresent?>]
}]
});
});
I am passing Highstock/Highcharts three separate series of data via PHP and for some reason only one series is displayed when the chart is loaded. Here is an example of what my HTML output looks like now: http://bit.ly/15D3Dhi and here is what my full PHP code looks like:
date_default_timezone_set('America/Los_Angeles');
$stocks = array('MSFT' => 'http://ichart.finance.yahoo.com/table.csv?s=MSFT', 'AAPL' => 'http://ichart.finance.yahoo.com/table.csv?s=AAPL', 'FB' => 'http://ichart.finance.yahoo.com/table.csv?s=FB', 'ZNGA' => 'http://ichart.finance.yahoo.com/table.csv?s=ZNGA');
$stocks_data = array();
foreach ($stocks as $key=>$stock) {
$fh = fopen($stock, 'r');
$header = fgetcsv($fh);
$varname = $key . '_data';
$$varname = array();
while ($line = fgetcsv($fh)) {
${$varname}[count($$varname)] = array_combine($header, $line);
}
fclose($fh);
}
foreach($MSFT_data as $val){
$MSFT[] = array((strtotime($val['Date']) * 1000), ((float)$val['Close']));
}
$MSFT = json_encode($MSFT);
foreach($AAPL_data as $val){
$AAPL[] = array((strtotime($val['Date']) * 1000), ((float)$val['Close']));
}
$AAPL = json_encode($AAPL);
foreach($FB_data as $val){
$FB[] = array((strtotime($val['Date']) * 1000), ((float)$val['Close']));
}
$FB = json_encode($FB);
?>
<html>
<head>
<title>
Highcharts + PHP + Stock Data
</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
chart = new Highcharts.StockChart({
chart: {
renderTo: 'container'
},
rangeSelector: {
selected: 4
},
yAxis: {
labels: {
formatter: function() {
return (this.value > 0 ? '+' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent'
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2
},
series: [{
name: 'MSFT',
data: <?php echo $MSFT; ?>
}, {
name: 'AAPL',
data: <?php echo $AAPL; ?>
}, {
name: 'FB',
data: <?php echo $FB; ?>
}]
});
});
</script>
</head>
<body>
<script src="http://code.highcharts.com/stock/highstock.js"></script>
<script src="http://code.highcharts.com/stock/modules/exporting.js"></script>
<div id="container" style="height: 500px; min-width: 600px"></div>
</body>
</html>
Can anyone look at my code and see why only one series is showing up? If you look at the source of my HTML output, all data appears to have been passed in the same way, so it's not clear to me why only one series is displayed.
Thanks and let me know if you have any questions or need more information.
Looked at it, and the first thing I noticed is the code is quite clean, but there is a JS error:
Highcharts error #15: www.highcharts.com/errors/15
Title: Highcharts expects data to be sorted
Then I noticed FB is the only one that shows up, but expanding the date range lets you see FB and another series, so the Y axis is to blame.
Out of whim I decided to fix the JS error first, and somehow the Y-axis solved itself. So looks like the JS error is the culprit.
EDITED: Using the much faster array_reverse instead of array_unshift per 585connor's suggestion:
foreach($MSFT_data as $val){
$MSFT[] = array((strtotime($val['Date']) * 1000), ((float)$val['Close']));
}
$MSFT = json_encode(array_reverse($MSFT));
foreach($AAPL_data as $val){
$AAPL[] = array((strtotime($val['Date']) * 1000), ((float)$val['Close']));
}
$AAPL = json_encode(array_reverse($AAPL));
foreach($FB_data as $val){
$FB[] = array((strtotime($val['Date']) * 1000), ((float)$val['Close']));
}
$FB = json_encode(array_reverse($FB));
foreach($ZNGA_data as $val){
$ZNGA[] = array((strtotime($val['Date']) * 1000), ((float)$val['Close']));
}
$ZNGA = json_encode(array_reverse($ZNGA));