Модный график с помощью «Bokeh»

Опубликовано Опубликовано в рубрике Интересное, Рецепты

Сегодня в читалку свалилась статья из Analitics Vidhya о хитром фреймворке для построения динамических графиков «Bokeh» . Быстро пролистав ее, хотел было распрощаться, так как в статье приведены примеры на Python. Но потом пригляделся и увидел, что у этого фреймворка есть реализация для очень многих языков, в том числе для R. Следовательно – неплохо бы ознакомиться, чтобы понять – нужно ли складывать это в свою библиотеку полезных навыков.

Сами примеры в статье не особо вдохновляли – поэтому решил посмотреть, вообще что народ делает с помощью этой библиотеки. Зашел на страницу проекта в Галлерею, полистал что есть. Особо ничего не зацепило – но вот одна картинка была интересная. Такую часто можно встретить в различной Инфографике, и вообще одна из популярных по этой теме в Pinterest.

Отлично – вот ее мы и научимся делать. Но, есть одна загвоздка – реализация этого есть только на Python.
Ну вот, и интересный вызов. Посмотрим – насколько идентична реализация библиотеки для Python и для R.
Для начала — надо установить библиотеку и нужную библиотеке библиотеку (sic)!. Ее нет на CRAN, брать надо с github


devtools::install_github("ramnathv/htmlwidgets")
devtools::install_github("bokeh/rbokeh")
library(rbokeh)

Далее — строкой заливаем данные, и хитрым образом создаем из этой строки dataframe:

antibiotics <-
"bacteria, penicillin, streptomycin, neomycin, gram
Mycobacterium tuberculosis, 800, 5, 2, negative
Salmonella schottmuelleri, 10, 0.8, 0.09, negative
Proteus vulgaris, 3, 0.1, 0.1, negative
Klebsiella pneumoniae, 850, 1.2, 1, negative
Brucella abortus, 1, 2, 0.02, negative
Pseudomonas aeruginosa, 850, 2, 0.4, negative
Escherichia coli, 100, 0.4, 0.1, negative
Salmonella (Eberthella) typhosa, 1, 0.4, 0.008, negative
Aerobacter aerogenes, 870, 1, 1.6, negative
Brucella antracis, 0.001, 0.01, 0.007, positive
Streptococcus fecalis, 1, 1, 0.1, positive
Staphylococcus aureus, 0.03, 0.03, 0.001, positive
Staphylococcus albus, 0.007, 0.1, 0.001, positive
Streptococcus hemolyticus, 0.001, 14, 10, positive
Streptococcus viridans, 0.005, 10, 40, positive
Diplococcus pneumoniae, 0.005, 11, 10, positive"

con <- textConnection(antibiotics)
df <- read.csv(con, stringsAsFactors = FALSE)
close(con)
df$gram <- trimws(df$gram)

Извините, дальше просто приведу код — желания комментировать каждую строку нет. Основные моменты что происходит, пометил в коде комментариями. Надеюсь, получился довольно Reproducibility код.

#Задаем цвета
Penicillin_color <- "#0d3362"
Streptomycin_color <- "#c64737"
Neomycin_color <- "black"

df$colors <- NA
df[df$gram=='positive',]$colors <- "#aeaeb8"
df[df$gram=='negative',]$colors <- "#e69584"

###########################
width <- 1200
height <- 1200
inner_radius <- 90
outer_radius <- 300 - 10

minr <- sqrt(log(.001 * 1E4))
maxr <- sqrt(log(1000 * 1E4))
a <- (outer_radius - inner_radius) / (minr - maxr)
b <- inner_radius - a * maxr

rad <- function(mic)
{
return (a * sqrt(log(mic * 1E4)) + b)
}

big_angle <- 2.0 * pi / (nrow(df) + 1)
small_angle <- big_angle / 7

x <- rep(0,nrow(df))
y <- rep(0,nrow(df))

p <- figure(plot_width=width, plot_height=height, title="", xlim=c(-420, 420), ylim =c(-420, 420), min_border=0, outline_line_color="black", background_fill="#f0e1d2", border_fill="#f0e1d2") %>%
ly_lines( x=x+1, y=y+1, alpha=0)

#Основное кольцо
angles <- pi/2 - big_angle/2 - 0:(nrow(df)-1)*big_angle colors = df$colors p <- p %>%
ly_annular_wedge(x, y=y,
inner_radius=inner_radius,
outer_radius=outer_radius,
start_angle=-big_angle+angles,
end_angle=angles,
color=colors)

#Маленькие клинья
p <- p %>%
ly_annular_wedge(x, y,
inner_radius=inner_radius,
outer_radius=rad(df$penicillin),
start_angle=-big_angle+angles+5small_angle,
end_angle=-big_angle+angles+6
small_angle,
color=Penicillin_color) %>%
ly_annular_wedge(x, y,
inner_radius=inner_radius,
outer_radius=rad(df$streptomycin),
start_angle=-big_angle+angles+3small_angle,
end_angle=-big_angle+angles+4
small_angle,
color=Streptomycin_color) %>%
ly_annular_wedge(x, y,
inner_radius=inner_radius,
outer_radius=rad(df$neomycin),
start_angle=-big_angle+angles+1small_angle,
end_angle=-big_angle+angles+2
small_angle,
color=Neomycin_color)

#Круговые оси и метки
labels = 10.0^ seq(-3, 4)
radii = a * sqrt(log(labels * 1E4)) + b
p <- p %>%
ly_arc(x, y, radius=radii, line_color="white") %>%
ly_text(x, radii,text= labels,font_size="8pt",align = "center",baseline="middle")

#Радиальные оси
p <- p %>%
ly_annular_wedge(x, y,
inner_radius=inner_radius-10,
outer_radius=outer_radius+10,
start_angle=-big_angle+angles,
end_angle=-big_angle+angles,
color="black")

#Подпишем бактерии
xr = radii[1]cos(array(-big_angle/2 + angles))
yr = radii[1]
sin(array(-big_angle/2 + angles))
label_angle=array(-big_angle/2+angles)

label_angle[label_angle < -pi/2] <- label_angle[label_angle < -pi/2] + pi # easier to read labels on the left side p <- p %>%
ly_text(xr, yr, text=df$bacteria, angle=label_angle,
font_size="9pt", align="center", baseline="middle")

#Нарисуем легенду
p <- p %>%
ly_arc(c(-40, -40), c(-370, -390), color=unique(df$colors), radius=5) %>%
ly_text(c(-30, -30), c(-370, -390), text=paste0("Gram-",c('positive','negative')),
font_size="7pt", align="left", baseline="middle") %>%
ly_rect(c(-40, -40, -40),c(18,0,-18),
xright = c(-40, -40, -40)+30, ytop=c(18,0,-18)+13,
color=c(Penicillin_color,Streptomycin_color,Neomycin_color)) %>%
ly_text(c(-15, -15, -15), c(18, 0, -18),
text=c('Penicillin','Streptomycin','Neomycin'),
font_size="9pt", align="left", baseline="middle")

#Спрячем оси
p <- p %>% x_axis(visible=FALSE)
p<- p %>% y_axis(visible=FALSE)

#Выводим график
print(p)

В результате — рисуется вот такой вот симпатичный html

Вывод — библиотека довольно годная и интересная — можно ее использовать в работе.
Вывод 2 — теперь, когда понятно как вычисляются все эти углы и диапазоны — вполне реально попробовать реализовать такое в том же ggplot2

Добавить комментарий