github の puhch card みたいなのを自分で生成したいと思って cairo を使って描いてみた。
ChangeLog が元データなので、日本時間である。
また、円の面積が ChangeLog の項目数に比例する。
stat-changelog.rb:
#!/usr/bin/ruby1.8 # usage: # ./stat-changelog.rb ruby/{ChangeLog,doc/ChangeLog-1.9.3,doc/ChangeLog-1.8.0} require 'time' WDAYS = %w[Sun Mon Tue Wed Thu Fri Sat] MONTHS = %w[Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec] h = Hash.new(0) ARGF.each {|line| if /\A((?:#{Regexp.union WDAYS})\s+(#{Regexp.union MONTHS})\s+\d+\s+\d\d:\d\d:\d\d\s+\d+)/o =~ line t = Time.parse($1) k = [t.wday, t.hour] h[k] += 1 end } max = 0 h.each_value {|n| max = n if max < n } if max == 0 puts 'no data' exit end require 'cairo' require 'pango' format = Cairo::FORMAT_ARGB32 radius = 20 diameter = radius * 2 width = diameter * (1+24) height = diameter * (1+7) surface = Cairo::ImageSurface.new(format, width, height) context = Cairo::Context.new(surface) # background context.set_source_rgb(1, 1, 1) # white context.rectangle(0, 0, width, height) context.fill context.set_source_rgb(0, 0, 0) # black hour_layouts = [] 0.upto(23) {|hour| layout = context.create_pango_layout layout.text = "%02d" % hour layout.width = diameter * Pango::SCALE layout.alignment = Pango::ALIGN_CENTER hour_layouts << layout } max_height = hour_layouts.map {|layout| layout.size[1] }.max hour_layouts.each_with_index {|layout, hour| context.save { context.translate((1+hour) * diameter, radius - max_height / Pango::SCALE / 2) context.show_pango_layout(layout) } } wday_layouts = [] 0.upto(6) {|wday| layout = context.create_pango_layout layout.text = WDAYS[wday] layout.width = diameter * Pango::SCALE wday_layouts << layout } max_width = wday_layouts.map {|layout| layout.size[0] }.max max_height = wday_layouts.map {|layout| layout.size[1] }.max wday_layouts.each_with_index {|layout, wday| context.save { context.translate(radius - max_width / Pango::SCALE / 2, (1+wday) * diameter + radius - max_height / Pango::SCALE / 2) context.show_pango_layout(layout) } } 0.upto(6) {|wday| 0.upto(23) {|hour| n = h[[wday, hour]] r = Math.sqrt(n) / Math.sqrt(max) * radius context.arc((1+hour) * diameter + radius, (1+wday) * diameter + radius, r, 0, 2 * Math::PI) context.fill } } surface.write_to_png("changelog.png") system("feh changelog.png")
Debian Bug #596492 - The unit of the amount of CPU time for RLIMIT_RTTIME
R の ggplot2 というのが良いらしいと聞いたので試してみる。(データは Wikipedia から)
bmi-gnu_r-ggplot.R:
library(ggplot2) names <- c("唯", "澪", "律", "紬", "梓", "さわ子", "和", "憂") heights <- c(156, 160, 154, 157, 150, 165, 158, 154) weights <- c(50, 54, 48, 53, 46, 56, 52, 50) data <- data.frame(name=names, height=heights, weight=weights) bmi <- function(b) function(w) sqrt(w/b)*100 x = seq(40,60,1) p <- ggplot() + xlim(40,60) + ylim(140,180) p <- p + geom_text(aes(x=data$weight, y=data$height, label=data$name)) p <- p + xlab("体重[kg]") + ylab("身長[cm]") p <- p + geom_line(aes(x=x, y=bmi(18.5)(x))) p <- p + geom_line(aes(x=x, y=bmi(25)(x))) p <- p + geom_line(aes(x=x, y=bmi(30)(x))) p <- p + geom_line(aes(x=x, y=bmi(40)(x))) p <- p + geom_text(aes(x=45,y=170,label="低体重")) p <- p + geom_text(aes(x=58,y=170,label="普通")) p <- p + geom_text(aes(x=58,y=145,label="前肥満")) print(p)
みなさん普通で健康的ですな。
それはそれとして、曲線を端まで描く方法がわからない。
coord_cartesian() を使えばいいのか。
bmi-gnu_r-ggplot-2.R:
library(ggplot2) names <- c("唯", "澪", "律", "紬", "梓", "さわ子", "和", "憂") heights <- c(156, 160, 154, 157, 150, 165, 158, 154) weights <- c(50, 54, 48, 53, 46, 56, 52, 50) data <- data.frame(name=names, height=heights, weight=weights) bmi <- function(b) function(w) sqrt(w/b)*100 xx = seq(40,60,1) p <- ggplot() p <- p + coord_cartesian(xlim=c(40,60), ylim=c(140,170)) p <- p + scale_y_continuous(breaks=seq(140,180,by=10)) p <- p + geom_ribbon(aes(x=xx, ymin=bmi(18.5)(xx), ymax=180), fill="skyblue", alpha=0.5) p <- p + geom_ribbon(aes(x=xx, ymin=bmi(25)(xx), ymax=bmi(18.5)(xx)), fill="lightgreen", alpha=0.5) p <- p + geom_ribbon(aes(x=xx, ymin=bmi(30)(xx), ymax=bmi(25)(xx)), fill="yellow3", alpha=0.5) p <- p + geom_ribbon(aes(x=xx, ymin=130, ymax=bmi(30)(xx)), fill="orangered", alpha=0.5) p <- p + geom_text(aes(x=data$weight, y=data$height, label=data$name)) p <- p + xlab("体重[kg]") + ylab("身長[cm]") p <- p + geom_line(aes(x=xx, y=bmi(18.5)(xx))) p <- p + geom_line(aes(x=xx, y=bmi(25)(xx))) p <- p + geom_line(aes(x=xx, y=bmi(30)(xx))) p <- p + geom_line(aes(x=xx, y=bmi(40)(xx))) p <- p + geom_text(aes(x=44,y=163,label="低体重(BMI: 〜18.5)")) p <- p + geom_text(aes(x=44,y=143,label="普通(BMI: 18.5〜25)")) p <- p + geom_text(aes(x=56,y=143,label="前肥満(BMI: 25〜30)")) print(p)
ぐらでーしょん
bmi-gnu_r-ggplot-3.R:
library(ggplot2) names <- c("唯", "澪", "律", "紬", "梓", "さわ子", "和", "憂") heights <- c(156, 160, 154, 157, 150, 165, 158, 154) weights <- c(50, 54, 48, 53, 46, 56, 52, 50) data <- data.frame(name=names, height=heights, weight=weights) bmi <- function(b) function(w) sqrt(w/b)*100 xx <- seq(40,60,0.2) yy <- seq(140,170,0.2) bmi_w <- rep(xx, length(yy)) bmi_h <- rep(yy, rep(length(xx), length(yy))) bmi_bmi <- bmi_w / (bmi_h/100)^2 bmi_table <- data.frame(w=bmi_w, h=bmi_h, BMI=bmi_bmi) p <- ggplot() p <- p + coord_cartesian(xlim=c(40,60), ylim=c(140,170)) p <- p + scale_y_continuous(breaks=seq(140,180,by=10)) p <- p + scale_fill_gradient2(low="blue", mid="green", high="red", midpoint=22) p <- p + geom_tile(data=bmi_table, aes(x=w, y=h, z=BMI, fill=BMI, alpha=0.7)) p <- p + geom_text(aes(x=data$weight, y=data$height, label=data$name)) p <- p + xlab("体重[kg]") + ylab("身長[cm]") p <- p + geom_line(aes(x=xx, y=bmi(18.5)(xx))) p <- p + geom_line(aes(x=xx, y=bmi(25)(xx))) p <- p + geom_line(aes(x=xx, y=bmi(30)(xx))) p <- p + geom_line(aes(x=xx, y=bmi(40)(xx))) p <- p + geom_text(aes(x=44,y=163,label="低体重(BMI: 〜18.5)")) p <- p + geom_text(aes(x=44,y=143,label="普通(BMI: 18.5〜25)")) p <- p + geom_text(aes(x=56,y=143,label="前肥満(BMI: 25〜30)")) print(p)
凡例に alpha の 0.7 が出てくるのはわからない。
[latest]