#!/usr/bin/python2.5

"""Produce an X-Y plot from a text file of numbers in columns.
You can plot multiple curves in the same graph.
Curves can share a common x-axis, or each can have its own x-axis.
Each X or Y can be any column from a file.
Usage: g_multiplot [flags]
Examples:
g_multiplot -f datafile -xc 0 -yc 1
	To plot column 1 against column 0.
	(Column 0 is the leftmost column in the datafile.)
g_multiplot -f datafile -xc 0 -yc 1 -yc 3
	To plot columns 1 and 3 against column 0.
g_multiplot -f fileA -xc 0 -yc 1 -f fileB -yc 2
	To plot columns 1 in fileA and 2 in fileB against column 0 in fileA.
g_multiplot -x fileA 0 -yc 1 -f fileB -yc 2
	"-x file column" is exactly the same as "-f file -xc column"
g_multiplot -x fileA 0 -y fileB 0
	Plotting column 0 in fileB against column 0 in fileA
	(they must have the same length, of course).
g_multiplot -f fileA -xc 0 -yc 1 -f fileB -xc 0 -yc 1
	Two overlaid plots in the same frame.

Note that a dash ("-") can be used for one filename to read data from
the standard input.
Note: GNU purists may use --xc and --yc interchangeably with -x and -y,
similarly for all other multicharacter flags.
Note: specifying "-1", "t", or "i" for either the x or y column gives
you the sequence of integers, 0, 1, 2, ... .  That way you can plot
against time.

Other flags:
-xl label     set the x-label
-yl label     set the y-label
-t title   or  -title title    set the graph title
-xr min max     set the range of the x-axis.
-yr min max     set the range of the y-axis.
-c name or -color name    set the color of the current dataset.
	You can specify a color as a comma-separated triple of integers:
	"45,11,255" (in the range [0,256) ), or color names,
	or just *anything*, which will be hashed and converted to a random
	color.  Takes effect on the next -y or -yc command.
-l  Draw with a line.  Takes effect on the next -y or -yc command.
-L description
    Draw with a dashed line.  Takes effect on the next -y or -yc command.
    "description" can be "period,onfrac", where "period" is
    the periodicity of the line, and  "onfrac" is a percentage
    of the line that is drawn.   -L 0.1,0.1 is dotted.
    -L 0.1,0.5 is a normal dash.   -L 0.1,0.7 is a long dash.
    -L solid -L dashed -L broken -L dotted also work.
    Any other argument leads to a random choice of period,onfrac.
-w  Set linewidth (and also size of symbols).
-p  Draw with isolated points (default).
	Takes effect on the next -y or -yc command.
-P name  Draw with a named symbol.
	Legal names are "circle", "square", "triangle", "utriangle".
	Takes effect on the next -y or -yc command.
Note: you may intersperse -l, -L, -p and -P among the
-x, -xc, -f, -y, -yc commands to make some graphs lines
and others points, and yet others different colors.

-fmt set the output plot format (PS, PDF, SVG)
	and maybe (TK, WX) to display on the screen.
-o file   to set the output file (or window name).
"""

import graphite
from graphite import *
from graphite.forbin import *
import die

import Num
import sys


def _fmt(styleinfo):
	ss = None
	ls = None
	sym = None
	color = styleinfo.get('color', graphite.getcolor("green"))
	# print 'size=', size
	if styleinfo['usepoint']:
		size = styleinfo.get('size', 4)
		ss = SymbolStyle(size=size,
				edgeWidth=0,
				fillColor=color,
				edgeColor=color)
		sym = Symbol.G(styleinfo.get('symbol', 'circle'))
	if styleinfo['useline']:
		width = styleinfo.get('width', styleinfo.get('size', 4)/4.0)
		kind=styleinfo.get('linekind', SOLID)
		ls = LineStyle(width=width,
				kind=kind,
				color = color,
				)
		if kind == DASHED:
			ls.period = styleinfo.get('period', 5)
			ls.onfrac = styleinfo.get('onfrac', 0.5)
 
	return PointPlot(lineStyle = ls, symbolStyle = ss, symbol = sym)




if __name__ == '__main__':
	try:
		import psyco
		psyco.full()
	except ImportError:
		pass

	arglist = sys.argv[1:]
	data = []
	formats = []
	x = []
	media = 'PS'
	d = None
	canvas = 'plot'
	styleinfo = {'color': graphite.getcolor("green"),
			'linekind': SOLID,
			'size': 4,
			'usepoint': 1,
			'useline': 0
			}
	g = Graph()
	g.axes[X].tickMarks[0].labels = AUTO
	g.axes[Y].tickMarks[0].labels = AUTO
	while len(arglist)>0 and len(arglist[0])>0 and arglist[0][0]=='-':
		arg = arglist.pop(0)
		if arg == '-x':
			d = read(arglist.pop(0))
			x.append( d.column(arglist.pop(0)) )
		elif arg == '-y':
			d = read(arglist.pop(0))
			data.append(d.column( arglist.pop(0)) )
			formats.append(_fmt(styleinfo))
		elif arg == '-f':
			d = read(arglist.pop(0))
		elif arg == '-yc' or arg=='--yc':
			col = arglist.pop(0)
			try:
				data.append(d.column(col))
			except IndexError:
				die.die('Bad column number: %s' % col)
			formats.append(_fmt(styleinfo))
		elif arg == '-xc' or arg=='--xc':
			if d is None:
				die.die('Must specify data file with -f, -x, or -y')
			x.append( d.column(arglist.pop(0)) )
		elif arg == '-c' or arg=='-color' or arg=='--color':
			styleinfo['color'] = getcolor(arglist.pop(0))
		elif arg == '-o':
			canvas = arglist.pop(0)
		elif arg == '-title' or arg=='-t' or arg=='--title':
			g.title.text = arglist.pop(0)
		elif arg == '-xl' or arg=='--xl':
			g.axes[X].label.text = arglist.pop(0)
		elif arg == '-yl' or arg=='--yl':
			g.axes[Y].label.text = arglist.pop(0)
		elif arg == '-yr' or arg=='--yr':
			a = float(arglist.pop(0))
			b = float(arglist.pop(0))
			g.axes[Y].range = (a, b)
		elif arg == '-xr' or arg=='--yr':
			a = float(arglist.pop(0))
			b = float(arglist.pop(0))
			g.axes[X].range = (a, b)
		elif arg == '-p':
			styleinfo['usepoint'] = 1
			styleinfo['useline'] = 0
		elif arg == '-P':
			styleinfo['usepoint'] = 1
			styleinfo['useline'] = 0
			styleinfo['symbol'] = arglist.pop(0)
		elif arg == '-fmt' or arg=='--fmt':
			media = arglist.pop(0)
		elif arg == '-l':
			styleinfo['usepoint'] = 0
			styleinfo['linekind'] = SOLID
			styleinfo['useline'] = 1
		elif arg == '-L':
			styleinfo['usepoint'] = 0
			styleinfo['useline'] = 1
			styleinfo['linekind'] = DASHED
			styleinfo.update( getline(arglist.pop(0)) )
		elif arg == '-w':
			styleinfo['size'] = float(arglist.pop(0))
		elif arg == '--':
			break
		else:
			print "ERR: %s: Unrecognized flag: %s." % (sys.argv[0], arg)
			sys.exit(1)
	if len(arglist) != 0:
		print "ERR: %s: unused arguments starting with '%s'" % (sys.argv[0], arglist[0])
		print __doc__
		sys.exit(1)

	if len(data) == 0:
		print "ERR: %s: No data." % sys.argv[0]
		print __doc__
		sys.exit(1)


	if len(x) == 1:
		g.datasets = [ Dataset(Num.transpose((x[0], d))) for d in data ]
	elif len(x) == len(data):
		g.datasets = [ Dataset(Num.transpose((xt, d))) for (xt,d) in zip(x, data) ]
	else:
		print "ERR: %s: Inconsistent data" % sys.argv[0]
		print "You must either have one x dataset which is used for all the y data,"
		print "or one x dataset for each y dataset."
		print __doc__
		sys.exit(1)
	assert len(formats) == len(data)
	g.formats = formats

	genOutput(g, media, canvasname=canvas)
