I am attempting to make an Abelian Sandpile Model in PHP. I am getting started with a possible solution, and it is working for three dimensional array but not working for 5 dimensional array. I am not sure why the following issue is occurring.
$pile = array(array(0,1,0),array(0,2,3),array(1,0,1));
Expected : 021, 110, 112
Actual result : 021, 110, 112
$pile = array(array(0,0,3,0,0),array(0,0,3,0,0),array(3,3,3,3,3),array(0,0,3,0,0),array(0,0,3,0,0));
Expected : 01010, 12321, 03030, 12321, 01010
Actual result : 01010, 12221, 02020, 12221, 01010
PHP Script:
<?php
//$pile = array(array(0,1,0),array(0,2,3),array(1,0,1));
//expected : 021, 110, 112
//$result = sandpile($pile, 2);
$pile = array(array(0,0,3,0,0),array(0,0,3,0,0),array(3,3,3,3,3),array(0,0,3,0,0),array(0,0,3,0,0));
//expected : 01010, 12321, 03030, 12321, 01010
$result = sandpile($pile, 5);
function sandpile($pile, $n)
{
$total_rows = count($pile);
$mid_x = (int) ($total_rows / 2);
$mid_y = (int) (count($pile[$mid_x]) / 2);
$arr_result = array_redistribute($pile, $mid_x, $mid_y, $n);
return $arr_result;
}
function array_redistribute($arr_input = array(), $x, $y, $n = 1)
{
$arr_input[$x][$y] = $arr_input[$x][$y] + $n;
// if grains in a cell reaches 4
if ($arr_input[$x][$y] > 3)
{
$arr_input[$x][$y] = 0;
// increment closest cell
if(isset($arr_input[$x-1][$y]))
$arr_input[$x-1][$y] = $arr_input[$x-1][$y] + 1;
if(isset($arr_input[$x+1][$y]))
$arr_input[$x+1][$y] = $arr_input[$x+1][$y] + 1;
if(isset($arr_input[$x ][$y-1]))
$arr_input[$x ][$y-1] = $arr_input[$x][$y-1] +1;
if(isset($arr_input[$x][$y+1]))
$arr_input[$x][$y+1] = $arr_input[$x][$y+1] + 1;
// if closest cell value > 3
if(isset($arr_input[$x-1][$y]) && $arr_input[$x-1][$y]>3)
{
$arr_input = array_redistribute($arr_input, $x-1, $y, 1);
}
if(isset($arr_input[$x+1][$y]) && $arr_input[$x+1][$y]>3)
{
$arr_input = array_redistribute($arr_input, $x+1, $y, 1);
}
if(isset($arr_input[$x][$y-1]) && $arr_input[$x][$y-1]>3)
{
$arr_input = array_redistribute($arr_input, $x, $y-1, 1);
}
if(isset($arr_input[$x ][$y+1]) && $arr_input[$x][$y+1]>3)
{
$arr_input = array_redistribute($arr_input, $x, $y+1, 1);
}
return $arr_input;
}
?>
Related
I'm trying to A* pathfinding with Pacman problem using PHP.
<?php
$_fp = fopen("php://stdin", "r");
// Node
class Node {
var $x;
var $y;
var $fCost;
var $hCost;
var $gCost = 0;
var $parent;
function __construct($x=0,$y=0){
$this->x = $x;
$this->y = $y;
}
function getNeighbours($depth = 1) {
$neighbours = array();
$operand = array(
array ('x' => -1, 'y' => 0),
array ('x' => 0, 'y' => -1),
array ('x' => 0, 'y' => 1),
array ('x' => 1, 'y' => 0)
);
foreach ($operand as $key => $value) {
$checkX = $this->x + $value['x'];
$checkY = $this->y + $value['y'];
if( $checkX >= 0 && $checkY >= 0 )
array_push( $neighbours, $node = new Node( $checkX, $checkY ) );
}
return $neighbours;
}
function fCost(){
global $food;
return $this->gCost() + $this->hCost($food);
}
function gCost(){
global $pacman;
return abs($pacman->x - $this->x) + abs($pacman->y - $this->y);
}
function hCost($destination){
return abs($destination->x - $this->x) + abs($destination->y - $this->y);
}
}
function retracePath($start,$end) {
$current = $end;
while ( $current != $start ) {
echo $current->x . " " . $current->y."<br>";
$current = $current->parent;
}
}
$pacman = new Node();
$food = new Node();
// Input data
fscanf($_fp, "%d %d", $pacman->x, $pacman->y); // Pacman's position
fscanf($_fp, "%d %d", $food->x, $food->y); // Food's position
fscanf($_fp, "%d %d", $row_size, $col_size); // For map size row and col
// Input for map by row
for($row=0; $row<$row_size; $row++) {
$map[$row] = trim(fgets(STDIN));
}
// Astar
$arr_open = array(); // set of nodes to be evaluated
$arr_close = array(); // set of nodes already evaluated
array_push($arr_open, $pacman); // add the start node to $arr_open
$key_arr_open = 0;
while( count($arr_open) > 0 ) { // loop
$current = new Node();
$current = $arr_open[$key_arr_open];
unset($arr_open[$key_arr_open]);
array_push($arr_close, $current);
if($current->x == $food->x && $current->y == $food->y) {
retracePath($pacman,$current);
echo "sukses<br>"
break;
}
$neighbours = $current->getNeighbours();
foreach ($neighbours as $key => $data) {
if($map[$data->x][$data->y] == "%" or in_array($data, $arr_close))
{
//echo "not traversable<br>";
continue;
}
$new_cost_to_neighbour = $current->gCost() + $current->hCost($data);
if( $new_cost_to_neighbour < $data->gCost() or !in_array( $data, $arr_open ) ) {
$data->gCost = $new_cost_to_neighbour;
$data->hCost = $data->hCost($food);
$data->fCost = $new_cost_to_neighbour + $data->hCost($food);
$data->parent = $current;
if( !in_array($data, $arr_open) )
{
array_push($arr_open, $data);
}
}
}
$key_arr_open ++;
}
?>
Input format : Position x and y pacman, position x and y food, count row and column of tile, then the grid. Grid format is "P" for pacman, "." for food, "-" for traversable path and "%" for wall.
The problem is when I give input with 6x6 tile like this :
%%%%%%
%-%%-%
%-%%-%
%-%%-%
%.--P%
%%%%%%
The code is work. But, if I give input with 37x37 tile with complex maze, the node in the array of open always looped. (From HackerRank)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%-------%-%-%-----------%---%-----%-%
%-%%%%%%%-%-%%%-%-%%%-%%%-%%%%%%%-%-%
%-------%-------%-%-----%-----%-%---%
%%%%%-%%%%%-%%%-%-%-%-%%%-%%%%%-%-%%%
%---%-%-%-%---%-%-%-%---%-%---%-%---%
%-%%%-%-%-%-%%%-%%%%%-%%%-%-%%%-%%%-%
%-------%-----%---%---%-----%-%-%---%
%%%-%%%%%%%%%-%%%%%%%-%%%-%%%-%-%-%-%
%-------------%-------%-%---%-----%-%
%-%-%%%%%-%-%%%-%-%-%%%-%-%%%-%%%-%-%
%-%-%-----%-%-%-%-%-----%---%-%-%-%-%
%-%-%-%%%%%%%-%-%%%%%%%%%-%%%-%-%%%-%
%-%-%-%-----%---%-----%-----%---%---%
%%%-%%%-%-%%%%%-%%%%%-%%%-%%%-%%%%%-%
%-----%-%-%-----%-%-----%-%---%-%-%-%
%-%-%-%-%-%%%-%%%-%%%-%%%-%-%-%-%-%-%
%-%-%-%-%-----------------%-%-%-----%
%%%-%%%%%%%-%-%-%%%%%-%%%-%-%%%-%%%%%
%-------%-%-%-%-----%---%-----%-%---%
%%%%%-%-%-%%%%%%%%%-%%%%%%%%%%%-%-%%%
%---%-%-----------%-%-----%---%-%---%
%-%%%-%%%%%-%%%%%%%%%-%%%%%-%-%-%%%-%
%-%---%------%--------%-----%-------%
%-%-%-%%%%%-%%%-%-%-%-%-%%%%%%%%%%%%%
%-%-%---%-----%-%-%-%-------%---%-%-%
%-%-%%%-%%%-%-%-%-%%%%%%%%%-%%%-%-%-%
%-%---%-%---%-%-%---%-%---%-%-%-----%
%-%%%-%%%-%%%%%-%%%-%-%-%%%%%-%-%%%%%
%-------%---%-----%-%-----%---%-%---%
%%%-%-%%%%%-%%%%%-%%%-%%%-%-%%%-%-%%%
%-%-%-%-%-%-%-%-----%-%---%-%---%-%-%
%-%-%%%-%-%-%-%-%%%%%%%%%-%-%-%-%-%-%
%---%---%---%-----------------%-----%
%-%-%-%-%%%-%%%-%%%%%%%-%%%-%%%-%%%-%
%.%-%-%-------%---%-------%---%-%--P%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Your program is almost correct. The problem arises from using in_array() for looking up a node in $arr_close or $arr_open, because in_array() compares not only the position $x, $y, but also the other Node members $fCost, $hCost, $gCost ...; thus it doesn't recognize that a node is already in the closed set of nodes already evaluated if those other members differ, and gets to evaluate it repeatedly.
A quick fix is to use instead of in_array() a self-defined function that as needed only compares the $x, $y members:
function in($node, $arr)
{
foreach ($arr as &$member)
if ($member->x == $node->x && $member->y == $node->y) return TRUE;
return FALSE;
}
I get the following error when I try to paginate in Laravel 5.2.
BadMethodCallException in Macroable.php line 81: Method paginate does
not exist.
And code:
Illuminate\Contracts\Pagination\Paginator;
...
$count = 0;
$gdprecords = Gdprecord::all();
foreach($gdprecords as $gdprecord) {
$count++;
$Pa = $gdprecord->adultpopulation;
$Pc = $gdprecord->childpopulation;
$P = $Pa + $Pc; // total population
$T = ($gdprecord->gdpcapita * $P) * $gdpratio; // basic income for country
if($bi_ratio == 0) {
$gdprecord->bi_adult = round($T / $Pa, 2);
} else {
$gdprecord->bi_adult = round($T / ($Pa + ($Pc / $bi_ratio)), 2);
}
$gdprecord->bi_adult_monthly = round($gdprecord->bi_adult / 12, 2);
$gdprecord->bi_adult_daily = round($gdprecord->bi_adult / 365, 2);
if($bi_ratio == 0) {
$gdprecord->bi_child = 0;
} else {
$gdprecord->bi_child = round($gdprecord->bi_adult / $bi_ratio, 2);
}
$gdprecord->bi_child_monthly = round($gdprecord->bi_child / 12, 2);
$gdprecord->bi_child_daily = round($gdprecord->bi_child / 365, 2);
}
$sorted_gdprecords = $gdprecords->sortByDesc('bi_adult')->paginate(25);
I don't want to paginate until after the array has been sorted. How do I make this work?
Thanks, Philip
Here is a solution I found, borrowing code from someone else:
public function paginate($items,$perPage)
{
$pageStart = \Request::get('page', 1);
// Start displaying items from this number;
$offSet = ($pageStart * $perPage) - $perPage;
// Get only the items you need using array_slice
$itemsForCurrentPage = array_slice($items, $offSet, $perPage, true);
return new LengthAwarePaginator($itemsForCurrentPage, count($items), $perPage,Paginator::resolveCurrentPage(), array('path' => Paginator::resolveCurrentPath()));
}
and add this code:
$gdprecords2 = $gdprecords->sortByDesc('bi_adult')->all();
$perPage = 25;
$sorted_gdprecords = self::paginate($gdprecords2, $perPage);
Thanks for your help. -Philip
Ok, I don't even know where to start with this one! I'll try and explain what I want to achieve, and we'll go from there....
I have a list of dates each with an associated number, say from 20-100. What I want to do is to output the date in a shade which represents the associated number. So 20 would display in a light blue and 100 in a dark blue. My code so far looks like this...
dateArray = Array('2001-01-01'=>30, '2001-02-01'=>40, '2001-03-01'=>50, '2001-04-01'=>60, '2001-05-01'=>70, '2001-06-01'=>80, '2001-07-01'=>90, '2001-08-01'=>90, '2001-09-01'=>80, '2001-10-01'=>70, '2001-11-01'=>60, '2001-12-01'=>50)
$maxNum = max($dateArray);
$minNum = min($dateArray);
foreach($dateArray AS $date => $num){
$lightest = 'rgb(204,204,255)';
$darkest = 'rgb(0, 0, 179)';
///magic that converts $num into $shade goes here///
echo "<span style='color:$shade'>$date</span><br>"
}
Any ideas? Thanks
I would do something like that :
$dateArray = Array('2001-01-01'=>30, '2001-02-01'=>40, '2001-03-01'=>50, '2001-04-01'=>60, '2001-05-01'=>70, '2001-06-01'=>80, '2001-07-01'=>90, '2001-08-01'=>90, '2001-09-01'=>80, '2001-10-01'=>70, '2001-11-01'=>60, '2001-12-01'=>50)
// get max and min values
$maxNum = max($dateArray);
$minNum = min($dateArray);
// set rgb values for max and min
$lightest = array(204, 204, 255);
$darkest = array(0, 0, 179);
foreach($dateArray AS $date => $num)
{
// get a "delta" where the current num value is
$delta = ($num / $maxNum) - $minNum;
// get a pro-rata values thanks to $delta
$shadesNum = array(
$delta * ($lightest[0] - $darkest[0]) + $darkest[0],
$delta * ($lightest[1] - $darkest[1]) + $darkest[1],
$delta * ($lightest[2] - $darkest[2]) + $darkest[2]
);
echo "<span style='rgb(".implode(',', $shadesNum).")'>$date</span><br>";
}
Some languages have a "lerp" function - linear interpolation. Quite useful.
My suggestion:
for ($x1=20; $x1<=100; $x1+=10)
echo $x1 . ": " . getshade($x1) . "<br />\n";
function getshade($num) {
$rlight = 204;
$glight = 204;
$blight = 255;
$rdark = 0;
$gdark = 0;
$bdark = 179;
$lightnum = 20;
$darknum = 100;
$k01 = ($num-$lightnum)/($darknum-$lightnum); // 0 to 1
$rshade = ilerp($rlight, $rdark, $k01);
$gshade = ilerp($glight, $gdark, $k01);
$bshade = ilerp($blight, $bdark, $k01);
return "rgb($rshade,$gshade,$bshade)"; }
function lerp($start, $end, $k01) { // linear interpolation
return $k01*$end + (1.0-$k01)*$start; }
function ilerp($start, $end, $k01) { // integer lerp
return intval($k01*$end + (1.0-$k01)*$start); }
EDIT: Same thing but better:
$rgblight = [204,204,255];
$rgbdark = [0,0,179];
$numlight = 20;
$numdark = 100;
for ($x1=20; $x1<=100; $x1+=10)
echo $x1 . ": " . getshade2($x1, $numlight, $numdark, $rgblight, $rgbdark) . "<br />\n";
function getshade2($num, $numlight, $numdark, $rgblight, $rgbdark) {
$k01 = ($num-$numlight)/($numdark-$numlight);
for ($i1=0; $i1<3; $i1+=1)
$rgb[$i1] = ilerp($rgblight[$i1], $rgbdark[$i1], $k01);
return "rgb({$rgb[0]},{$rgb[1]},{$rgb[2]})"; }
I'd like help getting this PHP function to work with a third color option.
Note: No CSS. No Javascript. Just PHP and HTML.
<?php
function Gradient($HexFrom, $HexTo, $ColorSteps)
{
$FromRGB['r'] = hexdec(substr($HexFrom, 0, 2));
$FromRGB['g'] = hexdec(substr($HexFrom, 2, 2));
$FromRGB['b'] = hexdec(substr($HexFrom, 4, 2));
$ToRGB['r'] = hexdec(substr($HexTo, 0, 2));
$ToRGB['g'] = hexdec(substr($HexTo, 2, 2));
$ToRGB['b'] = hexdec(substr($HexTo, 4, 2));
$StepRGB['r'] = ($FromRGB['r'] - $ToRGB['r']) / ($ColorSteps - 1);
$StepRGB['g'] = ($FromRGB['g'] - $ToRGB['g']) / ($ColorSteps - 1);
$StepRGB['b'] = ($FromRGB['b'] - $ToRGB['b']) / ($ColorSteps - 1);
$GradientColors = array();
for($i = 0; $i <= $ColorSteps; $i++)
{
$RGB['r'] = floor($FromRGB['r'] - ($StepRGB['r'] * $i));
$RGB['g'] = floor($FromRGB['g'] - ($StepRGB['g'] * $i));
$RGB['b'] = floor($FromRGB['b'] - ($StepRGB['b'] * $i));
$HexRGB['r'] = sprintf('%02x', ($RGB['r']));
$HexRGB['g'] = sprintf('%02x', ($RGB['g']));
$HexRGB['b'] = sprintf('%02x', ($RGB['b']));
$GradientColors[] = implode(NULL, $HexRGB);
}
return $GradientColors;
}
$text = "blah testing blah testing blah";
$length = strlen($text);
$Gradients = Gradient("00FF00", "0000FF", $length);
for ($i=0; $i<$length; $i++) {
echo '<span style="color: #' . $Gradients[$i] . ';">' . $text[$i] . '</span>';
}
?>
What must I do to get a 3rd option? Such as:
Gradient($HexOne, $HexTwo, $HexThree, $ColorSteps)
//^^^^^^^^^
This should work for you:
So basically what I just added is, that if you provide more than 2 colors, that it simply merges the first gradient with the next one until you have all gradients which you want together. It also allows you to have different steps for each gradient which you have. So you can define that it should go from green to red in 20 steps and from red to blue in 50 steps.
You can either pass the colors as array and the steps as array or integer when you take an instance of the class. Or you can use the methods setColors() to set the array of colors and setSteps() to set the array or integer as interval.
You can also define if the gradient should be chunked or not if you have multiple colors. You can set and get the value if it should get chunked with setChunkedGradientState() and getChunkedGradientState(). This simply means if you don't want the gradient chunked, which is the default value, you will get an array like this:
Array
(
[0] => FD9B09
[1] => EBAE1C
[2] => D9C230
[3] => C7D544
[4] => B6E958
[5] => B6E958
[6] => A9EC8D
[7] => 9CEFC2
[8] => 8FF2F8
)
If it should be chunked you will get an array like this:
Array
(
[0] => Array
(
[0] => FD9B09
[1] => EBAE1C
[2] => D9C230
[3] => C7D544
[4] => B6E958
)
[1] => Array
(
[0] => B6E958
[1] => A9EC8D
[2] => 9CEFC2
[3] => 8FF2F8
)
)
full code:
<?php
class Gradienter {
public $colors = [];
public $gradient = [];
public $colorSteps = 2;
public $chunkedGradient = FALSE;
public function __construct(array $colors = [], $colorSteps = 2, $chunkedGradient = FALSE) {
$this->setColors($colors);
$this->setSteps($colorSteps);
$this->setChunkedGradientState($chunkedGradient);
return $this;
}
public function getGradient() {
if(count($this->colors) == 2) {
$this->createSingleGradient();
} elseif(count($this->colors) > 2) {
$this->createMultipleGradient();
} else {
throw new Exception("Not enough colors provided");
}
if($this->chunkedGradient)
$this->getChunkedGradient();
return $this->gradient;
}
public function getChunkedGradient() {
$stepCount = count($this->colors) - 1;
for($count = 0; $count < $stepCount; $count++) {
if(!is_array($this->colorSteps))
$gradient[] = array_splice($this->gradient, 0, $this->colorSteps);
elseif(!isset($this->colorSteps[$count]))
$gradient[] = array_splice($this->gradient, 0, 2);
else
$gradient[] = array_splice($this->gradient, 0, $this->colorSteps[$count]);
}
$this->gradient = $gradient;
}
public function createSingleGradient() {
if(!is_array($this->colorSteps))
$this->$gradient = $this->createGradient($this->colors[0], $this->colors[1], $this->colorSteps);
else
$this->$gradient = $this->createGradient($this->colors[0], $this->colors[1], $this->colorSteps[0]);
}
public function createMultipleGradient() {
foreach($this->colors as $k => $color) {
if(!isset($this->colors[$k+1]))
break;
if(!is_array($this->colorSteps))
$this->gradient = array_merge($this->gradient, $this->createGradient($this->colors[$k], $this->colors[$k+1], $this->colorSteps));
elseif(isset($this->colorSteps[$k]))
$this->gradient = array_merge($this->gradient, $this->createGradient($this->colors[$k], $this->colors[$k+1], $this->colorSteps[$k]));
else
$this->gradient = array_merge($this->gradient, $this->createGradient($this->colors[$k], $this->colors[$k+1], 2));
}
}
public function createGradient($start, $end, $interval) {
$colors = ["r", "g", "b"];
list($colorStart["r"], $colorStart["g"], $colorStart["b"]) = array_map("hexdec", str_split($start, 2));
list($colorEnd["r"], $colorEnd["g"], $colorEnd["b"]) = array_map("hexdec", str_split($end, 2));
foreach($colors as $color)
$colorSteps[$color] = ($colorStart[$color] - $colorEnd[$color]) / ($interval - 1);
for($count = 0; $count < $interval; $count++) {
foreach($colors as $color)
$rgb[$color] = floor($colorStart[$color] - ($colorSteps[$color] * $count));
$hexRgb = array_combine($colors, array_map(function($v){
return substr(sprintf('%02X', $v), 0, 2);
}, $rgb));
$GradientColors[] = implode("", $hexRgb);
}
return $GradientColors;
}
public function setColors(array $colors = []) {
$this->colors = $colors;
return $this;
}
public function getColors() {
return $this->colors;
}
public function setSteps($colorSteps = 2) {
if(!is_array($colorSteps))
$this->setSingleColorSteps($colorSteps);
else
$this->setMultipleColorSteps($colorSteps);
return $this;
}
public function setSingleColorSteps($colorSteps) {
$this->colorSteps = intval($colorSteps < 2 ? 2 : $colorSteps);
}
public function setMultipleColorSteps($colorSteps) {
$this->colorSteps = array_map(function($v){
return intval($v < 2 ? 2 : $v);
}, $colorSteps);
}
public function getSteps() {
return $this->colorSteps;
}
public function setChunkedGradientState($chunkedGradient) {
$this->chunkedGradient = $chunkedGradient;
return $this;
}
public function getChunkedGradientState() {
return $this->chunkedGradient;
}
}
$gradienter = new Gradienter();
$gradienter->setColors(["FD9B09", "B6E958", "F2F90B", "8FF2F8", "FB8CF8", "F05C3E"]);
$gradienter->setSteps([5, 30, 25, 60, 40]);
$gradients = $gradienter->getGradient();
foreach($gradients as $k => $color)
echo "<div style='background-color:#" . $color . "'>" . $color . "</div>";
?>
Demo 1
Demo 2
A little background
I am attempting to migrate a project built with Symfony 1.2 from one server to another. One of the functions of the project is to build a graph (originally done with JpGraph 2.3.5).
The graph does not display as intended without modifications to the code and am looking for some insight on what I might be overlooking. Images are linked due to not having enough points to post. Graph Image Gallery
The following graph is what is generated by the code block below
<?php
public function Graph($section) {
$report = $section->getReport();
$this->crews = array();
foreach ($section->getCrews() as $crew) {
$this->crews[$crew->getId()] = $crew;
};
# get the data
$nextDayValues = $section->getNextDayValues();
$nextDayValueLabels = $section->getNextDayValueLabels();
$max_y = max($nextDayValues) < 7 ? 7 : max($nextDayValues);
$this->crew_order = array_keys($nextDayValues);
$this->summary = $this->getSummary();
$this->bar_count = count($this->crews) + count($this->summary);
$left = 200;
$right = 30;
$top = 60;
$bottom = 80;
$width = 640;
$height = $top + $bottom + ($this->bar_count * 30 );
$x_unit = $this->bar_count / ($height - $top - $bottom);
$y_unit = $max_y / ($width - $left - $right);
$csim_targets = array();
$csim_alts = array();
$bar_data = array();
$max_days = 0;
foreach ($this->crew_order as $i => $crew_id) {
$csim_targets[$i] = url_for('units/index?crew_id='.$crew_id);
$csim_alts[$i] = sprintf("Units for %s",
$this->crews[$crew_id]->getCrew());
# figure out the maximum y value
$nextDayUnitsList = $this->crews[$crew_id]->getNextDayUnitsList();
$units_array[$crew_id] = $nextDayUnitsList;
if (count($nextDayUnitsList) > $this->max_days) {
$this->max_days = count($nextDayUnitsList);
};
};
$bg_values = array_values($nextDayValues);
foreach ($this->summary as $summary) {
array_push ($bg_values, $summary['value']);
};
$bg_bar = new BarPlot($bg_values);
$bg_bar->SetCSIMTargets($csim_targets, $csim_alts);
$bg_bar->SetNoFill(true);
$fg_bars = $this->getFgBars($units_array);
$fg_bar = new AccBarPlot($fg_bars);
$fg_bar->SetFillColor('black');
# initialize the graph
$graph = new Graph($width, $height, 'auto');
$graph->SetScale('textlin', 0, $max_y, 0, $this->bar_count);
$graph->Set90AndMargin($left, $right, $top, $bottom);
$graph->SetMarginColor('white');
$graph->SetFrame(false);
$graph->Add($fg_bar);
$graph->Add($bg_bar);
# add text labels
foreach ($this->crew_order as $i => $crew_id) {
$label = $this->value_label(
$nextDayValueLabels[$crew_id],
$i, $nextDayValues[$crew_id],
10 * $x_unit, 5 * $y_unit
);
$graph->AddText($label);
};
foreach ($this->summary as $i => $summary) {
$label = $this->value_label(
$summary['value'],
$i, $summary['value'],
10 * $x_unit, 5 * $y_unit
);
$graph->AddText($label);
};
# add title
$graph->title->Set(sprintf("%s - %s", $report->getName(),
$section->getName()));
$graph->title->SetFont(FF_VERDANA,FS_BOLD, 12);
$graph->title->SetMargin(10);
# add subtitle
$graph->subtitle->Set(date('d-M-Y g:ia'));
$graph->subtitle->SetFont(FF_VERDANA,FS_BOLD, 8);
# configure x-axis
$graph->xaxis->SetFont(FF_VERDANA, FS_NORMAL, 8);
$graph->xaxis->SetLabelAlign('right', 'center');
$graph->xaxis->SetLabelFormatCallback(array($this, 'x_axis_label'));
$graph->xaxis->scale->ticks->Set(1, 0);
# configure y-axis
$graph->yaxis->SetFont(FF_VERDANA, FS_NORMAL, 8);
$graph->yaxis->SetLabelAlign('center', 'top');
$graph->yaxis->SetLabelAngle(45);
$graph->yaxis->SetLabelFormatCallback(array($this, 'y_axis_label'));
$graph->yaxis->SetPos('max');
$graph->yaxis->SetLabelSide(SIDE_RIGHT);
$graph->yaxis->SetTickSide(SIDE_LEFT);
if (max($nextDayValues) > 28) {
$graph->yaxis->scale->ticks->Set(7, 1);
} else {
$graph->yaxis->scale->ticks->Set(1, 1);
};
# configure legend
$graph->legend->SetAbsPos(5, $height - 5, "left", "bottom");
$graph->legend->SetColumns(count($this->legend));
$graph->legend->SetFillColor('white');
$graph->legend->SetShadow(false);
$graph->SetImgFormat('png');
return $graph;
}
private function getFgBars($units_array) {
# initialize fg_bar data
$empty_crews = array_fill_keys(array_keys($this->crew_order),0);
# add segment bars
foreach ($this->summary as $summary) {
$empty_crews[] = 0;
};
$empty_segment = array();
foreach (array_keys($this->legend_colors) as $status) {
$empty_segment[$status] = $empty_crews;
};
$segments = array();
for ($day = 0; $day < $this->max_days; $day++) {
foreach (array_keys($empty_segment) as $status) {
$segment = $empty_segment;
foreach ($this->crew_order as $i => $crew_id) {
$nextDayUnitsList = $units_array[$crew_id];
if ($day + 1 < count($nextDayUnitsList)) {
$units = $nextDayUnitsList[$day];
$units_status = $units->getNextDayStatus();
$segment[$units_status][$i] = 1;
} elseif ($day + 1 == count($nextDayUnitsList)) {
$units = $nextDayUnitsList[$day];
$units_status = $units->getNextDayStatus();
$avail = $units->getUsedRatio();
$segment[$units_status][$i] = $avail;
} elseif ($day + 1 > count($nextDayUnitsList)) {
$segment[$units_status][$i] = 0;
};
};
};
foreach ($this->summary as $i => $summary) {
$diff = $summary['value'] - $day;
if ($diff >= 1) {
$segment['summary'][$i] = 1;
} elseif ($diff >= 0) {
$segment['summary'][$i] = $diff;
} else {
$segment['summary'][$i] = 0;
}
};
$segments[$day] = $segment;
};
# create legend
$fg_bars = array();
foreach (array_keys($empty_segment) as $status) {
$fg_bar = new BarPlot($empty_crews);
$fg_bar->setFillColor($this->legend_colors[$status]);
if ($status <> 'summary') {
$fg_bar->SetLegend($this->legend[$status]);
};
$fg_bars[] = $fg_bar;
};
# add segments
foreach ($segments as $day => $segment) {
foreach (array_keys($empty_segment) as $status) {
$fg_bar = new BarPlot($segment[$status]);
$fg_bar->setColor($this->legend_colors[$status]);
$fg_bar->setFillColor($this->legend_colors[$status]);
$fg_bars[] = $fg_bar;
};
};
return $fg_bars;
}
?>
Now the same graph on the new server using JpGraph 2.3.5 or JpGraph 3.5.0b1
A few problems can be seen:
Colours are not applied
x/y coord are offset (margins?)
scale is off
scale ticks are also removed
I am aware that to correct the colour you place $graph->Add($x); before modifying the properties. As such I had to move the code within the getFgBars() into Graph().
Which is documented in the manual under /docs/chunkhtml/ch29s02.html
With revising the code I broke apart the FgBars into $fg_bars[] & $lg_bars[] being the foreground data (color) & Legend bar.
If I remove the legend bar, the graph is displayed as intended.
Question:
What would be causing the margin / scale to go wonkey when adding on a second AccBarPlot()?
Solution:
Remove default theme. $graph->graph_theme = null; will restore both colour & margins without requiring to rewrite any code.
# initialize the graph
$graph = new Graph($width, $height, 'auto');
$graph->SetScale('textlin', 0, $max_y, 0, $this->bar_count);
$graph->Set90AndMargin($left, $right, $top, $bottom);
$graph->SetMarginColor('white');
$graph->SetFrame(false);
$graph->graph_theme = null;
Solution:
Remove default theme. $graph->graph_theme = null; after initalizing Graph() will restore both colour & margins without requiring to rewrite any code.
# initialize the graph
$graph = new Graph($width, $height, 'auto');
$graph->SetScale('textlin', 0, $max_y, 0, $this->bar_count);
$graph->Set90AndMargin($left, $right, $top, $bottom);
$graph->SetMarginColor('white');
$graph->SetFrame(false);
$graph->graph_theme = null;
Resources:
/docs/chunkhtml/ch29.html#id2619634 - The order of SetTheme() and changing settings
/docs/chunkhtml/ch29s02.html - Changing the display settings of line/bar graphs