snip2codewfreelandecon
snip2codewfreelandecon
Reputation Top 10%
WFreelandEcon @ Snip2Code
1 Snippet  (336th place)
Published
1 Channel
Created
1 Channel
Following
31 points  (1120th place)
Reputation
Junior Popular Coder
Junior Autobiographer
Senior Autobiographer
Junior Famous Coder

Recent Snippets See all snippets by snip2codewfreelandecon

public by WFreelandEcon  1215  1  4  0

Command line bar chart from JSON data (for GeekTool, et al)

Command line bar chart from JSON data (for GeekTool, et al): barchart.rb
#!/usr/bin/env ruby
# encoding: utf-8
# Brett Terpstra 2013, WTF license <http://www.wtfpl.net/txt/copying/>

# Outputs a vertical bar chart from date-based JSON data
# Requires the JSON rubygem: `[sudo] gem install json`
require 'date'
require 'open-uri'
require 'rubygems'
require 'json'

# Data source URL (sample output at the end of script)
data_url = "http://api.feedpress.it/feeds/..."
# Parent container key for data object
main_container = 'stats'
# Repeated key for date/stats objects
date_container = 'day'
# keys for amounts to collect
total_containers = ['greader','other','direct']

# How many columns to output
columns = 30
# Total height will be determined by min and max valudes
# scaled to max_rows
max_rows = 15

# If "test" is passed as an argument, load test data from end of script
if ARGV[0] == "test" || !data_url || data_url.strip == ""
    input = DATA.read
    columns = 30
    max_rows = 18
    main_container = 'stats'
    date_container = 'day'
    total_containers = ['greader','other','direct']
else
# Otherwise, read data from the data url
    input = open(URI.parse(data_url)).read
end

json = JSON.parse(input)

# Create two arrays, one for dates and one for totals
dates = []
totals = []
# Step through data objects to populate both arrays sequentially
json[main_container].each { |day|
    dates.push(Time.at(day[date_container]).to_datetime.strftime('%m/%d'))
    total = 0
    for item in total_containers
        total += day[item].to_i
    end

    totals.push(total)
}

# Find the highest and lowest values to determine bar heights
max = totals.sort[-1]
min = totals.sort[0]

# Trim data arrays down to the maximum number of columns 
# defined above
dates = dates.reverse[0..columns]
totals = totals.reverse[0..columns]

# Determine number or rows to generate
topline = max_rows
div = max / topline
bottomline = min/div

# Output each row. If the total for the column is greater
# than or equal to the scaled row counter, output a chunk 
# of the bar
topline.times do
    totals.each { |num|
        if num / div > topline
            print "◼ "
        else
            print "  "
        end
    }
    if topline + (max_rows/10).round == bottomline
        puts
        break
    else
        topline -= 1
        puts
    end
end

# Calculate average across all totals
avg = totals.inject(0.0) { |sum, el| sum + el } / totals.size

# Output a legend with today, peak and average
puts "#{dates[0]} - #{dates[-1]} ⇒Today: #{totals[-1]} | Peak: #{max} | Average: #{avg.round}"
puts

# Sample data for testing
__END__

{
    "stats": [
        {
            "day": 1382914800,
            "greader": 10195,
            "other": 4409,
            "direct": 879,
            "newsletter": 0
        },
        {
            "day": 1382824800,
            "greader": 10174,
            "other": 4327,
            "direct": 843,
            "newsletter": 0
        },
        {
            "day": 1382738400,
            "greader": 10172,
            "other": 4173,
            "direct": 861,
            "newsletter": 0
        },
        {
            "day": 1382652000,
            "greader": 10182,
            "other": 4195,
            "direct": 853,
            "newsletter": 0
        },
        {
            "day": 1382565600,
            "greader": 10163,
            "other": 4207,
            "direct": 851,
            "newsletter": 0
        },
        {
            "day": 1382479200,
            "greader": 10135,
            "other": 4206,
            "direct": 839,
            "newsletter": 0
        },
        {
            "day": 1382392800,
            "greader": 8196,
            "other": 4437,
            "direct": 850,
            "newsletter": 0
        },
        {
            "day": 1382306400,
            "greader": 8181,
            "other": 4482,
            "direct": 819,
            "newsletter": 0
        },
        {
            "day": 1382220000,
            "greader": 9968,
            "other": 4413,
            "direct": 858,
            "newsletter": 0
        },
        {
            "day": 1382133600,
            "greader": 9972,
            "other": 4413,
            "direct": 859,
            "newsletter": 0
        },
        {
            "day": 1382047200,
            "greader": 10050,
            "other": 4375,
            "direct": 842,
            "newsletter": 0
        },
        {
            "day": 1381960800,
            "greader": 10056,
            "other": 4310,
            "direct": 821,
            "newsletter": 0
        },
        {
            "day": 1381874400,
            "greader": 10048,
            "other": 4153,
            "direct": 773,
            "newsletter": 0
        },
        {
            "day": 1381788000,
            "greader": 10052,
            "other": 4108,
            "direct": 733,
            "newsletter": 0
        },
        {
            "day": 1381701600,
            "greader": 10055,
            "other": 4228,
            "direct": 701,
            "newsletter": 0
        },
        {
            "day": 1381615200,
            "greader": 10062,
            "other": 4371,
            "direct": 650,
            "newsletter": 0
        },
        {
            "day": 1381528800,
            "greader": 10079,
            "other": 4474,
            "direct": 623,
            "newsletter": 0
        },
        {
            "day": 1381442400,
            "greader": 10112,
            "other": 4590,
            "direct": 584,
            "newsletter": 0
        },
        {
            "day": 1381356000,
            "greader": 10245,
            "other": 4789,
            "direct": 571,
            "newsletter": 0
        },
        {
            "day": 1381269600,
            "greader": 10150,
            "other": 5101,
            "direct": 585,
            "newsletter": 0
        },
        {
            "day": 1381183200,
            "greader": 10155,
            "other": 5255,
            "direct": 583,
            "newsletter": 0
        },
        {
            "day": 1381096800,
            "greader": 10172,
            "other": 5266,
            "direct": 554,
            "newsletter": 0
        },
        {
            "day": 1381010400,
            "greader": 10201,
            "other": 5247,
            "direct": 585,
            "newsletter": 0
        },
        {
            "day": 1380924000,
            "greader": 10232,
            "other": 5285,
            "direct": 582,
            "newsletter": 0
        },
        {
            "day": 1380837600,
            "greader": 10235,
            "other": 5349,
            "direct": 570,
            "newsletter": 0
        },
        {
            "day": 1380751200,
            "greader": 10267,
            "other": 5288,
            "direct": 556,
            "newsletter": 0
        },
        {
            "day": 1380664800,
            "greader": 10308,
            "other": 5042,
            "direct": 540,
            "newsletter": 0
        },
        {
            "day": 1380578400,
            "greader": 10328,
            "other": 4828,
            "direct": 551,
            "newsletter": 0
        },
        {
            "day": 1380492000,
            "greader": 10364,
            "other": 4630,
            "direct": 574,
            "newsletter": 0
        },
        {
            "day": 1380405600,
            "greader": 10350,
            "other": 4479,
            "direct": 597,
            "newsletter": 0
        }
    ],
    "code": 1
}


;