burtin#
A reproduction of Will Burtin’s historical visualization of antibiotic efficacies with some minimal changes to improve readibility.
Note
This chart is reproduced as a demonstration of Bokeh’s versatile graphics capabilities, but there are better, simpler ways to present this data.
Details
- Sampledata:
- Bokeh APIs:
- More info:
- Keywords:
text, wedges
from numpy import arange, array, cos, log, pi, sin, sqrt
from bokeh.models import ColumnDataSource, Legend, LegendItem
from bokeh.plotting import figure, show
from bokeh.sampledata.antibiotics import data as df
DRUGS = ("penicillin", "streptomycin", "neomycin")
COLORS = ("#0d3362", "#c64737", "#000000")
GRAM = dict([
("negative", "#e69584"),
("positive", "#aeaeb8"),
])
big_angle = 2 * pi / (len(df) + 1)
angles = pi/2 - 3*big_angle/2 - array(df.index) * big_angle
df["start"] = angles
df["end"] = angles + big_angle
df["colors"] = [GRAM[gram] for gram in df.gram]
source = ColumnDataSource(df)
# Burtin's unusual inverted radial sqrt-log scale
micmin = sqrt(log(.001*1E4))
micmax = sqrt(log(1000*1E4))
def scale(mic):
return - sqrt(log(mic * 1E4)) + (micmin + micmax)
p = figure(
width=800, height=800, title=None, tools="", toolbar_location=None,
x_axis_type=None, y_axis_type=None, match_aspect=True,
min_border=0, outline_line_color="black", background_fill_color="#f0e1d2",
)
# large wedges for bacteria
br = p.annular_wedge(0, 0, micmax, micmin, "start", "end", fill_color="colors", line_color="#f0e1d2", source=source)
# circular axes and labels
radii = scale(10.0 ** arange(-3, 4))
p.circle(0, 0, radius=radii, fill_color=None, line_color="#f0e1d2")
p.text(
0, radii, ["0.001", "0.01", "0.1", "1", "10", "100", "1000"],
text_font_size="12px", anchor="center",
)
# small wedges for drugs
small_angle = big_angle / 7
for i, drug in enumerate(DRUGS):
start = angles+(5-2*i)*small_angle
end = angles+(6-2*i)*small_angle
p.annular_wedge(
0, 0, micmin, scale(df[drug]), start, end,
color=COLORS[i], line_color=None, legend_label=drug,
)
# bacteria labels
r = radii[0] * 1.1
xr = r * cos(angles + big_angle/2)
yr = r * sin(angles + big_angle/2)
p.text(
xr, yr, ["\n".join(x.split()) for x in df.bacteria],
text_font_size="13px", anchor="center",
)
p.legend.location = "center"
p.legend.background_fill_alpha = 0
p.legend.glyph_width = 45
p.legend.glyph_height = 20
p.x_range.range_padding = 0.2
p.y_range.range_padding = 0.2
p.grid.grid_line_color = None
legend = Legend(items=[
LegendItem(label="Gram-positive", renderers=[br], index=10),
LegendItem(label="Gram-negative", renderers=[br], index=0),
], location="bottom", orientation="horizontal", background_fill_alpha=0)
p.add_layout(legend, 'center')
show(p)