1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
# = Antibiotic Effectiveness : Pie chart
# After World War II, antibiotics earned the moniker “wonder drugs” for quickly treating previously-incurable diseases. Data was gathered to determine which drug worked best for each bacterial infection. Comparing drug performance was an enormous aid for practitioners and scientists alike. In the fall of 1951, Will Burtin published this graph showing the effectiveness of three popular antibiotics on 16 different bacteria, measured in terms of minimum inhibitory concentration.
# Recreating this display revealed some minor errors in the original: a missing grid line at 0.01 μg/ml, and an exaggeration of some values for penicillin.
$:.unshift(File.dirname(__FILE__)+"/../../../lib")
require 'rubyvis'
load(File.dirname(__FILE__)+"/antibiotics_data.rb")
width = 700
height = 700
inner_radius = 90
outer_radius = 300 - 10
drug_color = {
:penicillin=> "rgb(10, 50, 100)",
:streptomycin=> "rgb(200, 70, 50)",
:neomycin=> "black"
}
gram_color = {
:positive=> "rgba(174, 174, 184, .8)",
:negative=> "rgba(230, 130, 110, .8)"
}
# Burtin's radius encoding is, as far as I can tell, sqrt(log(mic)).
min = Math.sqrt(Math.log(0.001 * 1e4))
max = Math.sqrt(Math.log(1000 * 1e4))
a = (outer_radius - inner_radius) / (min - max.to_f)
b = inner_radius - a * max
radius = lambda {|mic| a * Math.sqrt(Math.log(mic * 1e4)) + b}
# The pie is split into equal sections for each bacteria, with a blank
# section at the top for the grid labels. Each wedge is further
# subdivided to make room for the three antibiotics, equispaced.
big_angle = 2.0 * Math::PI / ($bacteria.length + 1.0)
small_angle = big_angle / 7.0
#/* The root panel. */
vis = Rubyvis::Panel.new.
width(width).
height(height).
bottom(100);
# Background wedges to indicate gram staining color.
bg = vis.add(Rubyvis::Wedge).
data($bacteria). # assumes Burtin's order
left(lambda {|i| width / 2.0}).
top(height / 2.0).
inner_radius(inner_radius).
outer_radius(outer_radius).
angle(big_angle).
start_angle(lambda {|d|
index * big_angle + big_angle / 2.0 - Math::PI / 2.0
}).
fill_style(lambda {|d|
Rubyvis.color(gram_color[d[:gram].to_sym])
})
# Antibiotics.
bg.add(Rubyvis::Wedge).
angle(small_angle).
start_angle(lambda {|d|
bg.start_angle() + small_angle
}).
outer_radius(lambda {|d|
radius.call(d[:penicillin])
}).
fill_style(drug_color[:penicillin]).
add(Rubyvis::Wedge).
start_angle(lambda {|d|
proto.start_angle() + 2 * small_angle}).
outer_radius(lambda {|d|
radius.call(d[:streptomycin])
}).
fill_style(drug_color[:streptomycin]).
add(Rubyvis::Wedge).
outer_radius(lambda {|d|
radius.call(d[:neomycin])
}).
fill_style(drug_color[:neomycin])
# Circular grid lines.
bg.add(Rubyvis::Dot)
.data(Rubyvis.range(-3, 4))
.fill_style(nil)
.stroke_style("#eee")
.line_width(1)
.shape_size(lambda {|i|
radius.call(10**i)** 2
}).
anchor("top").add(Rubyvis::Label).
visible(lambda {|i| i < 3}).
text_baseline("middle").
text(lambda {|i|
i<0 ? (10** i).to_f : (10**i).to_i
})
# Radial grid lines.
bg.add(Rubyvis::Wedge)
.data(Rubyvis.range($bacteria.size + 1))
.inner_radius(inner_radius - 10)
.outer_radius(outer_radius + 10)
.fill_style(nil)
.stroke_style("black")
.angle(0)
# Labels.
bg.anchor("outer").add(Rubyvis::Label)
.text_align("center")
.text(lambda {|d| d[:name]})
# Antibiotic legend.
vis.add(Rubyvis::Bar)
.data(Rubyvis.keys(drug_color))
.right(width / 2 + 3)
.top(lambda { height / 2.0 - 28 + self.index * 18})
.fill_style(lambda {|d| drug_color[d]})
.width(36)
.height(12)
.anchor("right").add(Rubyvis::Label)
.textMargin(6)
.textAlign("left");
# Gram-stain legend.
vis.add(Rubyvis::Dot).
data([:positive, :negative]).
left(width / 2.0 - 20).
bottom(lambda { -60 + index * 18}).
fill_style(lambda {|d| gram_color[d]}).
stroke_style(nil).
shape_size(30).
anchor("right").add(Rubyvis::Label).
text_margin(6).
text_align("left").
text(lambda {|d| "Gram-#{d}"})
vis.render
puts vis.to_svg
|