Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Re: Re: Drawing Graphs

by oakbox (Chaplain)
on Sep 15, 2002 at 11:03 UTC ( #198024=note: print w/replies, xml ) Need Help??


in reply to Re: Drawing Graphs
in thread Drawing Graphs

I, also, went with the POV-Ray route. I ended up spending a LOT of hours getting the information into a format that was pretty, but still easily readable. This wasn't just a case of reinventing the wheel, this was inventing mining, smelting, and wood working. The fact that POV-Ray takes its instructions from a text source file made it pretty easy to integrate into my final script, but the development time was prohibitive.
Just my 2 cents.

Update Posted an example of my code here: POV-Ray graphing example

oakbox

Replies are listed 'Best First'.
Re: Re: Re: Drawing Graphs
by Solo (Deacon) on Sep 15, 2002 at 13:25 UTC
    PhiRatE or oakbox, is the Perl code you used to generate the POV-Ray scene file for the graphs available somewhere? Being an old POV-Ray fan I'd like to see how you generated the scene file, specifically the camera def...

    (Edit: clarification of request)--Sorry, Beatnik.
    My original, poorly worded question, wonderfully answered by Beatnik was:

    Is the POV-Ray code available somewhere?
    --
    May the Source be with you.

    You said you wanted to be around when I made a mistake; well, this could be it, sweetheart.

      Okay, this needs some explanation. This script was created to look into a directory storing Storable.pm files. Each of these Storable files has a hash reference for the results of tests. (This was part of the psychological profiling system I am working on for http://www.iscreen.nl.) Each of these graphs takes between 5 and 30 seconds to render, so I was running this in the background as a cron job, pre-rendering the graphs so that when they are needed, they are already on the system and ready for download via the web.

      How it works:
      Pull up my values to graph (all results are between 1 and 9).
      Send those values to the Builder.
      The Builder tries to adjust the width of the bars to make them fit into the final image and then creates a POV source file.
      After the source file is built, return to the main program and run a system call to create the png output file.

      This was just a proof of concept. In the end, my customers weren't too happy with the look. It is very difficult (as mentioned earlier) to represent this kind of information in a clean way in 3D. Hopefully, you can use this code for some ideas and as a jumping-off point for your own code.

      Note! I made a few changes to this code before posting it here and I haven't tested my changes. I can't guarantee the prettiness either :)

      I put an example of the output (before fiddling with the source) here: http://www.oakbox.com/povexamp.png

      #!/usr/bin/perl use strict; no strict 'refs'; use Storable qw(retrieve nstore); my $dir = "/source/of/data/files/storable"; my $outputdir = "/dir/for/images/povtrace"; chdir $dir || (warn "Cannot chdir $dir: $!" and return); opendir(DIR, $dir) || (warn "Cannot open $dir: $!" and return); my @contents = readdir DIR; closedir(DIR); foreach my $f (@contents) { if($f !~ /candidateinfo/){ # not looking at candidates! my $file = $dir."/".$f; # the file # get test ID my ($can,$tg) = split(/-/,$f); if($can < 200){next;} # only recent candidates my ($tid,undef) = split(/\./,$tg); if($tid eq ""){next;} # filter kooky files my $Test = eval{retrieve($file)}; # read the storable my $scorecant; my @xdata; my @ydata; foreach my $tcode (sort keys %{$Test->{norms}}){ push(@xdata,$Test->{norms}->{$tcode}); push(@ydata,$Test->{expert_names}->{$tcode}); $scorecant .= "$Test->{norms}->{$tcode}"; } my $ccc = @ydata; if($ccc <1){next;} $ccc = @xdata; if($ccc <1){next;} my $outfile = "$outputdir/$tid-$scorecant.png"; if(-e($outfile)){ next; } # I've already graphed this result set # build the POV-Ray source file &Builder(\@xdata,\@ydata,"$tid-$scorecant.pov"); # Render that source file, the settings below are # a balance between speed and pretty my $povcall = qq( povray +L/home/oakbox/tmp/povray-3.5/include +A ++I$tid-$scorecant.pov +O$outfile +V +W400 +H300 +FN6); my $whang = system("$povcall 1>povray.stdout 2>povray.stderr"); } } exit; sub Builder { my ($xdata,$ydata,$renderfilename) = @_; my @xdata; my @ydata; my $number_vert_lines = 9; # this is a kludge, but I'm in a hurry foreach ( @{$xdata} ){ push(@xdata,$_);} foreach ( @{$ydata} ){ push(@ydata,$_);} # make sure that I have an x for every y my $county = @ydata; my $countx = @xdata; if($countx ne $county){ die "Your x and y counts don't add up!"; } # find height scaling factor my $maxyval = 9 ; my $heightscale = 4 / $maxyval; my $ylabels; foreach my $level (0...$number_vert_lines){ my $label = ($level/$number_vert_lines) * $maxyval; $label = sprintf("%.1f", $label); my $lineup = ($level/$number_vert_lines) * 4; $ylabels .= qq( text { ttf "Arial.ttf" "$label" .1, 0 pigment { Black } scale .15 translate <-.7,$lineup,0> rotate <0,350,0> } object { Divide_Line translate <-.5,$lineup,0>} ); } # calculate dividers and bar width my $widthval = 6 / $county; if($widthval > 2){$widthval=2;} my $yspace = $widthval * .8; # make bar declarations one for each y value my @colorseq = ("Blue","Green","Red","Blue","Green","Red","Blue","Gree +n","Red","Blue","Green","Red","Blue","Green","Red","Blue","Green","Re +d","Blue","Green","Red","Blue","Green","Red","Blue","Green","Red","Bl +ue","Green","Red","Blue","Green","Red","Blue","Green","Red","Blue","G +reen","Red","Blue","Green","Red","Blue","Green","Red","Blue","Green", +"Red","Blue","Green","Red","Blue","Green","Red","Blue","Green","Red", +"Blue","Green","Red","Blue","Green","Red"); my $bar_descriptors; my $tscale_factor = ".01"; my $scale_factor = .20; my $theight = -.15; foreach my $placeh (0...$#ydata){ my $barheight = $xdata[$placeh] * $heightscale; $barheight = sprintf("%.2f", $barheight); my $yplace = $placeh * $widthval; $yplace = sprintf("%.2f", $yplace); my $interior_lights; foreach my $lights (0){ # only one light now, but easy to add! if($lights < $barheight){ my $bong = $lights + .1; $interior_lights.=qq( light_source { <.1,$bong,.2> color White } ); }} my $tplace = $yplace + ($yspace/2); $bar_descriptors.=qq( #declare Bar_$placeh = merge { cylinder { <0,$barheight,0>, <0,0,0>, .2 finish { Dull } pigment { $colorseq[$placeh] filter .5} interior{ ior 1.5 fade_distance 5 fade_power .5 caustics 1 } } $interior_lights bounded_by { box {<0,0,0>, <$yspace,$barheight,1>} } } object { Bar_$placeh translate <$yplace,0,0> } text { ttf "Arial.ttf" "$ydata[$placeh]" .15, 0 pigment { $colorseq[$placeh] } scale $scale_factor translate <.15,$theight,0> rotate <0,20,350> translate <$tplace,0,0> } ); # $scale_factor = $scale_factor + $tscale_factor; # $theight = $theight + $tscale_factor; } my $final_output = qq( #include "colors.inc" #include "finish.inc" camera { location <.7,2.5,-6.5> look_at <2.4,1.9,0> } background { White } global_settings { max_trace_level 30 } light_source { <0, 50, -50> color White shadowless } #declare Divide_Line = box { <0,0,-.1>, <7,-.015,-.12> pigment { Gray05 } } $ylabels $bar_descriptors ); open (WRT,">$renderfilename"); print WRT $final_output; close(WRT); } exit;

      oakbox

      Ofcourse...
      The Pov-Ray Download section has a few links.

      Greetz
      Beatnik
      ...Perl is like sex: if you're doing it wrong, there's no fun to it.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://198024]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (10)
As of 2019-09-19 17:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    The room is dark, and your next move is ...












    Results (249 votes). Check out past polls.

    Notices?