Skip to content

Instantly share code, notes, and snippets.

@tremby
Created January 6, 2012 18:07
Show Gist options
  • Save tremby/1571696 to your computer and use it in GitHub Desktop.
Save tremby/1571696 to your computer and use it in GitHub Desktop.
plot -- ascii plot of numerical input data
#!/usr/bin/env ruby
def usage(stdout = false)
stream = stdout ? $stdout : $stderr
bin = File.basename($0)
indent = " " * (bin.length() + "Usage: ".length())
stream.puts("Usage: #{bin} [--help|-h]")
stream.puts(indent + " [--vertical]")
stream.puts(indent + " [--width <columns>]")
stream.puts(indent + " [--height <rows>]")
stream.puts(indent + " [--label]")
stream.puts <<eof
Plot data to a bar graph on the console.
Use the --vertical switch to plot vertical bars rather than horizontal ones. Use
the --height option to specify a height when in vertical mode (defaults to the
height of your terminal).
Use the --width option to specify a width (defaults to $COLUMNS).
Use the --label switch to enable labelling the bars in horizontal mode.
Standard input should be numeric data, one number per line.
eof
end
# duplicate stdin so we can get the terminal size without it getting our stdin
# and so throwing errors
stdin = STDIN.dup
STDIN.reopen(STDOUT)
# get terminal size
terminalsize = %x(stty size).scan(/\d+/).map { |s| s.to_i }
# put it back how it was
STDIN.reopen(stdin)
# set defaults
nomoreoptions = false
direction = :horizontal
label = false
width = terminalsize[1]
if (width.nil?)
width = 80
end
height = terminalsize[0]
if (height.nil?)
height = 24
end
# handle arguments
while ($*.length() > 0)
arg = $*.shift()
if (arg == "--")
nomoreoptions = true
next
end
if (!nomoreoptions && arg[0,1] == "-")
if (arg == "--help" || arg == "-h")
usage(true)
exit(0)
elsif (arg == "--vertical")
direction = :vertical
next
elsif (arg == "--label")
label = true
next
elsif (arg == "--height")
arg = $*.shift()
if (arg.nil?)
$stderr.puts("Expected a positive integer after the --height option")
else
arg = arg.to_i()
if (arg > 0)
height = arg
next
else
$stderr.puts("Expected a positive integer after the --height option")
end
end
elsif (arg == "--width")
arg = $*.shift()
if (arg.nil?)
$stderr.puts("Expected a positive integer after the --width option")
else
arg = arg.to_i()
if (arg > 0)
width = arg
next
else
$stderr.puts("Expected a positive integer after the --width option")
end
end
else
$stderr.puts("Unknown option \"#{arg}\"")
end
else
$stderr.puts("Unexpected argument \"#{arg}\"")
end
# problem with arguments
usage()
exit(1)
end
# read stdin, treat each line as a float
data = $stdin.readlines()
data.map! { |datum| datum.to_f }
max = data.max()
if (direction == :horizontal)
if (label)
# get the longest string number when written as decimal
stringnumbers = data.map { |datum| datum.to_s().length() }
longestnumber = stringnumbers.max()
usablewidth = width - longestnumber - 1
else
usablewidth = width
end
data.each do |datum|
if (label)
puts(datum.to_s().rjust(longestnumber) << " " << ("#" * (usablewidth * datum / max).round()))
else
puts("#" * (usablewidth * datum / max).round())
end
end
else
# leave a row for the new prompt
height -= 1
# get the heights of each column
bars = []
for i in 0...width
bars[i] = (height * data[(i * data.length() / width).round()] / max).round()
end
for i in 0...height
for j in 0...width
if (height - i > bars[j])
$stdout.write(" ")
else
$stdout.write("#")
end
end
$stdout.write($/)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment