Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

JPGraph Data Help

Status
Not open for further replies.

PCHomepage

Programmer
Feb 24, 2009
609
US
Using the JPGraph 3.5 scatter graph, I have it working and recieving data but I am not sure how to do multiple sets of data in different colors on top of each other.

The MySQL data consists of ID, FileID, DataX and DataY. The ID field can be ignored but when FileID switches from one value to the next, the graph needs to change too but right now it is all on top of each other. That is, the FileID is what differenciates between the data that needs to go into individual plots.

The mysqli query is looping through the data with:

Code:
while ($row = $result->fetch_array()) {
   $datax[] = $row[2];
   $datay[] = $row[3];
}

and the data is being fed to JPGraph through a custom function with:

Code:
Scatterplot($datay, $datax, $JPGraphPath);

but how can I trigger something within the function so that it will know when the FileID is the next one and set the appropriate colors etc. for the overlay? It probably doesn't need more than five or six different plots since more would be unreadable anyway. Thank you.
 
Actually this is more of an array issue as I'm not sure how to match the values with each other inside the function so that I can separate out dynamic values for $datax1, $datay1, $datax2, $datay2 etc. To get the needed ID into the function, I modified it slightly:

Code:
Scatterplot($DataID, $datay, $datax, $JPGraphPath, $_POST['Filename'], $ProcessType);

and the array is being generated with:

Code:
if ($result = $mysqli->query("$Query")) {
     while ($row = $result->fetch_array()) {
	$dataID[] = $row[1];
	$datax[] = $row[2];
	$datay[] = $row[3];
     }
	
   $result->close();
} else {
     printf("MySQLi Error: %s\n", $mysqli->error);
}

Any ideas?
 
please provide the 'custom' function scatterplot(). the normal way of generating the scatterplot is to create a scatterplot object and pass the x and y data arrays only.
 
Here's the function, which is fairly straightforward and working. The problem is that there should be multiple sets of data in the graph (up to five or maybe six) but they all show on top of each other in the same color since there is nothing to differentiate them:

Code:
function Scatterplot($DataID, $datay, $datax, $JPGraphPath, $FileName, $ProcessType) {
	require_once ($JPGraphPath."/jpgraph.php");
	require_once ($JPGraphPath."/jpgraph_scatter.php");

	$graph = new Graph(800,450);
	$graph->SetImgFormat('png',60);

	$graph->SetScale("intlin",0,0,0,800);

	$graph->img->SetMargin(100,40,40,75);
	$graph->SetShadow();

	$graph->title->Set($ProcessType." Data");
	$graph->title->SetFont(FF_ARIAL,FS_BOLD,18);

	// Set Y-Axis appearance
	$graph->yaxis->SetTitle("Y Graph Values",'middle');
	$graph->yaxis->scale->ticks->Set(1000,25);	
	$graph->yaxis->title->SetFont(FF_ARIAL,FS_BOLD,10);
	$graph->yaxis->title->SetMargin(50);

	// Set X-Axis title
	$graph->xaxis->SetTitle("X Graph Scale'middle');
	$graph->xaxis->scale->ticks->Set(100,25);	
	$graph->xaxis->title->SetFont(FF_ARIAL,FS_BOLD,10);
	$graph->xaxis->title->SetMargin(20);

	$graph->ygrid->Show(true,false);
	$graph->xgrid->Show(true,false);	

	$sp1 = new ScatterPlot($datay,$datax);
	$graph->Add($sp1);
	$sp1->SetColor("red");
	$sp1->SetLegend("SP1");

	// Produce an image, display the graph
	$fileName = $JPGraphPath."/Temp/".$FileName.".png";	
        $graph->Stroke($fileName); // Creates image file

	$OutputImage = "<div class=\"ImageGraph\">\n";
	$OutputImage .= "<img src=\"jpgraph/Temp/".$FileName.".png\">\n";
	$OutputImage .= "</div>\n\n";

	clean_old_tmp_files(); // not working
	unlink($FileName); // not working

	echo $OutputImage;
}

Also (and this IS a JPGraph question!), I need a very specific Y-axis scale of 1; 10; 100; 1000; 10000; 100000; 1000000 but can find nothing to say how to do it. It's not a matter of having it start at 1 and end at 1000000 but the steps in between have to be specific to these values. Can it be done and how?
 
I am very surprised that the code above works as the filename that the output is actually stored in is in the variable $fileName whereas you are serving an image with the variable reference $FileName. the capitalisation changes the image value (and also explains why your unlink line is not working).

the data code is correct. the only variables that are important are the arrays of x and y values

for the second question on y-axis values change the setScale argument to intlog
 
Yes, I noticed that and meant to change it but haven't had a chance. The variable names were a little too close to be comfortable. That aside (and it is working), but how do I make it internally see when the FileID value changes from one to the next so that the second graph and so on get individual colors?
 
Thank you again for your excellent help. So with SetScale to intlog, how can the specific increments by added or does it do so automatically? I see no facility in any of the documentation for doing do. In any event, with jpgraph_log.php included in and SetScale argument to intlog, it crashes without any error. Only the page's header appears.

You were right about unlink. Now it works - too well - so I had to remark it out. It was deleting the file before it could be presented to the screen! Ultimately, these graphs will probably need to be saved anyway so it's not a problem.
 
second graph? are you trying to present multiple scatter plots on the same canvas?

intlog will plot an integer scale on the x axis and a logarithmic scale on the y axis. by default the scale should be 10,100,1000 etc (
if there is a crash without an error then you should

1. turn on error reporting
2. turn on error logging
3. check your logs.

the first two are done in php.ini.

you can also cause jpgraph to display errors by editing the conf file and enabling INSTALL_PHP_ERR_HANDLER and CATCH_PHPERR
 
Thanks. Because I've got it set up as a function and have only a single streams for X and Y coming into JPGraph, it contains results from multiple tests all in the same stream. The intent of feeding in the FileID calue was to try to use it somehow to separate teh date back into the individual tests so that each could have its own plot because each test's graph needs to be in a separate color. If it is not, they are all on top of each other and in the same color. In fact, I seem unable to even change the one color. I have it set now to red but it still gives the default, which appears to be blue.

For enabling the intlog, All the PHP errors are enabled and JPGraph always gives good on-screen error reporting too but not this time. There is just nothing after the page header and title. As for the logs, I'm not sure I have access to them but I'll try it at home on my own development system where I know I do. The default scale is okay except that I need it to start at 1 and go to 1000000 specifically but I've got to get it working first!
 
instead of using a fileID make each of $datay and datax multidimenstional arrays. then in your receiving function do this

Code:
$colours = array('red','green','blue','purple','black','yellow','lightblue');
foreach($datay as $key=>$_datay):
 $sp[$key] = new ScatterPlot($_datay,$datax[$key]);
 $graph->Add($sp[$key]);
 $sp[$key]->mark->SetFillColor( isset($colours[$key]) ? $colours[$key] : $colours[0]    );
 $sp[$key]->SetLegend("SP" . ($key+1) );
 //delete the next three lines if you don't want the plot points to be linked
 $sp[$key]->link->show();
 $sp[$key]->link->setWeight(1);
 $sp[$key]->link->setColor(  isset($colours[$key]) ? $colours[$key] : $colours[0]   );
endforeach;

to set a mandatory scale
Code:
$graph->yaxis->scale->SetAutoMin(0);
$graph->yaxis->scale->SetAutoMax(1000000);

if nothing is coming out of the page then there may be a syntax error which will cause the page to bug out without errors on some systems. the way to avoid this is to create another script that has this in it
Code:
error_reporting (E_ALL);
ini_set('display_errors', true);
require '/path/to/bugging/script.php';
this is because the above script contains no errors and the includes are not parsed until they are required. at that stage the directives to report and display errors are in play.

another potential problem with jpgraph is memory usage. i have found in the past the need to give php a lot of memory when manipulating graphs. you should get a warning with this code though.
 
That sounds great, thank you! I'll try it tomorrow. Somehow I still need the FileID because I'll need it to fetch the file name from another table to present it in the color key. I guess that bridge can be crossed when I get to it.
 
It is now giving a most colorful legend but I am unsure how to convert my data into a multi-dimensional array since it's coming from the same two columns of the same table nor am I clear how to us the FileID to extract the name of the file for use in the legend. That is, I know how to do the query but I am not sure on what to query!
 
Code:
//assume columns are fileid, datax, datay
$sql = "select fileid, datax, datay from tablename";
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)):
 $datax[$row[0]][] = $row[1];
 $datay[$row[0]][] = $row[2];
endwhile;
 
Thank you! Modifying the code slightly to match the others on the site, I now have this:

Code:
if ($result = $mysqli->query("$sql")) {
	while($row = $result->fetch_array()):
		$datax[$row[0]][] = $row[1];
		$datay[$row[0]][] = $row[2];
	endwhile; 
		$result->close();
} else {
	printf("MySQLi Error: %s\n", $mysqli->error);
}

. . . and in the test page for the plot, the legend now shows only the three entries just as it should for the three sets of data being fed in so that's exactly right!

I'm not sure how, but for the legend I need to get the FileName itself so I tried replacing DataID with FileName by writing a joined query. It does indeed give the file name as the key but all legend and graph values are red so is it better to revert to the DataID, then add another query within the function to obtain the name?

On the intlog issue, my development system here at home has all errors enabled so with the intlog on, the first error it gave was for an undefined function:

Code:
Fatal error: Call to undefined method LogTicks::Set()

With that line remarked out, it then gave a memory error:

Code:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 24 bytes)

Since this does not involve much data, the memory issue seemed rather odd so I must have been calling it incorrectly with:

Code:
$graph->SetScale("linlog",1,1000000,0,800);

As soon as I removed the x and y limits, there were no more memory errors:

Code:
$graph->SetScale("linlog");

However, the y axis does not have the names it needs of 1, 10, 100, 1000 etc. Instead it has 10^0, 10^1, 10^2, 10^3 etc.

On the colors and when using DataID, it seems to be jumping directly to the third, fourth and fifth, which are all relatively dark and difficult to differentiate. I know I can reorganize them in the array but I am curious if there is a way to pick them from the beginning using the actual order in which they are. Right now the plot shows [bold]'blue','purple','black'[/bold] while the array has [bold]'red','green','blue','purple','black','yellow','lightblue'[/bold]

Thank you again for all your help!
 
After posting I found the JPGraph setting for formatting the display value of Y:

Code:
$graph->yaxis->SetLabelFormatCallback('number_format');

Now that I know it exists, I'll see what I can find one that presents it without the commas but this is great for now.
 
Since I know MySQL better than I do arrays, I went ahead and added a lookup query to the $key array which fetches very nicely the file name(s) for display in the legend.

Code:
foreach($datay as $key=>$_datay):
	$queryFN = "SELECT FileName FROM file_uploads WHERE ID = ".$key." ORDER by FileName";
		if ($result = $mysqli->query($queryFN)):
			$row = $result->fetch_row();
			$FileName = $row[0];
			$result->close();
		endif;
	$sp[$key] = new ScatterPlot($_datay,$datax[$key]);
	$graph->Add($sp[$key]);
	$sp[$key]->mark->SetFillColor( isset($colors[$key]) ? $colors[$key] : $colors[0]);
	$sp[$key]->SetLegend(basename($FileName, ".csv"));
	// Link plot points (unremark next three lines to use)
	//$sp[$key]->link->show();
	//$sp[$key]->link->setWeight(1);
	//$sp[$key]->link->setColor(  isset($colors[$key]) ? $colors[$key] : $colors[0]);
endforeach;

I just noticed, though that the X and Y gridlines are missing when they were there before. They should be visible with these current lines:

Code:
$graph->ygrid->Show(true,false);
$graph->xgrid->Show(true,false);

Also, the X-axis was incremented by 100 before but now it is in increments of 50 even with:

Code:
$graph->xaxis->scale->ticks->Set(100,25);

Although it doesn't need ticks, it does need both of the grids! Any ideas?
 
In a LinePlot graph, is there a similar way of graphing multiple columns of the same dataset while also being able to send multiple datasets to overlay it? I tried something like this but, of course, JPGraph protested because the X-axis and Y-axis did not match in the number of plot points:

Code:
while ($row = $result->fetch_array()) :
	$datax[$row[1]][] = $row[2];
	$datay[$row[1]][] = $row[3];
	$datay[$row[1]][] = $row[4];
endwhile;
 
The memory issues relate not to the data but the amount of memory it takes to build the canvas. Increase that for starters.

Don't use explicit scales. Use intlog or linlog and set an automax limit.

For the rest I'm on too small a screen to digest tonight.
 
That's fine as it's working now just as it should. Perhaps not the most elegant code but I thought I would share it here in case it helps anyone else. I have a number of graphs to do and the search page needs to be able to switch through them at will so it seemed better to create functions. It is posted here at the bottom.

The line plot I am working on now is causing issues as I'm not sure how to supply multiple lines to the same graph and to also supply multiple graphs at the same time on top of each other. In other words, each entry has five or six columns of data (not just a single X and a single Y) for each color and they need labels at the plot top (peaks) to differenciate them.

In the meantime, I am trying a simple Table Graph but have so far gotten nothing to appear although no errors either. The labels are hard-coded in an array while the data is dynamic so I merged arrays:

Code:
if ($result = $mysqli->query("$FullListQuery")) :
	$Captions = array('Filename','Column2','Column3','Column4','Column5','Column6','Column7','Column8');

	while ($row = $result->fetch_array()) :
		$datarow[$row[0]][] = $row[1];
		$datarow[$row[0]][] = $row[2];
		$datarow[$row[0]][] = $row[3];
		$datarow[$row[0]][] = $row[4];
		$datarow[$row[0]][] = $row[5];
		$datarow[$row[0]][] = $row[6];
		$datarow[$row[0]][] = $row[7];
		$datarow[$row[0]][] = $row[8];
		$datarow[$row[0]][] = $row[9];		
	endwhile;

	$data = array_merge($Captions,$datarow);
endif;

The above, though, is not totally multidimensional as the column values are not so I think it's confusing the graph. The function itself is:

Code:
function TableGraph($data, $JPGraphPath, $ProcessType) {
	require_once ($JPGraphPath."/jpgraph.php");
	require_once ($JPGraphPath."/jpgraph_canvas.php");
	require_once ($JPGraphPath."/jpgraph_table.php");
	
	$ImageName = rand();
	$graph = new CanvasGraph(70,50);
	//$graph->SetImgFormat('png',60);	
	
	foreach($data as $key=>$_data):
		$table = new GTextTable();
		$table->Set($data[$key]);
		$graph->Add($table);
	endforeach; 
	
	// Setup the basic table and data

	// Produce an image, display the graph
	$fileName = $JPGraphPath."/Temp/".$ImageName.".png";	
	$graph->Stroke($fileName); // Creates image file

	$OutputImage = "<div class=\"ImageGraph\">\n";
	$OutputImage .= "<img src=\"jpgraph/Temp/".$ImageName.".png\">\n";
	$OutputImage .= "</div>\n\n";

	echo $OutputImage;
}

Here is the working scatter plot function:

Code:
function Scatterplot($datay, $datax, $JPGraphPath, $ImageName, $ProcessType, $mysqli) {
	require_once ($JPGraphPath."/jpgraph.php");
	require_once ($JPGraphPath."/jpgraph_scatter.php");
	require_once ($JPGraphPath."/jpgraph_log.php");		

	$graph = new Graph(800,450);
	$graph->SetImgFormat('png',60);

	$graph->SetScale("linlog");
	
	$graph->yaxis->scale->SetAutoMin(0);
	$graph->yaxis->scale->SetAutoMax(1000000); 
	
	$graph->xaxis->scale->SetAutoMin(0);
	$graph->xaxis->scale->SetAutoMax(800); 
	
	//$graph->yaxis->SetLabelFormatString()
	$graph->yaxis->SetLabelFormatCallback('number_format');
	
	$graph->img->SetMargin(100,40,40,75);
	$graph->SetShadow();

	$graph->title->Set($ProcessType." Data");
	$graph->title->SetFont(FF_ARIAL,FS_BOLD,18);

	// Set Y-Axis appearance
	$graph->yaxis->SetTitle("Y-Axis",'middle');
	$graph->yaxis->title->SetFont(FF_ARIAL,FS_BOLD,10);
	$graph->yaxis->title->SetMargin(50);

	// Set X-Axis title
	$graph->xaxis->SetTitle("X-Axis", 'middle');
	$graph->xaxis->scale->ticks->Set(100,25);	
	$graph->xaxis->title->SetFont(FF_ARIAL,FS_BOLD,10);
	$graph->xaxis->title->SetMargin(20);

	$graph->ygrid->Show(true,false);
	$graph->xgrid->Show(true,false);

	// Plot multi-dimensional array as $datax and $datay
	$colors = array('yellow','black','blue','red','green','purple','lightblue');	

	foreach($datay as $key=>$_datay):
		// Query to fetch legend file name from dcs_uploads table
		$queryFN = "SELECT FileName FROM file_uploads WHERE ID = ".$key." ORDER by FileName";
			if ($result = $mysqli->query($queryFN)):
				$row = $result->fetch_row();
				$FileName = $row[0];
				$result->close();
			endif;
		$sp[$key] = new ScatterPlot($_datay,$datax[$key]);
		$graph->Add($sp[$key]);
		$sp[$key]->mark->SetFillColor( isset($colors[$key]) ? $colors[$key] : $colors[0] );
		$sp[$key]->SetLegend(basename($FileName, ".csv"));
	
		// Link plot points (unremark next three lines to use)
		//$sp[$key]->link->show();
		//$sp[$key]->link->setWeight(1);
		//$sp[$key]->link->setColor(  isset($colors[$key]) ? $colors[$key] : $colors[0]   );
	endforeach; 
	
	// Produce an image, display the graph
	$fileName = $JPGraphPath."/Temp/".$ImageName.".png";	
	$graph->Stroke($fileName); // Creates image file

	$OutputImage = "<div class=\"ImageGraph\">\n";
	$OutputImage .= "<img src=\"jpgraph/Temp/".$ImageName.".png\">\n";
	$OutputImage .= "</div>\n\n";

	echo $OutputImage;
}
 
lots of questions in that one. a new problem might beget a new thread?

The line plot I am working on now is causing issues as I'm not sure how to supply multiple lines to the same graph and to also supply multiple graphs at the same time on top of each other. In other words, each entry has five or six columns of data (not just a single X and a single Y) for each color and they need labels at the plot top (peaks) to differenciate them.

you call this a line plot, but then talk about columns. do you mean a bar chart? or are you talking about a chart on which you wish to have plotted several lines based on similarly scaled data?

On the gtable question, could you try this instead
Code:
//get data
if ($result = $mysqli->query("$FullListQuery")) :
	$datay[] = array('FileName','Column2','Column3','Column4','Column5','Column6','Column7','Column8');
	while ($row = $result->fetch_array()) :
		$datay[] = $row;
	endwhile;
endif; 

function TableGraph($data, $JPGraphPath, $ProcessType ) {
	require_once ($JPGraphPath."/jpgraph.php");
	require_once ($JPGraphPath."/jpgraph_canvas.php");
	require_once ($JPGraphPath."/jpgraph_table.php");
	
	$ImageName = rand();
	$graph = new CanvasGraph(70,50);
	//$graph->SetImgFormat('png',60);	

	$table = new GTextTable();
	$table->Set($data);
	$graph->Add($table);
	 
	
	// Setup the basic table and data

	// Produce an image, display the graph
	$fileName = $JPGraphPath."/Temp/".$ImageName.".png";	
	$graph->Stroke($fileName); // Creates image file

	$OutputImage = "<div class=\"ImageGraph\">\n";
	$OutputImage .= "<img src=\"jpgraph/Temp/".$ImageName.".png\">\n";
	$OutputImage .= "</div>\n\n";

	echo $OutputImage;
}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top