Populating Google combo chart with multidimensional PHP array - php

I have a php array with data on students. It looks like this:
array(5) {
["question1"]=>
array(30) {
["2014, 03, 02"]=>
array(10) {
["student1"]=>
int(54)
["student2"]=>
int(43)
... etc. ...
["median"]=>
string(2) "49"
}
Each day the students answers five questions with a value from 1 to 100. Each day a median value for all answers to a single question is calculated. The answers and the median value is stored like above.
Now I want to populate a Google Charts combo chart with this data but I just can't get it to work.
I would like to visualise the data with the date on the X-axis, the 1-100 value on the Y-axis and each answer as a point. The data for the median value should be displayed as a curve over the points. Points and curves for each question should have its own colour.
But I'm pretty much stuck. I can't figure out how to insert the data. I have tried this approach:
var jsonData = (<?= json_encode($data)?>);
var data = new google.visualization.arrayToDataTable(jsonData);
but I only get the following error message:
Uncaught Error: Not an array format+da,default+da,ui+da,corechart+da.I.js:181
lda format+da,default+da,ui+da,corechart+da.I.js:181
Gp format+da,default+da,ui+da,corechart+da.I.js:183
drawChart ?side=graf:4888

You need to change the format of your data. The Visualization API expects data in a tabular format, where your x-axis data is in the first column and each data series (a set of colored points) is its own column of data. You can either construct a json representation of a DataTable (for use with the DataTable constructor) or an array of arrays of data (for use with the arrayToDataTable function).
Since you are already using the arrayToDataTable function, this is the structure you need to have:
$data = array(
array('Date', 'Question 1', array('type' => 'number', 'role' => 'interval', 'id' => 'Q1Median'), 'Question 2', array('type' => 'number', 'role' => 'interval', 'id' => 'Q2Median') /* repeat for other questions */),
// format is array(date, q1 score, q1 median, q2 score, q2 median...)
// set the median in the first row for the day, leave it null for all other rows
array('2014, 03, 02', 54, 49, /* repeat for other questions */),
array('2014, 03, 02', 43, null, /* repeat for other questions */),
// repeat one row for each student for each day
);
The median values are set in an "interval" role column, which you can style to display as a curved line in the chart options:
interval: {
// use the column ID of an interval to set the options for that interval
Q1median: {
style: 'line'
},
Q2median: {
style: 'line'
}
// etc...
}
Options for styling intervals are documented here.

Related

A csv file has a state, county, and data on each line. How can I use PHP associative arrays to convert to states=>counties=>county=>data

My data looks like:
countyFIPS,County Name,State,stateFIPS,1/22/20,1/23/20,1/24/20,1/25/20,....
1001,Autauga County,AL,1,0,0,0,0,0,0,0,0,....
...
I've been able to retrieve it using an Ajax call and collect it into a simple PHP array, then convert it to json to use in my javascript application. While it appears that the data is all counties of a state, followed by the same configuration for the next state, there is no guarantee that it won't be mixed up in some later set of data.
I'm an old Fortran programmer, and would tend to build a hash table for the "states", then check if the state exists in the hash table. If not create a new hash table and add this empty hash table as the value for the key with the name of the state to the "state" hash table. Then check the state hash table to see if it has a key for the county. Again, if it doesn't, then add an empty array as the value for the key with the county name and add that to the state hash table, then proceed to put the values for that row into the county array. I know this will work, but thought maybe there was some clever way to use associative arrays in PHP to accomplish the same thing.
I look at array_filter, but can't seem to figure out how to adapt it to this case. Are there other functions that might work here?
Then, once I have this structure of
$nested_object = { state1=>{county1,county2,county3...},state2=>{counties}},
and those counties have:
county=>[values],
how can I easily convert this to a json structure? Should it have other keys like "states", and within a state "counties". From looking at Haroldo's question "Convert a PHP object to an associative array" of Dec 3, 2010, it appears like I would use:
$array = json_decode(json_encode($nested_object), true);
Will this give me the structure I am looking for?
I want to end up with a structure that I can ask for the states as a set of keys, then for a selected state ask for the counties in that state as a set of keys, and upon selecting one, get the array of values for that state/county. This has to run on a server with potentially a large amount of data and a moderate amount of hits per unit time so I wanted as reasonably efficient way as possible.
I want to end up with a structure that I can ask for the states as a set of keys, then for a selected state ask for the counties in that state as a set of keys, and upon selecting one, get the array of values for that state/county
Okay, so you need something like:
$structure = [
'AL' => [
'counties' => [
'FIPS1' => 'County1',
'FIPS2' => 'County2',
],
'data' => [
'FIPS1' => [
[ 'date1' => value1, 'date2' => value2, 'date3' => value3... ]
],
],
],
'AK' => [ ... ]
];
You can do that using array_map() and a lambda function writing to $structure, but... in my experience, it is not worth it.
Best to do like you said:
while ($row = get_another_row()) {
$countyFIPS = array_unshift($row);
$countyName = array_unshift($row);
$stateName = array_unshift($row);
$stateFIPS = array_unshift($row);
if (!array_key_exists($stateName, $structure)) {
$structure[$stateName] = [
'counties' => [ ],
'data' => [ ],
];
}
if (!array_key_exists($countyFIPS, $structure[$stateName]['counties'])) {
$structure[$stateName]['counties'][$countyFIPS] = $countyName;
$structure[$stateName]['data'][$countyFIPS] = [ ];
}
// Now here you will have $headers, obtained from the header row unshifting
// the first four fields.
foreach ($headers as $i => $key) {
$structure[$stateName]['data'][$countyFIPS][$key] = $row[$i];
}
}
This way if you add two CSVs with different dates, the code will still work properly. Dates will not be sorted though, but you can do that with a nested array_map and the aksort function.
To output this in JSON, just use json_encode on $structure.

How do I use linest function in phpspreadsheet?

I am using 33_Chart_create_scatter.php to generate a XY scatter chart. I am closing in on completion. All I have left is inducing the linest function. Would someone please provide some code on the use of linest in phpspreadsheet?
I've done a lot of googles, with no luck. Lots of visits to phpspreadsheet docs. With a lot of information, I don't understand. I have not used classes to this point, so I don't know how to form the code to talk with the classes shown in the code section below?
Here is the data I use:
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$1:$C$18', null, 18),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$F$1:$F$18', null, 18)
[;
\PhpOffice\PhpSpreadsheet\Calculation\Statistical::LINEST
'LINEST' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical::class, 'LINEST'],
'argumentCount' => '1-4',
],
public static function LINEST($yValues, $xValues = null, $const = true, $stats = false)
{
$const = ($const === null) ? true : (bool) Functions::flattenSingleValue($const);
$stats = ($stats === null) ? false : (bool) Functions::flattenSingleValue($stats);
if ($xValues === null) {
$xValues = range(1, count(Functions::flattenArray($yValues)));
}
Of course, I have no results yet. My expectations would be to have returned the linest statistic derived.
No one has added anything for a week. Here is what I have accomplished in that week: I got the following two data arrays by running the formula wizzard / linest on the data in 33 Chart create scatter. The chart I made. So, I know what the data is that I want from phpspreadsheet/linest.
Six foot data array
0.798178535 18.35040936
0.012101577 0.241020964
0.996335545 0.53274435
4350.269442 16
1234.67843 4.541064671
Ten foot data array
0.819287926 16.98988304
0.007826008 0.15586663
0.998542214 0.344522174
10959.54502 16
1300.848983 1.899128449
setCellValue, puts the formula in cell A32 and cell A32 displays the first number from the Six foot data array above.
$helper->log, gives the following output. The getCell gives the linest formula in the cell.
getCalculatedValue gives the Last value in the Six foot data array above.
19:12:47 Write Xlsx format to 33_Chart_create_scatter.xlsx in 0.0138 seconds
19:12:47 Value of linest six foot from getCell(A32) : =LINEST(D1:D18 , C1:C18 , TRUE, TRUE)
19:12:47 Value of linest six foot used getCalculatedValue get cell A32 : 4.5410646714826
19:12:47 Value of linest ten foot from getCell(A42) : =LINEST(G1:G18 , F1:F18 , TRUE, TRUE)
19:12:47 Value of linest ten foot used getCalculatedValue get cell A42 : 1.8991284485724
I tried
$spreadsheet->getActiveSheet()->fromArray($linestSix ,null,'C32');
That does the same as setCellValue, described above.
Follow this link, enter link description here ,to see the browser output when I run my code to generate my chart, 33 Chart create scatter. Go down about 75 lines into the object to [Worksheet!A32] , There is my data, but, how do I get it out of there? I got that from the print_r of $linest6 below.
$linest6 = $spreadsheet->getActiveSheet()->setCellValue('A32', '=LINEST(D1:D18 , C1:C18 , TRUE, TRUE)');
echo 'The six foot data array : <br>';
echo '<pre>';
print_r($linest6);
echo '</pre>';
Would someone, maybe Mark Baker, help me get the statistics from linest, the same as I described above from the formula wizzard? Thank you.
I finally got it!! Many trips to Google. Reviewing how to retrieve an array from a class-function. Here is my final script.
$stats = new Statistical();
$statArr6 = $stats->LINEST($dataArraySixY, $dataArraySixX, TRUE, TRUE);
$statArr10 = $stats->LINEST($dataArrayTenY, $dataArrayTenX, TRUE, TRUE);
$worksheet->fromArray(
$statArr6,
NULL,
"C22");
$worksheet->fromArray(
$statArr10,
NULL,
'C32'
);
I have a little more to display the info as I want to, but I have the arrays.

Displaying all aggregated results from Elasticsearch query in PHP

I have a field called "arrivalDate" and this field is a string. Each document has an arrivalDate in string format (ex: 20110128). I want my output to be something like this (date and the number of records that have that date):
Date : how many records have that date
20110105 : 5 records
20120501 : 2 records
20120602 : 15 records
I already have the query to get these results.
I am trying to display aggregated results in PHP from Elasticsearch. I want my output to be something like this:
Date : how many records have that date
20110105 : 5 records
20120501 : 2 records
20120602 : 15 records
This is what I have so far:
$json = '{"aggs": { "group_by_date": { "terms": { "field": "arrivalDate" } } } }';
$params = [
'index' => 'pickups',
'type' => 'external',
'body' => $json
];
$results = $es->search($params);
However, I don't know how to display the results in PHP. For example, if I wanted to display the total number of documents I would do echo $results['hits']['total'] How could I display all the dates with the number of records they have in PHP?
I'd suggest using aggregations in the same way you construct the query, from my experience it seems to work quicker. Please see the below code:
'aggs' => [
'group_by_date' => [
'terms' => [
'field' => 'arrivalDate',
'size' => 500
]
]
]
Following that, instead of using the typical results['hits']['hits'] you would switch out the hits parts to results['aggregations']. Then access the returning data by accessing the buckets in the response.
For accessing the data from the aggregation shown above, it would likely be something along the lines of:
foreach ($results as $result){
foreach($result['buckets'] as $record){
echo($record['key']);
}
}
There will be a better way of accessing the array within the array, however, the above loop system works well for me. If you have any issues with accessing the data, let me know.

PHPExcel with CodeIgniter merge two different columns to give a result

I'm working with a spreadsheet where I have column 'G' and 'M' where I have in column 'G' cities names and in 'M' I have the date where determined product was delivered there. I'm working in a system where I need to get the information from the both columns and display in a dashboard like "Cities X Date Delivered". For example, City A have 30 products delivered at May 2th. After I'll build some chart or something. But for now, I need to found a way to merge that information perhaps into an array?
If you don't need to worry about what type of product but how many products where delivered on a certain date, you could have an 2D array where the key is the name of the city and the value is an array of dates:
// key = City, Value = {date1, date2, ... ,dateN}
$deliveredProducts = array
(
"city1" => array("date1", "date2", "date1"),
"city2" => array("date2", "date3", "date2")
);
//To get the number of products delivered to city1 on date1:
$tally = array_count_values($deliveredProducts["city1"]);
$count = $tally["date1"];
I hope this helps.

How to Build a Column Chart in Highcharts with Data Entered Dynamically Within a CMS

A Little Background
Note: I'll be referring to the Highcharts demo column chart throughout this question. The demo chart shows monthly rainfall for 4 major cities.
I'm using WordPress to allow users to dynamically generate a Highcharts column chart.
Rather than have users enter all data points for a particular city (12 points: one for each month), I thought it'd be more intuitive to have users enter the data points for each month (4 points: one for each city).
In the screenshot below, you can see how I set up the data entry: users enter the month on the left and the month's rainfall for each city on the right:
Users then enter the name and choose a color for each city in a separate area of the page.
The Problem
In the code that generates the demo chart, you can see that the data points are grouped by city:
series: [{
name: 'Tokyo',
data: [49.9, 71.5, 106.4, ...]
}, {
name: 'New York',
data: [83.6, 78.8, 98.5, ...]
} ...
However, the way I built things in WordPress, I can only figure out how to generate an array of data points for each month, such that I get this output:
// array #1
[49.9, 83.6, 48.9, 42.4]
// array #2
[71.5, 78.8, 38.8, 33.2]
// array #3
[106.4, 98.5, 39.3, 34.5]
// array #4
[129.2, 93.4, 41.4, 39.7]
// etc.
The Question
How do I create arrays of the nth values in each array? In other words, instead of looping through the values in each month, I want to just grab the first values for each month and drop them into a new array, then grab the 2nd values for each month and drop them into another array, and so on.
So, I should end up with this:
// array #1 (made up of 1st value of each array from above)
[49.9, 71.5, 106.4, 129.2]
// array #2 (made up of 2nd value of each array from above)
[83.6, 78.8, 98.5, 93.4]
// array #3 (made up of 3rd value of each array from above)
[48.9, 38.8, 39.3, 41.4]
// array #4 (made up of 4th value of each array from above)
[42.4, 33.2, 34.5, 39.7]
// etc.
Behold! My Broken (Nearly Working) Code
I've managed to get pretty close with this code...
// outer loop: iterate through each month
foreach ( $column_data as $key => $column ) :
// get the X-axis labels (names of the month)
$x_label_array[$key] = $column['label'];
// create an empty array to accept values for each city
${'column_' . $key . '_array'} = array();
// inner loop: iterate through data points for each month
foreach ( $column['columns_4'] as $key_inner => $multi_column ) :
array_push( ${'column_' . $key_inner . '_array'}, (float)$multi_column['value'] );
endforeach;
endforeach;
...but for each iteration, it skips one more value in each successive array, such that I get this output:
// this is perfect!
Array(
[0] => 49.9
[1] => 71.5
[2] => 106.4
[3] => 129.2
)
// missing 1st value
Array(
[0] => 78.8
[1] => 98.5
[2] => 93.4
)
// missing 1st and 2nd values
Array(
[0] => 39.3
[1] => 41.4
)
// missing 1st, 2nd, and 3rd values
Array(
[0] => 39.7
)
Plus, the whole notion of using a new array for each loop seems pretty janky. Is there a better way? Is this possible in PHP, or should I restructure how I ask the user to enter the data?
First of all, I like the idea of CMS controllable Highcharts! It's something I've done before too.
Rather than have users enter all data points for a particular city (12 points: one for each month), I thought it'd be more intuitive to have users enter the data points for each month (4 points: one for each city).
Personally, I think that's a bit counter intuitive. If you add another city, then a new value box pops up in 12 different places. Whereas you could have a nice ajax process or something at the end of the input screen which allows the WordPress CMS user to add another city dynamically, and entering the 12 new values in one place.
Anyway, I don't know your website so your way could be more intuitive. For your specific problem, you can think of your array of arrays as a matrix - you just need to make them officially an array of arrays rather than lots of single arrays.
Then you can use array_map to solve your problem:
$matrix = [
[49.9, 83.6, 48.9, 42.4],
[71.5, 78.8, 38.8, 33.2],
[106.4, 98.5, 39.3, 34.5],
[129.2, 93.4, 41.4, 39.7]
];
array_unshift($matrix, null);
$matrix = call_user_func_array('array_map', $matrix);
This guy provides a really good explanation of this above PHP process (better than I could!).

Categories