Class Plot
In: lib/plot.rb
Parent: Object

Methods

Constants

MAX_BIN = 35

Attributes

countries  [R] 
locations  [R] 
path  [R] 
visits  [R] 

Public Class methods

[Source]

    # File lib/plot.rb, line 9
 9:   def initialize(path)
10:     @path = path
11:     @locations = Constants::Config::Admin::LOCATIONS
12:     (@countries = locations.dup).shift
13:     @visits = Visit.all(:include => [:responses, :trackings, :items, { :prompt => :items }], :order => 'visits.created_at', :conditions => "(user_id NOT IN (#{User.admin_ids.join(',')}) OR user_id IS NULL) AND user_agent NOT LIKE '%bot%'")
14:   end

Public Instance methods

[Source]

     # File lib/plot.rb, line 296
296:   def actions_plots
297:     locations.each do |country|
298:       data = country == locations.first ? visits : visits.reject { |visit| visit.ip_country_code != country }
299:       next if data.empty?
300:       freq_divided(data.map(&:trackings).flatten).zip([
301:         "Popular Hits per Action",
302:         "Unpopular Hits per Action"
303:       ], [true, false]).each do |trackings, subject, log|
304:         title = "#{country} #{subject}"
305:         trackings_plot(trackings, "#{title}#{' (log scale)' if log}", title.downcase.downcase.gsub(/ /, '_'), log) unless trackings.last.nil?
306:       end
307:     end
308: 
309:     data = split_actions_by_country.unshift(split_by_action(gather_trackings).transpose)
310:     data.zip(locations.map { |country| "#{country} Last Hits per Action" }).each do |trackings, title|
311:       trackings_plot(trackings, "#{title} (log scale)", title.downcase.gsub(/ /, '_'), true) unless trackings.last.nil?
312:     end
313:   end

[Source]

     # File lib/plot.rb, line 171
171:   def by_day
172:     today = Time.now
173:     by_day_data = [{}, {}, {}]
174:     visits.reverse.each do |visit|
175:       while (visit.created_at < today - 1.day) do today -= 1.day end
176:       locations.each do |country|
177:         by_day_data[0][country] ||= Hash.new(0)
178:         by_day_data[1][country] ||= Hash.new(0)
179:         by_day_data[2][country] ||= Hash.new(0)
180:         if country == locations.first || visit.ip_country_code == country
181:           by_day_data[0][country][today] += 1
182:           by_day_data[1][country][today] += visit.responses.length
183:           by_day_data[2][country][today] += visit.items.length
184:         end
185:       end
186:     end
187:     by_day_data.zip(
188:       ["Visitors per Day", "Votes per Day", "Uploads per Day"],
189:       ['Visitors', 'Votes', 'Uploads']
190:     )
191:   end

[Source]

     # File lib/plot.rb, line 193
193:   def by_day_plots
194:     by_day.each do |hash, subject, ylabel|
195:       locations.each do |country|
196:         data = hash[country].sort_by(&:first).transpose
197:         next if data.empty?
198:         title = "#{country} #{subject}"
199:         GNUPlotter.plot({
200:           :file_name => "#{path}#{title.dashed}",
201:           :title => title,
202:           :xlabel => "Days",
203:           :ylabel => ylabel,
204:           :data => data.last,
205:           :size => [800, 300],
206:           :font_size => 10,
207:           :xtics => data.first.sparse(20).map { |date| date && "#{date.mon}/#{date.mday}" }
208:         })
209:       end
210:     end
211:   end

[Source]

     # File lib/plot.rb, line 213
213:   def by_visitor_plots
214:     locations.each do |country|
215:       data = country == locations.first ? visits : visits.reject { |visit| visit.ip_country_code != country }
216:       next if data.empty?
217:       dates = data.sparse(20).map { |visit| visit && "#{visit.created_at.mon}/#{visit.created_at.mday}" }
218:       [["Votes", 'responses'], ["Uploads", 'items'], ["Actions", 'trackings']].each do |group, method|
219:         title = group + ' per Visitor'
220:         cur_data = data.map { |visit| visit.send(method).length }
221:         [ ['Day of Visit', cur_data, dates], ['Visit', cur_data.sort_by { |el| -el }, ['']]
222:         ].each do |xlabel, data_set, xtics|
223:         GNUPlotter.plot({
224:           :file_name => "#{path}#{country.downcase}_#{title.dashed}_#{xlabel.dashed}",
225:           :title => title,
226:           :xlabel => xlabel,
227:           :ylabel => "#{group} (log scale)",
228:           :data => data_set,
229:           :size => [800, 300],
230:           :font_size => 10,
231:           :xrange => [0, data.length],
232:           :xtics => xtics,
233:           :logscale => 'y'
234:         })
235:       end
236:       end
237:     end
238:   end

[Source]

    # File lib/plot.rb, line 57
57:   def data
58:     locations.each do |location|
59:       current_visits = (location == 'All') ? visits : visits.reject do |visit|
60:         visit.ip_country_code != location
61:       end
62:       loc = location.downcase
63:       Param.data_store("#{loc}visits_to_voters", current_visits.partition { |visit| visit.trackings.any? do |tracking|
64:         tracking.controller == 'responses' && tracking.action == 'create'
65:       end }.map(&:length))
66:       Param.data_store("#{loc}visits_to_register", current_visits.partition { |visit| !visit.user.nil? }.map(&:length))
67:       Param.data_store("#{loc}visits_to_interact", current_visits.partition { |visit| visit.trackings.length > 3 }.map(&:length))
68:     end
69:   end

[Source]

     # File lib/plot.rb, line 166
166:   def freq_divided(trackings)
167:     trackings = split_by_action(trackings)
168:     [trackings[0, trackings.length/2].transpose, trackings[trackings.length/2, trackings.length - 1].transpose]
169:   end

[Source]

    # File lib/plot.rb, line 96
96:   def gather_trackings(visits = nil)
97:     visits ||= self.visits
98:     visits.map { |visit| visit.trackings.last }.compact
99:   end

[Source]

     # File lib/plot.rb, line 267
267:   def histogram_plots
268:     votes_bins = 1
269:     uploads_bins = 1
270:     actions_bins = 1
271:     [
272:       visit_histograms(visits, :responses, votes_bins),
273:       visit_histograms(visits, :items, uploads_bins),
274:       visit_histograms(visits, :trackings, actions_bins)
275:     ].zip(["Votes Histogram", "Uploads Histogram", "Actions Histogram"],
276:       ["Votes (#{votes_bins} per bin)", "Uploads (#{uploads_bins} per bin)", "Actions (#{actions_bins} per bin)"]
277:     ).each do |hash, subject, xlabel|
278:       locations.each do |country|
279:         data = hash[country].sort_by(&:first).transpose
280:         title = "#{country} #{subject}"
281:         GNUPlotter.plot({
282:           :file_name => "#{path}#{title.downcase.gsub(/ /, '_')}",
283:           :title => "#{title} (log scale)",
284:           :xlabel => xlabel,
285:           :ylabel => "Visits",
286:           :data => data.last,
287:           :size => [800, 300],
288:           :font_size => 10,
289:           :xtics => data.first.sparse(20),
290:           :logscale => 'y'
291:         })
292:       end
293:     end
294:   end

[Source]

    # File lib/plot.rb, line 16
16:   def items
17:     questions = Question.all(:include => [:items, :groups])
18:     for question in questions
19:       stats = {}
20:       stats[@locations.first] = [
21:         Item.ratings_overall(question),
22:         Item.wins_overall(question)
23:       ]
24:       for country in countries
25:         stats[country] = [
26:           Item.ratings_for_country(question, country),
27:           Item.wins_for_country(question, country)
28:         ]
29:       end
30:       for item in question.items
31:         xtics = []
32:         count = -1
33:         data = stats.sort_by(&:first).inject([]) do |array, el|
34:           stat = el.last
35:           ratings = stat.first[item.id].to_f
36:           percent = ratings > 0 ? 100 * (stat.last[item.id] / ratings) : 0
37:           xtics << el.first
38:           array << [count += 1, percent, error(percent, ratings)]
39:         end.transpose
40:         GNUPlotter.plot({
41:           :file_name => "#{path}items/question_#{question.id}_item_#{item.id}",
42:           :title => "item #{item.id} win percent for '#{question.groups.first.name}'",
43:           :xlabel => 'country',
44:           :ylabel => 'win percent with error',
45:           :data => data,
46:           :size => [250, 250],
47:           :font_size => 10,
48:           :xtics => xtics,
49:           :xrange => [-1, data.first.length],
50:           :yrange => [0, 100],
51:           :ds => { :using => '1:2:3', :error_bars => 'errorbars' }
52:         })
53:       end
54:     end
55:   end

[Source]

     # File lib/plot.rb, line 315
315:   def last_item_plots
316:     locations.each do |country|
317:       last_visit_items = visits.inject(Hash.new(0)) do |lasts, visit|
318:         # ignore visits without any votes
319:         if (country == locations.first || country == visit.ip_country_code) && visit.trackings.any? { |tracking| tracking.action == 'create' }
320:           visit.prompt && visit.prompt.items.map(&:id).each { |id| lasts[id] += 1 }
321:         end
322:         lasts
323:       end.reject { |last| last.last <= 1 }.sort_by(&:last).transpose
324:       store_items(:last, last_visit_items.transpose) if country == locations.first
325:       GNUPlotter.plot({
326:         :file_name => "#{path}#{country.downcase}_last_visit_items",
327:         :title => "#{country} Last Visit Items (minimum last item twice)",
328:         :xlabel => "Item",
329:         :ylabel => "Times Last Seen",
330:         :data => last_visit_items.last,
331:         :size => [900, 300],
332:         :font_size => 10,
333:         :xrange => [0, last_visit_items.last.length],
334:         :yrange => [0, last_visit_items.last.max + 1]
335:       }) unless last_visit_items.empty?
336:     end
337:   end

[Source]

     # File lib/plot.rb, line 339
339:   def skipped_item_plots
340:     locations.each do |country|
341:       skipped_items = Response.all(:include => [:visit, :items, { :prompt => :items }], :conditions => 'items_responses.item_id IS NULL').inject(Hash.new(0)) do |skipped, response|
342:         response.prompt.items.map(&:id).each { |id| skipped[id] += 1 } if country == locations.first || country == response.visit.ip_country_code
343:         skipped
344:       end.reject { |skip| skip.last <= 1 }.sort_by(&:last).transpose
345:       store_items(:skipped, skipped_items.transpose) if country == locations.first
346:       GNUPlotter.plot({
347:         :file_name => "#{path}#{country.downcase}_skipped_items",
348:         :title => "#{country} Skipped Items (minimum skipped twice)",
349:         :xlabel => "Item",
350:         :ylabel => "Skip Count",
351:         :data => skipped_items.last,
352:         :size => [900, 300],
353:         :font_size => 10,
354:         :xrange => [0, skipped_items.last.length],
355:         :yrange => [0, skipped_items.last.max + 1]
356:       }) unless skipped_items.empty?
357:     end
358:   end

[Source]

     # File lib/plot.rb, line 101
101:   def split_actions_by_country
102:     countries.map do |country|
103:       split_by_action(gather_trackings(visits.select { |visit| visit.ip_country_code == country })).transpose
104:     end
105:   end

[Source]

     # File lib/plot.rb, line 107
107:   def split_by_action(trackings)
108:     trackings.inject(Hash.new(0)) do |hash, tracking|
109:       case tracking.controller
110:       when 'responses'
111:         case tracking.action
112:         when 'new'
113:           hash['vote'] += 1
114:         when 'index'
115:           hash['recent winners'] += 1
116:         when 'create'
117:           hash['[vote]'] += 1
118:         end
119:       when 'items'
120:         case tracking.action
121:         when 'new'
122:           hash['upload'] += 1
123:         when 'index'
124:           hash['list photos'] += 1
125:         when 'show'
126:           hash['view photo'] += 1
127:         when 'create'
128:           hash['[upload]'] += 1
129:         when 'comment'
130:           hash['[comment]'] += 1
131:         end
132:       when 'sessions'
133:         case tracking.action
134:         when 'destroy'
135:           hash['[logout]'] += 1
136:         when 'new'
137:           hash['login'] += 1
138:         when 'create'
139:           hash['[login]'] += 1
140:         end
141:       when 'users'
142:         case tracking.action
143:         when 'new'
144:           hash['signup'] += 1
145:         when 'create'
146:           hash['[signup]'] += 1
147:         end
148:       when 'profiles'
149:         case tracking.action
150:         when 'show'
151:           hash['view profile'] += 1
152:         when 'new'
153:           hash['new profile'] += 1
154:         when 'edit'
155:           hash['edit profile'] += 1
156:         when 'create'
157:           hash['[create profile]'] += 1
158:         when 'update'
159:           hash['[update profile]'] += 1
160:         end
161:       end
162:       hash
163:     end.sort_by { |array| -array.last }
164:   end

[Source]

    # File lib/plot.rb, line 80
80:   def trackings_plot(trackings, title, filename, log = true)
81:     options = {
82:       :file_name => "#{path}#{filename}",
83:       :title => title,
84:       :xlabel => "Action",
85:       :ylabel => "Hits",
86:       :data => trackings.last,
87:       :size => [900, 300],
88:       :font_size => 10,
89:       :xrange => [-1, trackings.last.length],
90:       :xtics => trackings.first
91:     }
92:     options.merge!(:logscale => 'y') if log
93:     GNUPlotter.plot(options)
94:   end

[Source]

    # File lib/plot.rb, line 71
71:   def usage
72:     by_day_plots
73:     histogram_plots
74:     by_visitor_plots
75:     actions_plots
76:     last_item_plots
77:     skipped_item_plots
78:   end

[Source]

     # File lib/plot.rb, line 240
240:   def visit_histograms(visits, method, increment, min = 0)
241:     histograms = {}
242:     visits_hash = locations.inject({}) do |hash, country|
243:       hash[country] = visits.dup
244:       histograms[country] = { min => hash[country].find_all { |visit|
245:         visit.send(method).length == min && visit_for_country?(country, visit)
246:       } }
247:       hash[country] -= histograms[country][min]
248:       histograms[country][min] = histograms[country][min].length
249:       hash
250:     end
251: 
252:     currents = locations.inject({}) { |hash, country| hash[country] = increment; hash }
253:     while !visits_hash[locations.first].flatten.empty? do
254:       locations.each do |country|
255:         histograms[country][currents[country]] = visits_hash[country].find_all do |visit|
256:           num_visits = visit.send(method).length
257:           num_visits > min && visit_for_country?(country, visit) && (currents[country] > MAX_BIN || num_visits <= currents[country])
258:         end
259:         visits_hash[country] -= histograms[country][currents[country]]
260:         histograms[country][currents[country]] = histograms[country][currents[country]].length
261:         currents[country] += increment
262:       end
263:     end
264:     histograms
265:   end

[Validate]