| Class | Plot |
| In: |
lib/plot.rb
|
| Parent: | Object |
| MAX_BIN | = | 35 |
| countries | [R] | |
| locations | [R] | |
| path | [R] | |
| visits | [R] |
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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