OSDN Git Service

3ca7f0e700c43516ee186b06a744e0ab34b52cce
[shogi-server/shogi-server.git] / utils / players_graph.rb
1 #!/usr/bin/ruby
2 #    This generates graphs of evaluation values from comments in CSA files.
3 #    Ruby libraries that are required: 
4 #      - RubyGems: http://rubyforge.org/projects/rubygems/
5 #      - rgplot:   http://rubyforge.org/projects/rgplot/
6 #    OS librariles that is required:
7 #      - Gnuplot:  http://www.gnuplot.info/
8 #                  On Debian, $ sudo apt-get install gnuplot
9 #    
10 #    Copyright (C) 2008  Daigo Moriwaki <daigo@debian.org>
11 #
12 #    Version: $Id$
13 #
14 #    This program is free software; you can redistribute it and/or modify
15 #    it under the terms of the GNU General Public License as published by
16 #    the Free Software Foundation; either version 2 of the License, or
17 #    (at your option) any later version.
18 #
19 #    This program is distributed in the hope that it will be useful,
20 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
21 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 #    GNU General Public License for more details.
23 #
24 #    You should have received a copy of the GNU General Public License
25 #    along with this program; if not, write to the Free Software
26 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
27
28 require 'pathname'
29 require 'getoptlong'
30 require 'yaml'
31 require 'date'
32 require 'set'
33 require 'rubygems'
34 require 'gnuplot'
35
36 $players = {}
37
38 class Format
39   attr_reader :ext, :size
40   def initialize(root)
41     @root = root
42     @size = "1,1"
43   end
44 end
45
46 class LargeFormat < Format
47   def initialize(root)
48     super
49   end
50
51   def apply(plot)
52     plot.terminal @ext
53     plot.size     @size
54     plot.format 'x "%y/%m/%d"'
55     plot.ytics  "100"
56     plot.mytics "5"
57     plot.xlabel  "Date"
58     plot.ylabel  "Rate"
59   end
60 end
61
62 class LargePngFormat < LargeFormat
63   def initialize(root)
64     super
65     @ext = "png"
66   end
67
68   def to_image_file(name)
69     return File.join(@root, "#{name}-large.#{ext}")
70   end
71 end
72
73 class SmallPngFormat < Format
74   def initialize(root)
75     super
76     @ext = "png"
77   end
78
79   def to_image_file(name)
80     return File.join(@root, "#{name}-small.#{ext}")
81   end
82
83   def apply(plot)
84     plot.terminal "png size 320,200 crop"
85     plot.format   'x "%b"'
86     plot.ytics    "200"
87     plot.mytics   "2"
88   end
89 end
90
91 class SvgFormat < LargeFormat
92   def initialize(root)
93     super
94     @ext = "svg"
95   end
96
97   def to_image_file(name)
98     return File.join(@root, "#{name}.#{ext}")
99   end
100 end
101
102 def plot(format, name, dates, rates, rdates, rrates)
103   Gnuplot.open do |gp|
104     Gnuplot::Plot.new( gp ) do |plot|
105       format.apply(plot)
106       plot.title   name
107       plot.output format.to_image_file(name)
108       
109       #plot.size    "ratio #{1/1.618}"
110       plot.xdata   "time"
111       plot.timefmt '"%Y-%m-%d"'
112       plot.xrange  "[\"%s\":\"%s\"]" % 
113                     [dates.first.strftime("%Y-%m-%d"),
114                      dates.last.strftime("%Y-%m-%d")]
115       ymin = ((rates + rrates).min/50) * 50
116       ymax = ((rates + rrates).max/50 + 1) * 50
117       plot.yrange "[%s:%s]" % [ymin, ymax]
118       plot.grid
119       data = []
120       data << Gnuplot::DataSet.new([dates, rates]) do |ds|
121                 ds.using = "1:2"
122                 ds.with  = "lines"
123                 ds.title = "original"
124               end
125       if !rdates.empty?
126         data << Gnuplot::DataSet.new([rdates, rrates]) do |ds|
127                   ds.using = "1:2"
128                   ds.with  = "lines"
129                   ds.title = "relative (rate24)"
130                 end
131       end
132       plot.data = data
133     end
134   end  
135 end
136
137 def load_file(file_name)
138   if /^.*-(\d{8}).yaml$/ =~ file_name
139     date = Date::parse($1)
140   else
141     return
142   end
143   db = YAML::load_file(file_name)
144   return unless db['players'][0]
145   db['players'][0].each do |name, hash|
146     $players[name] ||= {}
147     $players[name][date] = hash['rate'].to_i
148   end
149 end
150
151 if $0 == __FILE__
152   def usage
153     puts "Usage: #{$0} [--output-dir dir] <players_yaml_files>..."
154     puts "Options:"
155     puts "  --output-dir dir  Images will be located in the dir."
156     exit 1
157   end
158
159   usage if ARGV.empty?
160
161   parser = GetoptLong.new
162   parser.set_options(['--output-dir', '-o', GetoptLong::REQUIRED_ARGUMENT])
163   begin
164     parser.each_option do |name, arg|
165       eval "$OPT_#{name.sub(/^--/, '').gsub(/-/, '_').upcase} = '#{arg}'"
166     end
167   rescue
168     usage
169   end
170   
171   while file = ARGV.shift
172     load_file(file)
173   end
174   
175   formats = [LargePngFormat.new($OPT_OUTPUT_DIR),
176              SmallPngFormat.new($OPT_OUTPUT_DIR),
177              SvgFormat.new($OPT_OUTPUT_DIR)]
178
179   $players.each do |name, hash|
180     dates, rates = hash.sort.transpose
181     rdates = dates.find_all do |date| 
182       $players["YSS+707d4f98d9d2620cdaab58f19d02a2e4"] &&
183       $players["YSS+707d4f98d9d2620cdaab58f19d02a2e4"][date] 
184     end
185     rrates = rdates.map do |date|
186       2300 - $players["YSS+707d4f98d9d2620cdaab58f19d02a2e4"][date] + hash[date]
187     end
188     formats.each do |format|
189       plot(format, name, dates, rates, rdates, rrates)
190     end
191   end
192 end
193