In my DB there is Transaction table. This table contains information about user money transactions. My task is to generate two diagrams(graphs) showing transaction amount per day, and per month.
Example of the diagram that I should implement is displayed on the image below:
As you can see from the diagram, when there are no transactions per day, the total value should be 0.
In the database, I group my transactions by day using the following query:
select DATE_FORMAT(t.transactionDate ,"%b %d") as dayName, sum(t.amount) total from `Transaction` t, t.transactionStatus = 1 and t.user=17
group by dayName
order by t.transactionDate asc;
This is working like a charm when there are transactions for every day, but this is not working fine when there is a day without any transaction. Let's say in DB we have the following transactions:
May 1st 20$
May 1st 30$
May 1st 38$
May 2nd 20$
May 4th 100$
May 4th 50$
So no transactions on May 3rd.
When I group these transactions I get the following result:
May 1st 88$
May 2nd 20$
May 4th 150$
What I want now is to generate May 3rd 0$. Is it possible to do it directly in DB, or I have to process it using PHP?
If I have to process it using PHP, any ideas?
For plotting I'm using Chart JS library, and here is example of data input:
var areaChartData = {
labels: ["May 01", "May 02", "May 04"],
datasets: [
{
label: "Transactions",
fillColor: "rgba(210, 214, 222, 1)",
strokeColor: "rgba(210, 214, 222, 1)",
pointColor: "rgba(210, 214, 222, 1)",
pointStrokeColor: "#c1c7d1",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [88,20,150]
},
]
};
As you can see, my idea is to use values from the database directly in the chart, where transaction date is my X-axis, and total is my Y-axis.
One approach is, to have all possible dates and values first as an PHP array:
$labels = array(
"May 1st" => 0,
"May 2nd" => 0,
"May 3rd" => 0,
"May 4th" => 0,
"May 6th" => 0,
"May 6th" => 0,
....
);
Then fill all the values from the database to their according date key in the array
...
foreach ( $rows as $row )
{
$labels[$row['date']] = $row['agg_val'];
...
Now you can iterate over the $labels array and put out the values. Those, which are not in the DB (no transactions) are initialized to zero.
Looking at your query, it will generate $result like below,
array (size=3)
0 =>
array (size=2)
'dayName' => string 'May 01' (length=6)
'total' => int 88
1 =>
array (size=2)
'dayName' => string 'May 02' (length=6)
'total' => int 20
2 =>
array (size=2)
'dayName' => string 'May 04' (length=6)
'total' => int 150
This script will prepare array for chartdata,
$begin = reset($result) ['dayName']; // 1st date in result
$end = end($result) ['dayName']; // last date in result
$begin = new DateTime($begin);
$end = new DateTime($end);
$end->modify('+1 day');
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($begin, $interval, $end);
function search($input, $day)
{
foreach($input as $k => $v)
{
if ($v['dayName'] == $day) return $k;
}
return false;
}
$chartdata = []; // array for chartdata
foreach($period as $dt) // loop for everyday from 1st to last day
{
$format = $dt->format('M d');
$flag = search($result, $dt->format('M d'));
$chartdata[$format] = is_int($flag) ? $result[$flag]['total'] : 0;
}
Now, your $chartdata contains the missing day May 03 from transactions table.
Now, use this as
labels: <?php echo json_encode(array_keys($chartdata))?>,
and
data: <?php echo json_encode(array_values($chartdata))?>
Related
I want to make a php calculator.
First i want it to have an assigned value per day for every month. For example marchs daily value is $12 and January is $7.
Based on these values I want the calculator to calculate daily charges from selected date calendar.
And then the total cost.
Any ideas how I can do it? Any articles that can help me?
Thank you in advance!!!
This might help you on your way. First set start and end date for the period. The logic then stores the 'days' for each month in $dates[] and sums the days for each month, stored in $daysPerMonth[]. Finally, using the $charges[] array, rotate through the days in each month and multiply by the set charges.
Array totalCharges[] shows the totals per month. Grand total, the overall total for the period.
<?php
$start = "2021-01-01";
$end = "2022-01-10";
$start = new DateTime($start);
$end = new DateTime($end);
$interval = new DateInterval('P1D');
$end = $end->modify( '+1 day' ); // include end date
$period = new DatePeriod($start, $interval, $end);
// store dates
$dates = [];
$format = 'm'; // only month is of interest
foreach ($period as $date) {
$dates[] = $date->format($format);
}
$daysPerMonth = array_count_values($dates); // count days per month
// set charges per month
$charges = ['01' => 7, '02' => 9, '03' => 12, '04' => 13, '05' => 14, '06' => 15,
'07' => 16, '08' => 15, '09' => 12, '10' => 9, '11' => 8, '12' => 7];
$totalCharges = []; // store total charges per month
foreach($charges as $monthly => $charge) {
foreach($daysPerMonth as $month => $days) {
if($monthly == $month) $totalCharges[$month] = $charge * $days;
}
}
print_r($totalCharges); // total charges per month
echo 'Grand Total : ' . array_sum($totalCharges);
I guess I’m stuck with this problem, so I’m hoping that you can give me some ideas how I can solve this task.
I’m working on an app that allows you to get an overview about your recurring payments (I know, this stuff exists already, this is just a side project) and your expenses.
The API is nearly finished but I struggle with this section: I need to know, if a recurring payment is due within a given time span.
The recurring events (contracts) contain amongst other fields startDate, endDate, intervalType (enum [weekly, monthly, quarterly, biannually, annually])
Currently I have this as my doctrine query:
return $this->createQueryBuilder('e')
->andWhere('e.startDate >= :start')
->andWhere('e.endDate <= :end')
->andWhere('e.user = :user')
->setParameter('start', $start)
->setParameter('end', $end)
->setParameter('user', $user)
->getQuery()
->getResult();
where the parameters start and end are the frame of interval.
But how can I check if and how often the contracts are due within the selected frame?
Afaik this would only be possible by iterating over the result of the query and check if the contract intersects with the timeframe and also note how often and when it occurs during this time.
But I have no idea how I can do this.
Example Data:
[name, intervalType, startDate, endDate, amount]
rent, monthly, 2019-01-01, 2020-10-11, -500
utility, monthly, 2019-01-01, 2020-10-11, -150
salary, monthly, 2019-01-01, 2020-10-11, 1700
investment, biannually, 2019-02-10, null , 2500
food, weekly, 2019-01-01, null , -50
If I have the timeframe (2019-05-01 - 2019-05-31) of this month I would get those contracts:
rent 2019-05-01
utility 2019-05-01
salary 2019-05-01
food 2019-05-01
food 2019-05-08
food 2019-05-15
food 2019-05-22
food 2019-05-29
If I'd choose the following 2 months (2019-07-01 - 2019-08-31) I would get this:
rent 2019-07-01
rent 2019-08-01
utility 2019-07-01
utility 2019-08-01
salary 2019-07-01
salary 2019-08-01
food 2019-07-01
food 2019-07-08
food 2019-07-15
food 2019-07-22
food 2019-07-29
food 2019-08-01
food 2019-08-08
food 2019-08-15
food 2019-08-22
food 2019-08-29
investment 2019-08-01
Would this be possible with DateTime and DateInterval?
The logic with the weekly interval looks wrong to me. At least with my bank app a weekly schedule would always fall on the same weekday, with 7 days between two consecutive occurrences.
So with that logic you could use this function:
function getScheduleBetween($data, $intervalStart, $intervalEnd) {
$ref = [
"yearly" => [12, "months"],
"annually" => [12, "months"],
"biannually" => [6, "months"],
"quarterly" => [3, "months"],
"monthly" => [1, "months"],
"weekly" => [7, "days"],
"daily" => [1, "days"]
];
$intervalStart = new DateTime($intervalStart);
$intervalEnd = new DateTime($intervalEnd);
$result = [];
foreach($data as $schedule) {
// Convert start/end to DateTime
$startDate = new DateTime($schedule["startDate"]);
$endDate = $schedule["endDate"] ? min(new DateTime($schedule["endDate"]), $intervalEnd) : $intervalEnd;
$name = $schedule["name"];
$interval = $schedule["intervalType"];
if (!isset($ref[$interval])) throw "Invalid interval type";
list($coeff, $interval) = $ref[$interval];
$match = clone $startDate;
if ($match < $intervalStart) {
$diff = $intervalStart->diff($match);
$count = $interval == "days" ? $diff->format("%a") : $diff->m + $diff->y * 12 + ($diff->d ? 1 : 0);
$count = ceil($count / $coeff) * $coeff;
$match->modify("+$count $interval");
}
while ($match <= $endDate) {
$temp = clone $match;
$result[] = ["name" => $name, "date" => $temp->format("Y-m-d")];
$match->modify("+$coeff $interval");
}
}
array_multisort(array_column($result, "date"), $result);
return $result;
}
Example use:
$data = [
["name" => "rent", "intervalType" => "monthly", "startDate" => "2019-01-01", "endDate" => "2020-10-11", "amount" => -500],
["name" => "utility", "intervalType" => "monthly", "startDate" => "2019-01-01", "endDate" => "2020-10-11", "amount" => -150],
["name" => "salary", "intervalType" => "monthly", "startDate" => "2019-01-01", "endDate" => "2020-10-11", "amount" => 1700],
["name" => "investment", "intervalType" => "biannually", "startDate" => "2019-02-10", "endDate" => null, "amount" => 2500],
["name" => "food", "intervalType" => "weekly", "startDate" => "2019-01-01", "endDate" => null, "amount" => -50],
];
$result = getScheduleBetween($data, "2019-05-01", "2019-05-31");
print_r($result);
With the larger period:
$result = getScheduleBetween($data, "2019-05-01", "2019-08-31");
print_r($result);
If you have other types of intervals I believe you can easily extend this function to support them, even with the other logic of "weekly".
I posted a question some time ago on representing data per date horizontally on a datatable.
See here: datatables dates at the top and data cells going from left to right
With the help of that thread I was able to get the data to display how I wanted it. With the dates showing at the top, the service provided on the left and all data associated with any date between the 2 date paramters inside the main body. (If there is no data in a particular date then the < td > will display 0. See here:
http://www.phpwin.org/s/ewbAS6
After manipulating this code further I made the dates of the search dynamic by proving a form with a start date and an end date, and a dropdown with the options of:
Daily
Weekly
Monthly
Quaterly
Yearly
this allows the interval of dates at the top to become dynamic. Of course all this is doing is changing the value of the 2nd parameter inside the date while loop.
WHILE (strtotime($date) <= strtotime($end_date)) {
echo '<th>' . $date . '</th>';
$date = date('Y-m-d', strtotime($date . ' +1day'));
}
with the parameter set at Weekly, the value of +1day becomes +1week, at Monthly; the value becomes +1month and so on.
MY ISSUE:
When the interval is set to daily, the dates with their corresponding attendance counts are displayed correctly but once you try to increase the interval to +1week and above the data does not round up to the week shown. Check this:
[LINK1]Per day: http://www.phpwin.org/s/ewbAS6
[LINK2]Per month: http://www.phpwin.org/s/xRo3I6
Looking at the array (modified on the LINK2)
$result[] = array('Service Name' => 'Health', 'date' => '2017-04-04', 'Attendance' => 5);
$result[] = array('Service Name' => 'Payroll', 'date' => '2017-04-16', 'Attendance' => 5);
$result[] = array('Service Name' => 'Saturday Youth Meeting', 'date' => '2017-04-03', 'Attendance' => 1);
$result[] = array('Service Name' => 'Saturday Youth Meeting', 'date' => '2017-05-03', 'Attendance' => 3);
$result[] = array('Service Name' => 'Payroll', 'date' => '2017-05-03', 'Attendance' => 2);
$result[] = array('Service Name' => 'Payroll', 'date' => '2017-04-11', 'Attendance' => 3);
$result[] = array('Service Name' => 'Payroll', 'date' => '2018-04-03', 'Attendance' => 10);
You can see in the array that there are multiple attendance entries in April, totaling 14 Attendances in that month however during LINK2 where the interval is increased to a month instead of showing 14 for April (which would be the sum of all the dates in that particular month) it shows the value 1.
My live version takes the array from a database so I used the YEAR(), MONTH(), WEEK() and DAY() function on the date and used group by. The query executes how I want it but having issues working on the PHP end.
I'm having a hell of a time trying to solve the following problem:
It's a calendar program where given a set of available datetime sets from multiple people, I need to figure out what datetime ranges everyone is available in PHP
Availability Sets:
p1: start: "2016-04-30 12:00", end: "2016-05-01 03:00"
p2: start: "2016-04-30 03:00", end: "2016-05-01 03:00"
p3: start: "2016-04-30 03:00", end: "2016-04-30 13:31"
start: "2016-04-30 15:26", end: "2016-05-01 03:00"
I'm looking for a function that I can call that will tell me what datetime ranges all (p) people are available at the same time.
In the above example the answer should be:
2016-04-30 12:00 -> 2016-04-30 13:31
2016-04-30 15:26 -> 2016-05-01 03:00
I did find this similar question and answer
Datetime -Determine whether multiple(n) datetime ranges overlap each other in R
But I have no idea what language that is, and have to unable to translate the logic in the answer.
Well that was fun. There's probably a more elegant way of doing this than looping over every minute, but I don't know if PHP is the language for it. Note that this currently needs to manage the start and end times to search separately, although it would be fairly trivial to calculate them based on the available shifts.
<?php
$availability = [
'Alex' => [
[
'start' => new DateTime('2016-04-30 12:00'),
'end' => new DateTime('2016-05-01 03:00'),
],
],
'Ben' => [
[
'start' => new DateTime('2016-04-30 03:00'),
'end' => new DateTime('2016-05-01 03:00'),
],
],
'Chris' => [
[
'start' => new DateTime('2016-04-30 03:00'),
'end' => new DateTime('2016-04-30 13:31')
],
[
'start' => new DateTime('2016-04-30 15:26'),
'end' => new DateTime('2016-05-01 03:00')
],
],
];
$start = new DateTime('2016-04-30 00:00');
$end = new DateTime('2016-05-01 23:59');
$tick = DateInterval::createFromDateString('1 minute');
$period = new DatePeriod($start, $tick, $end);
$overlaps = [];
$overlapStart = $overlapUntil = null;
foreach ($period as $minute)
{
$peopleAvailable = 0;
// Find out how many people are available for the current minute
foreach ($availability as $name => $shifts)
{
foreach ($shifts as $shift)
{
if ($shift['start'] <= $minute && $shift['end'] >= $minute)
{
// If any shift matches, this person is available
$peopleAvailable++;
break;
}
}
}
// If everyone is available...
if ($peopleAvailable == count($availability))
{
// ... either start a new period...
if (!$overlapStart)
{
$overlapStart = $minute;
}
// ... or track an existing one
else
{
$overlapUntil = $minute;
}
}
// If not and we were previously in a period of overlap, end it
elseif ($overlapStart)
{
$overlaps[] = [
'start' => $overlapStart,
'end' => $overlapUntil,
];
$overlapStart = null;
}
}
foreach ($overlaps as $overlap)
{
echo $overlap['start']->format('Y-m-d H:i:s'), ' -> ', $overlap['end']->format('Y-m-d H:i:s'), PHP_EOL;
}
There are some bugs with this implementation, see the comments. I'm unable to delete it as it's the accepted answer. Please use iainn or fusion3k's very good answers until I get around to fixing it.
There's actually no need to use any date/time handling to solve this
problem. You can exploit the fact that dates in this format are in alphabetical as well as chronological order.
I'm not sure this makes the solution any less complex. It's probably less
readable this way. But it's considerably faster than iterating over every minute so you might choose it if performance is a concern.
You also get to use
every
single
array
function
out there, which is nice.
Of course, because I haven't used any date/time functions, it might not work if Daylight Savings Time or users in different time zones need dealing with.
$availability = [
[
["2016-04-30 12:00", "2016-05-01 03:00"]
],
[
["2016-04-30 03:00", "2016-05-01 03:00"]
],
[
["2016-04-30 03:00", "2016-04-30 13:31"],
["2016-04-30 15:26", "2016-05-01 03:00"]
]
];
// Placeholder array to contain the periods when everyone is available.
$periods = [];
// Loop until one of the people has no periods left.
while (count($availability) &&
count(array_filter($availability)) == count($availability)) {
// Select every person's earliest date, then choose the latest of these
// dates.
$start = array_reduce($availability, function($carry, $ranges) {
$start = array_reduce($ranges, function($carry, $range) {
// This person's earliest start date.
return !$carry ? $range[0] : min($range[0], $carry);
});
// The latest of all the start dates.
return !$carry ? $start : max($start, $carry);
});
// Select each person's range which contains this date.
$matching_ranges = array_filter(array_map(function($ranges) use($start) {
return current(array_filter($ranges, function($range) use($start) {
// The range starts before and ends after the start date.
return $range[0] <= $start && $range[1] >= $start;
}));
}, $availability));
// Find the earliest of the ranges' end dates, and this completes our
// first period that everyone can attend.
$end = array_reduce($matching_ranges, function($carry, $range) {
return !$carry ? $range[1] : min($range[1], $carry);
});
// Add it to our list of periods.
$periods[] = [$start, $end];
// Remove any availability periods which finish before the end of this
// new period.
array_walk($availability, function(&$ranges) use ($end) {
$ranges = array_filter($ranges, function($range) use($end) {
return $range[1] > $end;
});
});
}
// Output the answer in the specified format.
foreach ($periods as $period) {
echo "$period[0] -> $period[1]\n";
}
/**
* Output:
*
* 2016-04-30 12:00 -> 2016-04-30 13:31
* 2016-04-30 15:26 -> 2016-05-01 03:00
*/
A different approach to your question is to use bitwise operators. The benefits of this solution are memory usage, speed and short code. The handicap is that — in your case — we can not use php integer, because we work with large numbers (1 day in minutes is 224*60), so we have to use GMP Extension, that is not available by default in most php distribution. However, if you use apt-get or any other packages manager, the installation is very simple.
To better understand my approach, I will use an array with a total period of 30 minutes to simplify binary representation:
$calendar =
[
'p1' => [
['start' => '2016-04-30 12:00', 'end' => '2016-04-30 12:28']
],
'p2' => [
['start' => '2016-04-30 12:10', 'end' => '2016-04-30 12:16'],
['start' => '2016-04-30 12:22', 'end' => '2016-05-01 12:30']
]
];
First of all, we find min and max dates of all array elements, then we init the free (time) variable with the difference in minutes between max and min. In above example (30 minutes), we obtain 230-20=1,073,741,823, that is a binary with 30 ‘1’ (or with 30 bits set):
111111111111111111111111111111
Now, for each person, we create the corresponding free-time variable with the same method. For the first person is easy (we have only one time interval): the difference between start and min is 0, the difference between end and min is 28, so we have 228-20=268435455, that is:
001111111111111111111111111111
At this point, we update global free time with a AND bitwise operation between global free time itself and person free time. The OR operator set bits if they are set in both compared values:
111111111111111111111111111111 global free time
001111111111111111111111111111 person free time
==============================
001111111111111111111111111111 new global free time
For the second person, we have two time intervals: we calculate each time interval with know method, then we compone global person free time using OR operator, that set bits if they are set in either first or second value:
000000000000001111110000000000 12:10 - 12:16
111111110000000000000000000000 12:22 - 12:30
==============================
111111110000001111110000000000 person total free time
Now we update global free time with the same method used for first person (AND operator):
001111111111111111111111111111 previous global free time
111111110000001111110000000000 person total free time
==============================
001111110000001111110000000000 new global free time
└────┘ └────┘
:28-:22 :16-:10
As you can see, at the end we have an integer with bits set only in minutes when everyone is available (you have to count starting from right). Now, you can convert back this integer to datetimes. Fortunately, GMP extension has a method to find 1/0 offset, so we can avoid to perform a for/foreach loop through all digits (that in real case are many more than 30).
Let's see the complete code to apply this concept to your array:
$calendar =
[
'p1' => [
['start' => '2016-04-30 12:00', 'end' => '2016-05-01 03:00']
],
'p2' => [
['start' => '2016-04-30 03:00', 'end' => '2016-05-01 03:00']
],
'p3' => [
['start' => '2016-04-30 03:00', 'end' => '2016-04-30 13:31'],
['start' => '2016-04-30 15:26', 'end' => '2016-05-01 03:00']
]
];
/* Get active TimeZone, then calculate min and max dates in minutes: */
$tz = new DateTimeZone( date_default_timezone_get() );
$flat = call_user_func_array( 'array_merge', $calendar );
$min = date_create( min( array_column( $flat, 'start' ) ) )->getTimestamp()/60;
$max = date_create( max( array_column( $flat, 'end' ) ) )->getTimestamp()/60;
/* Init global free time (initially all-free): */
$free = gmp_sub( gmp_pow( 2, $max-$min ), gmp_pow( 2, 0 ) );
/* Process free time(s) for each person: */
foreach( $calendar as $p )
{
$pf = gmp_init( 0 );
foreach( $p as $time )
{
$start = date_create( $time['start'] )->getTimestamp()/60;
$end = date_create( $time['end'] )->getTimestamp()/60;
$pf = gmp_or( $pf, gmp_sub( gmp_pow( 2, $end-$min ), gmp_pow( 2, $start-$min ) ) );
}
$free = gmp_and( $free, $pf );
}
$result = [];
$start = $end = 0;
/* Create resulting array: */
while( ($start = gmp_scan1( $free, $end )) >= 0 )
{
$end = gmp_scan0( $free, $start );
if( $end === False) $end = strlen( gmp_strval( $free, 2 ) )-1;
$result[] =
[
'start' => date_create( '#'.($start+$min)*60 )->setTimezone( $tz )->format( 'Y-m-d H:i:s' ),
'end' => date_create( '#'.($end+$min)*60 )->setTimezone( $tz )->format( 'Y-m-d H:i:s' )
];
}
print_r( $result );
Output:
Array
(
[0] => Array
(
[start] => 2016-04-30 12:00:00
[end] => 2016-04-30 13:31:00
)
[1] => Array
(
[start] => 2016-04-30 15:26:00
[end] => 2016-05-01 03:00:00
)
)
3v4l.org demo
Some additional notes:
At the start, we set $tz to current timezone: we will use it later, at the end, when we create final dates from timestamps. Dates created from timestamps are in UTC, so we have to set correct timezone.
To retrieve initial $min and $max values in minutes, firstly we flat original array, then we retrieve min and max date using array_column.
gmp_sub subtract second argument from first argument, gmp_pow raise number (arg 1) into power (arg 2).
In the final while loop, we use gmp_scan1 and gmp_scan0 to retrieve each ‘111....’ interval, then we create returning array elements using gmp_scan1 position for start key and gmp_scan0 position for end key.
I'm trying to display data on a line graph using Google Charts. The data displays fine, however I would like to set a date range to be displayed.
The data is sent from the database in a JSON literal format:
{
"cols": [
{"label": "Week", "type": "date"},
{"label": "Speed", "type": "number"},
{"type":"string","p":{"role":"tooltip"}},
{"type":"string","p":{"role":"tooltip"}},
{"type":"string","p":{"role":"tooltip"}},
{"type":"string","p":{"role":"tooltip"}},
],
"rows": [
{"c":[{"v": "Date('.$date.')"},{"v": null},{"v": null},{"v": null},{"v": null},{"v": null}]},
{"c":[{"v": "Date('.$date.')"},{"v": null},{"v": null},{"v": null},{"v": null},{"v": null}]}
]
}
Data is either displayed by week or month (null for easy reading) for example this week:
2012, 02, 06
2012, 02, 07
2012, 02, 09
Data isn't set for everyday of the week, therefore in this example only the dates above are shown. What I would like to be shown is the start of the week (2012, 02, 06) to the end of the week (2012, 02, 12) similar to the third example here.
I managed to get the whole week showing by checking if the date exists in the database and if not append an extra row will null data, this however meant the line was not continuous and the dates where not in order.
Could anyone offer any advice on how to I could go about doing this?
Thanks!
Did you try leaving the missing dates be missing dates (i.e. let the database return 2 values instead of 7)?
The continuous axis should handle missing dates, you just need to set the axis range from start to end of the week.
UPDATE
for interactive line chart the axis ranges can be set like this (as inspired by this thread):
hAxis: {...
viewWindowMode: 'explicit',
viewWindow: {min: new Date(2007,1,1),
max: new Date(2010,1,1)}
...}
see http://jsfiddle.net/REgJu/
"I managed to get the whole week showing by checking if the date exists in the database and if not append an extra row will null data, this however meant the line was not continuous and the dates where not in order."
I think you are on the right track you just need to do it in a slightly different way. I have the function like the below to make data continuous.
$data = array(
1 => 50,
2 => 75,
4 => 65,
7 => 60,
);
$dayAgoStart = 1;
$daysAgoEnd = 14;
$continuousData = array();
for($daysAgo=$daysAgoStart ; $daysAgo<=$daysAgoEnd ; $daysAgo++){
if(array_key_exists($daysAgo, $data) == true){
$continuousData[$daysAgo] = $data[$daysAgo];
}
else{
$continuousData[$daysAgo] = 0;
}
}
continuousData will now hold:
$data = array(
1 => 50,
2 => 75,
3 => 0,
4 => 65,
5 => 0,
6 => 0,
7 => 60,
8 => 0,
9 => 0,
10 => 0,
11 => 0,
12 => 0,
13 => 0,
14 => 0,
);
in that order, and then the data can be used in the charts without any gaps.
Perhaps you can use a different chart type? Dygraphs looks like it might be helpful.
Otherwise you may have to write your own custom chart type.