Re: [Boston.pm] Pretty Graphs with Perl
OK, so I now have the graph being built and being displayed in my html through an image tag. I'm still trying out GD::Graph printing through an IMG tag calling my script for now. I will try other methods next. However, I'm having some difficulty putting dynamic data into the plots. For example. Say I read in my parameters handed into my graph-building script and produce these variables: # Width of graph my $width = $param{'width'}; # height of graph my $height = $param{'height'}; # Y Axis max value my $yMax = $param{'yMax'}; # Now let's setup the data for the graph: my @data = ([1st,2nd,3rd,4th,5th,6th,7th, 8th, 9th] ); # all datasets separated by :: my $ds=1; # dataset counter # go through each dataset one at a time. foreach my $dataset(split(/::/, $param{'x'})) { my $i=0; # Go through each item in the dataset foreach my $num (split(/,/, $dataset)) { $data[$ds][$i++] = $num; } $ds++; } For the sake of making things easier, let's say that each dataset has exactly 10 integers separated by commas, and there are 2 datasets. So $param{'x'} would look something like this: 1,2,3,4,5,6,7,8,9,10::13,12,10,8,8,6,4,3,1,0 I get a broken image when I try to execute this (with the rest of the code listed below). If I manually setup @data it works fine. But if I try to us the data sent to the script, then it doesn't work. I have tested @data to make sure that my info is being stored; I simply do a print statment and take a look at specific spots in @data, like $data[1][4]. It it DOES print out the correct value '5'. I've tried several methods, but for some reason I can't seem to put the data in correctly. I know I must be doing something silly and small. Any ideas? Thanks. --Alex P.S. Ann, you're probably right that at some point I will need to hand some of this information to my script differently, as I am likely to surpass the 2048 character limit. But for now I'm just doing tiny tests :) Code: -- my $graph = GD::Graph::lines-new($width, $height); $graph-set( x_label = $param{'xLabel'}, y_label = $param{'yLabel'}, title = $param{'title'}, # Show the grid long_ticks = 0, # Show values on top of each bar show_values = 1, # Draw datasets in 'solid', 'dashed', 'dotted' and 'dotted-dashed' lines line_types = [1, 2, 3, 4], # Set the thickness of line line_width = 1, # Setting the max Y value y_max_value = $yMax, # Setting the number of values to show on Y axis y_tick_number = $yMax, # skip every __ values to display on Y axis y_label_skip = 1, dclrs = ['blue', 'green', 'red', 'cyan'] ) or die $graph-error; my $format = $graph-export_format; print header(image/$format); binmode STDOUT; print $graph-plot([EMAIL PROTECTED])-$format(); On 12/6/05, Ricker, William [EMAIL PROTECTED] wrote: * *Does anyone who has/does use GD::Graph know if there's an easy way to * *embed the output graphs into HTML. * *Basically I'd like to be able to print a bunch of HTML, then the graph, * *then some more HTML. [WDR] The basic techniques are to either (a) img href=../graphs/123456789.png Generate the graph to a 2nd file named with a random number (for security) or a serial number (if no security needed) my $thisgraph; # uniq name $this_graph = sprintf %s/%d.png, $graphdir, rand($bignumber) while -r $thisgraph; print qq{img href=$this_graph size=$normal_size}; put_to_file($gd-png(), $this_graph); where put_to_file is something like (from GD::Image png method notes) sub put_to_file { my ($data, $fn)[EMAIL PROTECTED]; my $fh; open $fh, $fh or die; binmode $fh; print $fh $data or die; close $fh or die; } (b) img href=/scripts/imagemaker?x=17y=42title=%22Foo%20Bar%22xname=Xyname=Y Put the code that decides what to do from the Request in a module, and call it from both the CGI or action module that generates the HTML page (which generates the img link) and the CGI or action module that generates the dynamic graphic (in response to the img link). Some amount of setup work (varies with app) would have to be redone or saved in DB or some other place (with unique names!), but at least the code is reused in a module. In this case, you put all the request parameters that the graph module needs on the IMG URI, or copy all the request parms to be safe if you don't know; since it's a module, it should know. One module, one script could do both Page and Image requests, with a arg difference (or HTTP context wanting text/html or image/*?) determining which to generate. A has efficiency advantages in that any shared setup work for the page and the graphic is done once. B allows someone to statically deep link or bookmark an image.
Re: [Boston.pm] Pretty Graphs with Perl
On Wed, Dec 07, 2005 at 09:39:45AM -0500, Alex Brelsfoard wrote: my $ds=1; # dataset counter # go through each dataset one at a time. foreach my $dataset(split(/::/, $param{'x'})) { my $i=0; # Go through each item in the dataset foreach my $num (split(/,/, $dataset)) { $data[$ds][$i++] = $num; } $ds++; } For the sake of making things easier, let's say that each dataset has exactly 10 integers separated by commas, and there are 2 datasets. So $param{'x'} would look something like this: 1,2,3,4,5,6,7,8,9,10::13,12,10,8,8,6,4,3,1,0 The code seems to work fine for me, but I wonder why you don't just do this: foreach my $dataset (split /::/, $param{'x'}) { push @data, [split /,/, $dataset]; } I get a broken image when I try to execute this (with the rest of the code listed below). If I manually setup @data it works fine. But if I try to us the data sent to the script, then it doesn't work. I have tested @data to make sure that my info is being stored; I simply do a print statment and take a look at specific spots in @data, like $data[1][4]. It it DOES print out the correct value '5'. I've tried several methods, but for some reason I can't seem to put the data in correctly. If you're only looking at specific spots in @data, then you could be overlooking where the actual problem is. I'd suggest doing a dump of @data with Data::Dumper or Data::Dump. I'd also check for errors and warnings from the script, either in the web server logs or by running the script from the command line. Ronald ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm
Re: [Boston.pm] Pretty Graphs with Perl
Just replacing my dataset collection method with your dataset collection method seems to have fixed things up. Wonderful. Now I can really get testing! Thanks all. --Alex On 12/7/05, Ronald J Kimball [EMAIL PROTECTED] wrote: On Wed, Dec 07, 2005 at 09:39:45AM -0500, Alex Brelsfoard wrote: my $ds=1; # dataset counter # go through each dataset one at a time. foreach my $dataset(split(/::/, $param{'x'})) { my $i=0; # Go through each item in the dataset foreach my $num (split(/,/, $dataset)) { $data[$ds][$i++] = $num; } $ds++; } For the sake of making things easier, let's say that each dataset has exactly 10 integers separated by commas, and there are 2 datasets. So $param{'x'} would look something like this: 1,2,3,4,5,6,7,8,9,10::13,12,10,8,8,6,4,3,1,0 The code seems to work fine for me, but I wonder why you don't just do this: foreach my $dataset (split /::/, $param{'x'}) { push @data, [split /,/, $dataset]; } I get a broken image when I try to execute this (with the rest of the code listed below). If I manually setup @data it works fine. But if I try to us the data sent to the script, then it doesn't work. I have tested @data to make sure that my info is being stored; I simply do a print statment and take a look at specific spots in @data, like $data[1][4]. It it DOES print out the correct value '5'. I've tried several methods, but for some reason I can't seem to put the data in correctly. If you're only looking at specific spots in @data, then you could be overlooking where the actual problem is. I'd suggest doing a dump of @data with Data::Dumper or Data::Dump. I'd also check for errors and warnings from the script, either in the web server logs or by running the script from the command line. Ronald ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm
Re: [Boston.pm] Pretty Graphs with Perl
On Tue, 6 Dec 2005, Alex Brelsfoard wrote: I've got a project coming up that's going to need me to make graphs. I do not yet know what kind of graph (dot, line, bar, etc.). But I am told that it needs to be pretty (and probably with multiple colors). The data needing to be displayed will be anywhere from 5 points, to many thousands of points. There will be some times where I will need to have multiple datasets (separated by color) set on the same graph, one over the next. I was thinking of a brute-force way of doing this with associative arrays. But I was wondering if you all had any better suggestions. Are there any good, friendly, tested modules for this sort of thing? Is this a time for Perl tk? Would this be better off in Java? Have you looked at SVG::Graph or SVG::TT::Graph ? http://search.cpan.org/~allenday/SVG-Graph/Graph.pm http://search.cpan.org/~llap/SVG-TT-Graph/lib/SVG/TT/Graph.pm http://sourceforge.net/projects/svg-graph http://leo.cuckoo.org/projects/SVG-TT-Graph/ http://use.perl.org/~davorg/journal/20979 Quoting from that last URL: At first I looked at GD::Graph as that's pretty much seen as the standard Perl graphing module. But, to be honest, the output really isn't up to the quality that you can get from Excel. Then someone suggested that I look at SVG::TT:Graph instead. And it's great. I got some very useable graphs up in about 15 minutes (then, of course, I spent two hours tweaking them). Of course, the catch is that you have to find a way to display SVG graphics for the project. If the goal is for this to be served over the web, most browsers still don't have SVG support by default, though there are good plugins that can be downloaded installed. These pages give a pretty good overview of SVG issues, including browser support: http://www.carto.net/papers/svg/samples/ http://sdx.archivesdefrance.culture.gouv.fr/gpl/navimages/en/svgViewer.html -- Chris Devers d»Ó¼urÆðekù ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm
Re: [Boston.pm] Pretty Graphs with Perl
hi ( 05.12.06 09:26 -0500 ) Alex Brelsfoard: But I was wondering if you all had any better suggestions. Are there any good, friendly, tested modules for this sort of thing? despite the somewhat dismissive comment put forth in the SVG discussion, GD::Graph is quite workable, and can return .jpg .png and others that browsers have no trouble handling. colors c. almost as you might dream them ... Would this be better off in Java? i don't think so, buy ymmv. -- \js oblique strategy: emphasize the flaws ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm
Re: [Boston.pm] Pretty Graphs with Perl
I've found this module is extremely useful, and they make very powerful graphs. http://www.advsofteng.com/ Easy to install and use. I can provide assistance if needed. -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Alex Brelsfoard Sent: Tuesday, December 06, 2005 10:45 AM To: Ronald J Kimball Cc: boston-pm@mail.pm.org Subject: Re: [Boston.pm] Pretty Graphs with Perl Th only problem is that I am going to need to create different dataset and graph them on the fly. Writing files out and then shelling doesn't quite sound like the most efficient way of doing things. Or am I missing things? Basically I will have a HUGE collection of data to pull from, then viewers will select what of that data they want plotted. Then my app should plot it. Make sense? It's seeming kind of like I will need to try a few of these to see what will work. Do you all agree that starting with GD::Graph is probably the best way to start? Thanks everyone. I reallly appreciate this help. I have a feeling this is going to be one of the largest/trickiest apps I've had to create. --Alex On 12/6/05, Ronald J Kimball [EMAIL PROTECTED] wrote: On Tue, Dec 06, 2005 at 09:35:18AM -0500, Geoff Rowell wrote: Alex Brelsfoard wrote: I've got a project coming up that's going to need me to make graphs. I do not yet know what kind of graph (dot, line, bar, etc.). But I am told that it needs to be pretty (and probably with multiple colors). The data needing to be displayed will be anywhere from 5 points, to many thousands of points. There will be some times where I will need to have multiple datasets (separated by color) set on the same graph, one over the next. I was thinking of a brute-force way of doing this with associative arrays. But I was wondering if you all had any better suggestions. Are there any good, friendly, tested modules for this sort of thing? Is this a time for Perl tk? Would this be better off in Java? I usually create data files and shell out to GnuPlot. That's also what I do for one of my projects. I tried GD::Graph and Chart::Graph::Gnuplot and wasn't happy with either. GD::Graph only allows you to graph two datasets when using two y axes. Chart::Graph::Gnuplot, which is a wrapper around gnuplot, has an unwieldy interface and makes it difficult to use some features of gnuplot. Ronald ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm
Re: [Boston.pm] Pretty Graphs with Perl
Alex wrote: Th only problem is that I am going to need to create different dataset and graph them on the fly. Writing files out and then shelling doesn't quite sound like the most efficient way of doing things. Or am I missing things? Basically I will have a HUGE collection of data to pull from, then viewers will select what of that data they want plotted. Then my app should plot it. Make sense? It's seeming kind of like I will need to try a few of these to see what will work. Do you all agree that starting with GD::Graph is probably the best way to start? I used GD::Graph for a project I did about a week ago. I've used it before, but this was the first time someone cared about how 'pretty' the output was, as opposed to simply how functional it was. My data consisted of an arbitrary number of items graphed along time (x) as a bar or a line. I found that if you are willing to spend a lot of time mucking around with the colours, and you can take steps to crop your data if it will make the graph too crowded, the results are not too bad. They are not beautifully polished, but they are presentable. Two problems in particular that I noted were that the legend sometimes obscures data on the right, and sometimes the calculations for the steps/height of the y-axis are just wacky (for example: steps of .25 when dealing with only whole numbers, or a top height of 2x the highest y-value). I recommend making your own calculations concerning Y and forcing GD::Graph to play along. Also if you have many different items, you may want to cluster them around your points at the X-axis for clarity by introducing an ignored element. This makes it much easier to see what is going on if you have (for instance) 5 elements being displayed at each point of x. - Ann ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm
Re: [Boston.pm] Pretty Graphs with Perl
In the past I've tried unsuccessfully to create a multi-part web document using GD. After getting frustrated, I ended up pointing the IMG tag directly to the GD script (i.e. IMG src=myscript.pl), passing all the parameters needed right in the HTML document. The script outputted an image stream to STDOUT, which the IMG tag correctly displayed. That said, I was behind a firewall, and the page was for internal consumption. I don't know if there are any security concerns creating the graphics in this manner for an external site. Also, I am sure this is not the most efficient way of doing it. I'll see if I can dig up the old code snippet that I had and pass it along (it's been over 5 years since I did this). I would be interested in seeing how to create a multi-part html steam, one that includes both graphics and text. Hope this helped. Tal -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Alex Brelsfoard Sent: Tuesday, December 06, 2005 4:02 PM To: Ricker, William Cc: boston-pm@mail.pm.org; Richard J. Barbalace Subject: Re: [Boston.pm] Pretty Graphs with Perl Does anyone who has/does use GD::Graph know if there's an easy way to embed the output graphs into HTML. Basically I'd like to be able to print a bunch of HTML, then the graph, then some more HTML. I've got the grph coming out all fine and dandy. Thanks. --Alex On 12/6/05, Ricker, William [EMAIL PROTECTED] wrote: Richard, At the risk of being branded a heretic, Heretic! :-) (-: Pi, fetch the brazier, would you? :-) I would suggest writing such a complex application in Java. Anything written in Java _becomes_ complex. The reason to write in Java is if the massive Apache + Struts + JBoss/WebLogic/Websphere super-framework is a killer app for your problem, or someone requires it, or you have to plug into some legacy Java. Alex, the original poster, should know already if that's the case. Alex, I've had good results with GD::Graph and the ::Chart:: versions thereof -- except when I let the libgd library differ from the Perl version. I haven't used plot(1) in so long it wasn't called gnuPlot yet, but a shell or Perl that shells out to (gnu)Plot is a classic, as has been mentioned previously. Alternatively, O'Reilly ONLamp has a nice article on simple graphing and analysis with Gnu R posted last month http://www.onlamp.com/pub/a/onlamp/2005/11/17/r_for_statistics.html [OnLamp.com seems to be down at this time!?] There's even a partial interface to Perl via PDL http://search.cpan.org/~cavanaugh/PDL-R-math-0.12/rmath.pd , but it's not for driving charts; PDL has it's own PDL::Graphics::* modules, which is yet another alternative if you have enough data to be worth the efficiencies of PDL (Perl Data Language, which uses the FORTRAN libraries). If you're on one of those Redmond-style OS's, you could probably use the Perl Spreadsheet modules and Win32::Ole modules to command Excel to plot graphs too *shudder*. There's lots more options on http://search.cpan.org/modlist/Graphics , not sure which are relevant to your problem. Cheers, Bill n1vux ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm
Re: [Boston.pm] Pretty Graphs with Perl
On 12/6/05, Alex Brelsfoard [EMAIL PROTECTED] wrote: Does anyone who has/does use GD::Graph know if there's an easy way to embed the output graphs into HTML. Basically I'd like to be able to print a bunch of HTML, then the graph, then some more HTML. I've got the grph coming out all fine and dandy. You have to print out HTML that includes an embedded image, and make the URL for that image be served by your program that prints out the graph. One warning if you shell out in a CGI script: be ABSOLUTELY sure that you send headers before calling the shell. A very common mistake is to print your header then call the shell, not realizing that your print just saved data in a buffer and then waits to send it until either the buffer is full or your program ends. The result is that in your code you see the header printed before the graph, but Apache receives graph before the header and gets upset at you. Cheers, Ben ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm
Re: [Boston.pm] Pretty Graphs with Perl
Does anyone who has/does use GD::Graph know if there's an easy way to embed the output graphs into HTML. Basically I'd like to be able to print a bunch of HTML, then the graph, then some more HTML. [WDR] The basic techniques are to either (a) img href=../graphs/123456789.png Generate the graph to a 2nd file named with a random number (for security) or a serial number (if no security needed) my $thisgraph; # uniq name $this_graph = sprintf %s/%d.png, $graphdir, rand($bignumber) while -r $thisgraph; print qq{img href=$this_graph size=$normal_size}; put_to_file($gd-png(), $this_graph); where put_to_file is something like (from GD::Image png method notes) sub put_to_file { my ($data, $fn)[EMAIL PROTECTED]; my $fh; open $fh, $fh or die; binmode $fh; print $fh $data or die; close $fh or die; } (b) img href=/scripts/imagemaker?x=17y=42title=%22Foo%20Bar%22xname=Xyname= Y Put the code that decides what to do from the Request in a module, and call it from both the CGI or action module that generates the HTML page (which generates the img link) and the CGI or action module that generates the dynamic graphic (in response to the img link). Some amount of setup work (varies with app) would have to be redone or saved in DB or some other place (with unique names!), but at least the code is reused in a module. In this case, you put all the request parameters that the graph module needs on the IMG URI, or copy all the request parms to be safe if you don't know; since it's a module, it should know. One module, one script could do both Page and Image requests, with a arg difference (or HTTP context wanting text/html or image/*?) determining which to generate. A has efficiency advantages in that any shared setup work for the page and the graphic is done once. B allows someone to statically deep link or bookmark an image. B has efficiency advantages if page is likely to be fetched by Lynx or WWW::Mechanize or spiders who will never fetch the image. B has efficiency advantages if the pages will be fetched through Akamai or client proxies, and multiple users may request the same image -- so the image will be cached outside your server -- dont' recreate it if you don't have to; this doesn't apply if everyone is local or every request is unique. etc ... Bill n1vux ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm
Re: [Boston.pm] Pretty Graphs with Perl
On Tue, Dec 06, 2005 at 04:28:30PM -0500, Ricker, William wrote: (a) img href=../graphs/123456789.png Generate the graph to a 2nd file named with a random number (for security) or a serial number (if no security needed) (b) img href=/scripts/imagemaker?x=17y=42title=%22Foo%20Bar%22xname=Xyname= Y Put the code that decides what to do from the Request in a module, and call it from both the CGI or action module that generates the HTML page (which generates the img link) and the CGI or action module that generates the dynamic graphic (in response to the img link). B has efficiency advantages if the pages will be fetched through Akamai or client proxies, and multiple users may request the same image -- so the image will be cached outside your server -- dont' recreate it if you don't have to; this doesn't apply if everyone is local or every request is unique. You don't have to recreate the image with A, if you cache it on the server. What I do is build a string containing the gnuplot commands, and use an MD5 hash of that string in the image filename. I keep the image file around for a couple hours, and if another request results in the same gnuplot commands, I just skip the call out to gnuplot. Ronald ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm
Re: [Boston.pm] Pretty Graphs with Perl
On Tue, 6 Dec 2005, Ricker, William wrote: (b) img href=/scripts/imagemaker?x=17y=42title=%22Foo%20Bar%22xname=Xyname= Y Put the code that decides what to do from the Request in a module, and call it from both the CGI or action module that generates the HTML page (which generates the img link) and the CGI or action module that generates the dynamic graphic (in response to the img link). Some amount of setup work (varies with app) would have to be redone or saved in DB or some other place (with unique names!), but at least the code is reused in a module. In this case, you put all the request parameters that the graph module needs on the IMG URI, or copy all the request parms to be safe if you don't know; since it's a module, it should know. One module, one script could do both Page and Image requests, with a arg difference (or HTTP context wanting text/html or image/*?) determining which to generate. If you opt for this solution, I strongly recommend not trying to pass serialized data to the script. Instead, store the data somewhere else and give the script the means to look up the data. Otherwise, it is quite likely, given arbitrary amounts of data, that you will find that your URL exceeds 2048 characters, which happens to be the maximum length of a URL in IE. Personally I prefer to just generate a temporary file if I have to store something temporarily (the data or the image). Here I am creating a file in a temporary directory, giving it a name with the datetime and generating module (useful for any developer who is looking at files), and a random string. Thius is quite adequate for our purposes, but of course it isn't suitable for all situations. I have an hourly cron job deleting all files in that directory which are older than one hour. - Ann ___ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm