Translations:

Belarusian

Estonian

Russian

At some point, it is bound to happen. Gnuplot is wonderful, but there comes a time where it just doesn't quite have the power that you need it to have. Perhaps you want to radically alter the way the axes are drawn. Perhaps you just want to do something simple like change the color of a plot line, but not the pattern. Maybe you really need some hefty math symbols displayed on the graph. At some point you'll hit the wall beyond which Gnuplot quickly stops being the right answer. What works better in these situations?

There are many answers. HippoDraw is powerful and free, although relatively unknown. Some people like XGraph. If you, like me, are a Python programmer, then you might be willing to go for a less user-friendly but more controllable solution. If so, then PyX (Pronounced "Piks") is one possibility.

As of this writing (January 2006), PyX is still pre-release software. Advertising a version of 0.8.1, there are definitely some rough edges on this. Usage of PyX may very well require some significant poking at the Python objects that make up the PyX framework. However, I can attest that this is time well spent: it took about 3 or 4 hours to go from first installing PyX to generating graphs that were (in my opinion) greatly superior to what I could have gotten out of Gnuplot, my normal go-to for graphing.

Multiple Plots

Plot Styles

Error Bars

Axis Labels and Scales

Graph Titles

Plotting Functions

Closing Notes

gnuplot> plot "data.dat"

from pyx import * g = graph.graphxy(width=8) g.plot(graph.data.file("data.dat", x=1, y=2)) g.writePDFfile("test")

There are three major differences between these two plots:

- Color - Gnuplot defaults to printing the first plot in red, the second in green, etc. (BTW: This is unfortunate for the ~3% of the population that is Red-Green colorblind.) PyX defaults to black and white.
- Key - Gnuplot defaults to rendering a key for each line in a plot, PyX does not.
- Image size - Gnuplot defaults to old computer-monitor resolutions like 640x480 with a ratio of 1.33:1. PyX defaults to canvases with the Golden Ratio of ~1.618:1. (This is likely to be less important to most, but I include it for completeness.)

from pyx import * g = graph.graphxy(width=8, key=graph.key.key()) g.plot(graph.data.file("data.dat", x=1,y=2)) g.writePDFfile("test")

gnuplot> plot "data.dat" title "My Data"Similarly in PyX:

from pyx import * g = graph.graphxy(width=8, key=graph.key.key()) g.plot(graph.data.file("data.dat", x=1, y=2, title="My Data")) g.writePDFfile("test")

from pyx import * g = graph.graphxy(width=8, ratio=4./3, key=graph.key.key()) g.plot(graph.data.file("data.dat", x=1, y=2, title="My Data")) g.writePDFfile("test")

from pyx import * g = graph.graphxy(width=8, ratio=4./3, key=graph.key.key()) g.plot(graph.data.file("data.dat", x=1, y=2, title="My Data"), styles=[graph.style.symbol(symbolattrs=[color.gradient.Rainbow])]) g.writePDFfile("test")

gnuplot> plot "data.dat" title "Data 1", "data2.dat" title "Data 2"

from pyx import * # Initialize graph object g = graph.graphxy(width=8, ratio=4./3, key=graph.key.key()) # These are the data lines we want to plot. data = [graph.data.file("data.dat", x=1, y=2, title="Data 1"), graph.data.file("data2.dat", x=1, y=2, title ="Data 2")] # Plot it g.plot(data, styles=[graph.style.symbol(symbolattrs=[color.gradient.Rainbow])]) # Write the output g.writePDFfile("test")

gnuplot> plot "data.dat" title "Data 1" with lines, "data2.dat" title "Data 2" with linespoints

from pyx import * # Initialize graph object g = graph.graphxy(width=8, ratio=4./3, key=graph.key.key()) # Plot the first line g.plot(graph.data.file("data.dat", x=1, y=2, title="Data 1"), styles=[graph.style.line([color.rgb.red, style.linestyle.solid, style.linewidth.thick])]) # Plot the second line g.plot(graph.data.file("data2.dat", x=1, y=2, title ="Data 2"), styles=[graph.style.line([color.rgb.green, style.linestyle.solid, style.linewidth.thick]), graph.style.symbol(symbolattrs=[color.rgb.green])]) # Write the output g.writePDFfile("test")

This section uses this as a data file.

plot "error.dat" using 1:2:3 with yerrorbars title "Samples"

from pyx import * g = graph.graphxy(width=8) g.plot(graph.data.file("error.dat", x=1, y=2, dy=3), styles=[graph.style.errorbar(errorbarattrs=[color.rgb.red]), graph.style.symbol(graph.style.symbol.circle, size=0.05, symbolattrs=[color.rgb.red])]) g.writePDFfile("test.pdf")

gnuplot> set ylabel "# Roaches" gnuplot> set xlabel "Time (days)" gnuplot> plot "data.dat" title "Data 1" with lines, "data2.dat" title "Data 2" with linespoints

from pyx import * # Initialize graph object g = graph.graphxy(width=8, ratio=4./3, key=graph.key.key(), x=graph.axis.linear(title="Time (days)"), y=graph.axis.linear(title="$\#$ Roaches")) # Plot the first line g.plot(graph.data.file("data.dat", x=1, y=2, title="Data 1"), styles=[graph.style.line([color.rgb.red, style.linestyle.solid, style.linewidth.thick])]) # Plot the second line g.plot(graph.data.file("data2.dat", x=1, y=2, title ="Data 2"), styles=[graph.style.line([color.rgb.green, style.linestyle.solid, style.linewidth.thick]), graph.style.symbol(symbolattrs=[color.rgb.green])]) # Write the output g.writePDFfile("test")

gnuplot> set ylabel "# Roaches" gnuplot> set xlabel "Time (days)" gnuplot> set xrange [0 to 35] gnuplot> set yrange [0 to 105] gnuplot> plot "data.dat" title "Data 1" with lines, "data2.dat" title "Data 2" with linespoints

from pyx import * # Initialize graph object g = graph.graphxy(width=8, ratio=4./3, key=graph.key.key(), x=graph.axis.linear(min=0, max=35, title="Time (days)"), y=graph.axis.linear(min=0, max=105, title="$\#$ Roaches")) # Plot the first line g.plot(graph.data.file("data.dat", x=1, y=2, title="Data 1"), styles=[graph.style.line([color.rgb.red, style.linestyle.solid, style.linewidth.thick])]) # Plot the second line g.plot(graph.data.file("data2.dat", x=1, y=2, title ="Data 2"), styles=[graph.style.line([color.rgb.green, style.linestyle.solid, style.linewidth.thick]), graph.style.symbol(symbolattrs=[color.rgb.green])]) # Write the output g.writePDFfile("test")

gnuplot> set ylabel "# Roaches" gnuplot> set xlabel "Time (days)" gnuplot> set xrange [0 to 35] gnuplot> set yrange [0 to 105] gnuplot> set title "Effectiveness of Brand X Roach Bait" gnuplot> plot "data.dat" title "Data 1" with lines, "data2.dat" title "Data 2" with linespoints

from pyx import * # Initialize graph object g = graph.graphxy(width=8, ratio=4./3, key=graph.key.key(), x=graph.axis.linear(min=0, max=35, title="Time (days)"), y=graph.axis.linear(min=0, max=105, title="$\#$ Roaches")) # Plot the first line g.plot(graph.data.file("data.dat", x=1, y=2, title="Data 1"), styles=[graph.style.line([color.rgb.red, style.linestyle.solid, style.linewidth.thick])]) # Plot the second line g.plot(graph.data.file("data2.dat", x=1, y=2, title ="Data 2"), styles=[graph.style.line([color.rgb.green, style.linestyle.solid, style.linewidth.thick]), graph.style.symbol(symbolattrs=[color.rgb.green])]) # Now plot the text, horizontally centered g.text(g.width/2, g.height + 0.2, "Effectiveness of Brand X Roach Bait", [text.halign.center, text.valign.bottom, text.size.Large]) # Write the output g.writePDFfile("test")

plot "data.dat" title "Data 1" with lines title "Data 1"

from pyx import * # Initialize graph object g = graph.graphxy(width=8, ratio=4./3, key=graph.key.key()) g.plot(graph.data.file("data.dat", x=1, y="$2/2", title="Data 1"), styles=[graph.style.line([color.rgb.red, style.linestyle.solid, style.linewidth.thick])]) g.writePDFfile("test")

Another common use for Gnuplot is to plot a function, be it purely mathematical or a best-fit for your data. (It is worth noting that PyX has no substitute for Gnuplot's "fit" capabilities if you are working with best-fit functions.)

set xrange [0:10] set yrange [0:10] f(x) = .2 * x**2 - x + 1 plot f(x)

from pyx import * # Initialize graph object g = graph.graphxy(width=8, key=graph.key.key(), x=graph.axis.linear(min=0, max=10), y=graph.axis.linear(min=0, max=10)) # Plot the function g.plot(graph.data.function("y(x) = .2 * x**2 - x + 1"), styles=[graph.style.line([color.rgb.red, style.linestyle.solid, style.linewidth.thick])]) # Write pdf g.writePDFfile("test.pdf")

set parametric set xrange[-5:5] set yrange[-5:5] set trange[0:10] unset key x(t) = cos(t) * t**.5 y(t) = sin(t) * t**.5 plot x(t),y(t)

import math def x(k): return math.cos(k) * k**.5 def y(k): return math.sin(k) * k**.5 # Initialize graph object g = graph.graphxy(width=8, x=graph.axis.linear(min=-5, max=5), y=graph.axis.linear(min=-5, max=5)) # Plot the function kMin = 0 kMax = 10 # The "context" parameter is a Python context, allowing us # to use functions locally defined in this function. OR # we can make the string "x, y = x(k), y(k)" into a more complex # Python expression (it is being passed to eval() under the hood.) g.plot(graph.data.paramfunction("k", kMin, kMax, "x, y = x(k), y(k)", context=locals()), styles=[graph.style.line([color.rgb.red, style.linestyle.solid, style.linewidth.thick])]) # Write pdf g.writePDFfile("test.pdf")

import math def x(k): return math.cos(k) * k**.5 def y(k): return math.sin(k) * k**.5 # Initialize graph object g = graph.graphxy(width=8, x=graph.axis.linear(min=-5, max=5), y=graph.axis.linear(min=-5, max=5)) # Plot the function kMin = 0 kMax = 10 g.plot([graph.data.paramfunction("k", kMin, kMax, "x, y = x(k), y(k)", context=locals()), graph.data.paramfunction("k", 0, 20, "x, y = 3+x(k), 1-y(k)", context=locals())], styles=[graph.style.line([color.gradient.RedBlue, style.linestyle.solid, style.linewidth.thick])]) # Write pdf g.writePDFfile("test.pdf")