in reply to gnuplot and CGI

Another option to consider is having your request handler generate the HTML and then "call back" to itself to generate the image:
# generate either HTML or graph depending on CGI parms my $graph_parms = (new CGI)->param('graph'); if ($graph_parms) { gen_graph($graph_parms) } else { gen_html() } sub gen_html { # ... generate other HTML ... # add IMG element that calls back to us to get image print qq(<img src="index.cgi?graph=..." ...>); } sub gen_graph { my $parms = shift; my $img_data = generate_graph( $parms ); print "Content-Type: image/png\n", "Cache-Control: max-age=300\n\n", $img_data; }
The Cache-Control header may help reduce load on your server for frequently requested graphs.

Cheers,
Tom

Replies are listed 'Best First'.
Re^2: gnuplot and CGI
by kryberg (Pilgrim) on Nov 09, 2004 at 22:23 UTC
    I've made progress but I'm still having trouble getting the image to display in the browser, I'm hoping I can get input from someone.

    The following code prints the A OK message and then prints
    Content-type: image/png Content-type: text/html 
    Software error:
    Failed to open pipe: No such file or directory
    #!/usr/bin/perl -w use CGI qw( :standard ); use CGI::Carp 'fatalsToBrowser'; print "Content-type: text/plain\n\n"; print p( "A OK" ); print "Content-type: image/png\n\n"; my $data = "05056670.txt"; my $plot = plotdata(); sub plotdata { open my $graph => "| gnuplot" or die "Failed to open pipe: $!\n"; my $graph; print $graph <<"gnu"; set terminal png color set output set xdata time set timefmt "%Y%m%d" set key left top title "Legend" box set grid xtics ytics set yrange [700:] set format x "%Y" set xlabel "Year" set ylabel "Sodim, water, filtered, milligrams per liter" set title "05056670 Western Stump Lake Major Ions" plot "$data" using 2:3 title "P00930 Sodium dissolved" gnu close $graph or die "Failed to close pipe: $!\n"; }
    The following code appears to work at the command prompt because it prints the text and a bunch of strange characters, but it this is what the browser shows:
    A OK 
    
    Content-Type: image/png 
    no image.
    !/usr/bin/perl -w use CGI qw( :standard ); use CGI::Carp 'fatalsToBrowser'; my $q = new CGI; print $q->header("text/html"); print p(" A OK "); my $img = `gnuplot setcmds`; print $q->header("image/png"), $img;
    setcmds file:
    set terminal png color set output set xdata time set timefmt "%Y%m%d" set key left top title "Legend" box set grid xtics ytics set yrange [700:] set format x "%Y" set xlabel "Year" set ylabel "Sodim, water, filtered, milligrams per liter" set title "05056670 Western Stump Lake Major Ions" plot "05056670.txt" using 2:3 title "P00930 Sodium dissolved"
    I'm sure I'm not doing something correctly, but I don't know what.
      You can only send one response at a time, but you are trying to send back two responses smashed together (one blob of text and one image):
      print "Content-type: text/plain\n\n"; print p( "A OK" ); print "Content-type: image/png\n\n";
      Only the first header is interpreted as a valid header, and hence the browser thinks it is seeing one big text response.

      What you must do is send back one response per request. The trick is to set the src attribute of your first response's IMG element in such a way as to cause the client's browser to call your CGI back and ask for the image.

      This is the idea:

      1. The client's web browser requests your page.
      2. Your CGI receives request and sends back a text/html response. The HTML includes an IMG element whose src attribute points back to your CGI and passes in an "I want the image" parameter.
      3. The client's browser receives your response, parses the HTML, and then tries to load the image. In doing so, it calls your CGI again (the src attribute points to it), asking for the image.
      4. Your CGI checks the request parameters and notices the "I want an image" parameter. The CGI then generates the image and sends back an image/png (or whatever type is appropriate) response.
      5. The client receives the image and finishes rendering the page.
      6. It's happy time. Dance.

      For a complete example that uses this technique, see the script referenced at the end of The Mobile Weather Problem and its solution on my site.

      Cheers,
      Tom

        Thank you so much! I now have the graph displaying in the browser in my test case!

        I knew just enough CGI to know that it was possible. I'm off to study your example - I appreciate that you have made it available online.
Re^2: gnuplot and CGI
by kryberg (Pilgrim) on Nov 09, 2004 at 21:50 UTC
    That sounds like a good possiblity - thanks