Search code examples
phppythonsvggnuplotcgi-bin

gnuplot without intermediary files?


I got python code that looks something like this

import subprocess

outdata = """0 45
1 35
2 45
3 35
4 45
5 35
6 45
7 35
8 45""" # etc... one for every minute of a day
f = open("data.txt", 'w')
f.write(outdata)
f.close()

filename = "graph"
title    = "today"
plottext = """
set terminal svg size 2560,1440 enhanced font 'Arial,40'
set output '""" + filename + """.svg'
set title '""" + title + """'
set xrange [0:1440]
set yrange [0:]
set xtics ("00" 0, "01" 60, "02" 120, "03" 180, "04" 240, "05" 300, "06" 360, "07" 420, "08" 480, "09" 540, "10" 600, "11" 660, "12" 720, "13" 780, "14" 840, "15" 900, "16" 960, "17" 1020, "18" 1080, "19" 1140, "20" 1200, "21" 1260, "22" 1320, "23" 1380, "24" 1440 )
plot 'data.txt' using 1:2 with lines notitle
"""
f = open("plotfile.plt", 'w')
f.write(plottext)
f.close()

p = subprocess.call(["gnuplot", "plotfile.plt"])

Which works like a charm. But how do I create a graph with gnuplot from within Python (or an language) without using the temporary files 'data.txt' and 'plotfile.plt'?

This is done 30+ times per minute every minute, every hour, year around so skipping the temporary files would save disk time because it is not small amounts of data that is being processed.

Follow-up question, it is possible to also skip the out file and capture the xml for the svg-file in a variable? This is going to go in cgi-bin so I want to be able to call it like this:

<img src="http://www.example.com/cgi-bin/plot.py?table=table1&date=2016-12-07">

Edit: the Python module for gnuplot is not available for me.

Edit2: Another example in PHP that almost do what I want is

$outdata="0 33
1 44
2 55
3 44
4 33
5 44
 6 55";

$plottext = "set terminal svg size 2560,1440 enhanced font 'Arial,40'
set term svg size 2560,1440 enhanced font 'Arial,40'
set title ''
set xrange [0:1440]
set yrange [0:]
set xtics ('00' 0, '01' 60, '02' 120, '03' 180, '04' 240, '05' 300, '06' 360, '07' 420, '08' 480, '09' 540, '10' 600, '11' 660, '12' 720, '13' 780, '14' 840, '15' 900, '16' 960, '17' 1020, '18' 1080, '19' 1140, '20' 1200, '21' 1260, '22' 1320, '23' 1380, '24' 1440)
plot '-' using 1:2 with lines notitle\n". $outdata;

file_put_contents("plotfile.plt", $plottext);

exec("gnuplot plotfile.plt", $out);

foreach($out as $line)
{
    print $line."\n";
}

I would like to call it with something like exec("gnuplot $plottext", $out); so I can skip the file plotfile.plt because if two people try to access a plotted graph at the same time this setup might screw it up because everyone used plotfile.plt which is not the best of solution. We could use a long random name for each http request but keeping track of that many temp files and erase them is not elegant.


Solution

  • Plotting files with gnuplot withing Python is not the best solution. It is much better to use pyplot. That way you can input data inside the python code and save the graph as svg in a string.

    import matplotlib.pyplot
    import io
    
    plotfile = io.StringIO()
    matplotlib.pyplot.plot([1,2,3,4], [1,2,1,4])
    matplotlib.pyplot.ylabel('Y-axis')
    matplotlib.pyplot.xlabel('X-axis')
    matplotlib.pyplot.savefig(plotfile, format="svg", dpi = 100)
    plotfile.seek(0)
    svgstring = plotfile.read()
    print(svgstring)
    

    This is exactly what I wished for in my question. No file I/O in the potting and I get to keep the graph in the python code so it can be used for dynamic images in web apps.