Skip to content

Instantly share code, notes, and snippets.

@rinx
Last active January 7, 2017 06:42
Show Gist options
  • Save rinx/4995d71729514d6a6e7791ad3f2abf9e to your computer and use it in GitHub Desktop.
Save rinx/4995d71729514d6a6e7791ad3f2abf9e to your computer and use it in GitHub Desktop.
Histogram libraries for ruby using gnuplot gem
# -*- coding: utf-8 -*-
# hist_gp.rb
#
# Author: Rintaro Okamura
#
# Description:
# Histogram libraries for ruby using gnuplot gem
#
require 'gnuplot'
module HistGnuplot
class Hist
def initialize
end
end
# 2D histogram
class Hist2D
attr_accessor :xdata, :ydata,
:title, :xlabel, :ylabel, :cblabel,
:binres_x, :binres_y,
:interval_x, :interval_y,
:dx, :dy, :x, :y,
:max_x, :max_y,
:min_x, :min_y,
:logscale
def initialize(xdata, ydata, bin_x=100, bin_y=100)
@binres_x = bin_x
@binres_y = bin_y
@xdata = xdata
@ydata = ydata
@max_x = xdata.max.to_f
@min_x = xdata.min.to_f
@max_y = ydata.max.to_f
@min_y = ydata.min.to_f
@max_x = 999.0 if @max_x.infinite?
@max_y = 999.0 if @max_y.infinite?
@min_x = -999.0 if @min_x.infinite?
@min_y = -999.0 if @min_y.infinite?
@logscale = false
end
def plot(outfilepath='none')
@interval_x = ((@max_x - @min_x).to_f / @binres_x).to_f
@interval_y = ((@max_y - @min_y).to_f / @binres_y).to_f
@dx = @interval_x / 2.0
@dy = @interval_y / 2.0
@x = []
@y = []
@binres_x.times do |i|
@x.push(@min_x + @interval_x * (i + 1).to_f - @dx)
end
@binres_y.times do |i|
@y.push(@min_y + @interval_y * (i + 1).to_f - @dy)
end
hist = Array.new(@binres_x).map{Array.new(@binres_y, 0)}
@binres_x.times do |ix|
insidebin_x_index = @xdata.each_with_index.select {|a|
a[0] >= (@x[ix]) and a[0] < (@x[ix] + @interval_x)
}.map{|a| a[1]}
@binres_y.times do |iy|
insidebin_y_index = @ydata.each_with_index.select {|a|
a[0] >= (@y[iy]) and a[0] < (@y[iy] + @interval_y)
}.map{|a| a[1]}
hist[ix][iy] = (insidebin_x_index & insidebin_y_index).length
end
end
Gnuplot.open do |gp|
SPlot.new(gp) do |plot|
case outfilepath
when /^none$/
plot.terminal 'x11'
when /\.tex$/
plot.terminal "tikz"
plot.output File.expand_path(outfilepath)
when /\.pdf$/
plot.terminal "pdf"
plot.output File.expand_path(outfilepath)
when /\.png$/
plot.terminal "pngcairo"
plot.output File.expand_path(outfilepath)
else
STDERR.puts "Error: unknown filetype"
exit
end
plot.title @title
plot.xlabel @xlabel
plot.ylabel @ylabel
plot.cblabel @cblabel
plot.set "datafile missing \"Infinity\""
plot.set "key off"
plot.set "view map"
plot.set "size square"
plot.xrange "[#{@min_x}:#{@max_x}]"
plot.yrange "[#{@min_y}:#{@max_y}]"
if @logscale
plot.cbrange "[1:#{hist.flatten.max}]"
plot.set "logscale cb"
else
plot.cbrange "[0:#{hist.flatten.max}]"
end
plot.set "palette defined ( 0 '#000090', 1 '#000fff', 2 '#0090ff', 3 '#0fffee', 4 '#90ff70', 5 '#ffee00', 6 '#ff7000', 7 '#ee0000', 8 '#7f0000')"
plot.data <<
Gnuplot::DataSet.new([@x, @y, hist]) do |ds|
ds.with = 'image pixels'
end
end
end
end
end
end
private
# https://github.com/rdp/ruby_gnuplot/blob/master/lib/gnuplot.rb#L358
class SPlot < Gnuplot::Plot
def initialize (io = nil, cmd = "splot")
@cmd = cmd
@settings = []
@arbitrary_lines = []
@data = []
@styles = []
yield self if block_given?
$stderr.puts "writing this to gnuplot:\n" + to_gsplot + "\n" if $VERBOSE
if io
io << to_gsplot
io << store_datasets
end
end
def to_gsplot (io = "")
@settings.each do |setting|
io << setting.map(&:to_s).join(" ") << "\n"
end
@styles.each{|s| io << s.to_s << "\n"}
@arbitrary_lines.each{|line| io << line << "\n" }
io
end
def store_datasets (io = "")
if @data.size > 0
io << @cmd << " " << @data.collect { |e| e.plot_args }.join(", ")
io << "\n"
v = @data.collect { |ds| ds.to_gsplot }
io << v.compact.join("e\n")
end
end
end
class Array
def to_gsplot
f = ""
if ( self[0].kind_of? Array ) then
x = self[0]
y = self[1]
d = self[2]
x.each_with_index do |xv, i|
y.each_with_index do |yv, j|
f << [ xv, yv, d[i][j] ].join(" ") << "\n"
end
f << "\n"
end
elsif ( self[0].kind_of? Numeric ) then
self.length.times do |i| f << "#{self[i]}\n" end
else
self[0].zip( *self[1..-1] ).to_gsplot
end
f
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment