#!/usr/bin/env python3

import sys
import random
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
import matplotlib; matplotlib.use('Agg')  # noqa; for systems without X11
from matplotlib.backends.backend_pdf import PdfPages
import pylab as plt

plt.rcParams.update({
    'axes.grid': True,
})


def get_all_values_from_fd(fd):
    values = []
    for line in fd:
        try:
            x, y = line.strip().split()
            values.append((float(x), float(y)))
        except ValueError:
            print('ignoring', line)
            continue
    return values


def main(args, pdf):
    plt.figure()
    if not args.input:
        values = get_all_values_from_fd(sys.stdin)
        if args.max_points >= 0 and len(values) > args.max_points:
            values = random.sample(values, args.max_points)
        x = [v[0] for v in values]
        y = [v[1] for v in values]
        plt.plot(x, y)
        plt.xlim(xmin=min(x), xmax=max(x))
        plt.ylim(ymin=min(y), ymax=max(y))
    else:
        all_min_x, all_max_x = None, None
        all_min_y, all_max_y = None, None
        for fname, label in args.input:
            with open(fname, 'rt') as fd:
                values = get_all_values_from_fd(fd)
            if args.max_points >= 0 and len(values) > args.max_points:
                values = random.sample(values, args.max_points)
            x = [v[0] for v in values]
            y = [v[1] for v in values]
            this_min_x, this_max_x = min(x), max(x)
            this_min_y, this_max_y = min(y), max(y)
            if all_min_x is None or this_min_x < all_min_x:
                all_min_x = this_min_x
            if all_max_x is None or this_max_x > all_max_x:
                all_max_x = this_max_x
            if all_min_y is None or this_min_y < all_min_y:
                all_min_y = this_min_y
            if all_max_y is None or this_max_y > all_max_y:
                all_max_y = this_max_y
            plt.plot(x, y, label=label)
        plt.xlim(xmin=all_min_x, xmax=all_max_x)
        plt.ylim(ymin=all_min_y, ymax=all_max_y)
        plt.legend(loc='lower right')
    if args.xlabel:
        plt.xlabel(args.xlabel)
    if args.ylabel:
        plt.ylabel(args.ylabel)
    if args.title:
        plt.title(args.title)
    pdf.savefig()


if __name__ == '__main__':
    parser = ArgumentParser(
        formatter_class=ArgumentDefaultsHelpFormatter,
        description='Takes one or more lists of values, one per line, and '
        'plots a CDF of them. Values may either be given on stdin or read '
        'from one or more files.')
    parser.add_argument(
        '-i', '--input', nargs=2, metavar=('FNAME', 'LABEL'),
        action='append', help='Specify a file to read values from and what '
        'to label its line in the PDF. If given 0 times, data will be '
        'read from stdin. Can be given more than once. The only time data '
        'will be read from stdin is if it is given 0 times.')
    parser.add_argument('-o', '--output', default='temp.pdf')
    parser.add_argument('-x', '--xlabel', type=str,
                        help='What to label the X axis in the PDF')
    parser.add_argument('-y', '--ylabel', type=str,
                        help='What to label the Y axis in the PDF')
    parser.add_argument('-t', '--title', type=str,
                        help='What to title the plot in the PDF')
    parser.add_argument('--max-points', default=10000, type=int,
                        help='Maximum number of points on a line. Negative '
                        'means infinite')
    args = parser.parse_args()
    with PdfPages(args.output) as pdf:
        exit(main(args, pdf))

Add plot-xy.py