sociales - ¿Cómo hacer un diagrama de rayos solares en R o Python?
r vs python 2018 (7)
Aquí hay un sunburst ggplot2
con dos capas.
La idea básica es simplemente hacer una barra diferente para cada capa, y hacer que las barras sean más anchas para las capas externas. También me metí con el eje x para asegurarme de que no haya ningún agujero en el medio del gráfico circular interior. De este modo, puede controlar el aspecto de la ráfaga de luz cambiando los valores de ancho y eje x.
library(ggplot2)
# make some fake data
df <- data.frame(
''level1''=c(''a'', ''a'', ''a'', ''a'', ''b'', ''b'', ''c'', ''c'', ''c''),
''level2''=c(''a1'', ''a2'', ''a3'', ''a4'', ''b1'', ''b2'', ''c1'', ''c2'', ''c3''),
''value''=c(.025, .05, .027, .005, .012, .014, .1, .03, .18))
# sunburst plot
ggplot(df, aes(y=value)) +
geom_bar(aes(fill=level1, x=0), width=.5, stat=''identity'') +
geom_bar(aes(fill=level2, x=.25), width=.25, stat=''identity'') +
coord_polar(theta=''y'')
La única desventaja que tiene en comparación con el software específico de Sunburst es que supone que desea que las capas externas sean colectivamente exhaustivas (es decir, sin espacios). Las capas exteriores "parcialmente exhaustivas" (como en algunos de los otros ejemplos) son seguramente posibles pero más complicadas.
Para completar, aquí se limpia con formatos y etiquetas más agradables:
library(data.table)
# compute cumulative sum for outer labels
df <- data.table(df)
df[, cumulative:=cumsum(value)-(value/2)]
# store labels for inner circle
inner_df <- df[, c(''level1'', ''value''), with=FALSE]
inner_df[, level1_value:=sum(value), by=''level1'']
inner_df <- unique(text_df[, c(''level1'', ''level1_value''), with=FALSE])
inner_df[, cumulative:=cumsum(level1_value)]
inner_df[, prev:=shift(cumulative)]
inner_df[is.na(prev), position:=(level1_value/2)]
inner_df[!is.na(prev), position:=(level1_value/2)+prev]
colors <- c(''#6a3d9a'', ''#1F78B4'', ''#33A02C'', ''#3F146D'', ''#56238D'', ''#855CB1'', ''#AD8CD0'', ''#08619A'', ''#3F8DC0'', ''#076302'', ''#1B8416'', ''#50B74B'')
colorNames <- c(unique(as.character(df$level1)), unique(as.character(df$level2)))
names(colors) <- colorNames
ggplot(df, aes(y=value, x='''')) +
geom_bar(aes(fill=level2, x=.25), width=.25, stat=''identity'') +
geom_bar(aes(fill=level1, x=0), width=.5, stat=''identity'') +
geom_text(data=inner_df, aes(label=level1, x=.05, y=position)) +
coord_polar(theta=''y'') +
scale_fill_manual('''', values=colors) +
theme_minimal() +
guides(fill=guide_legend(ncol=1)) +
labs(title='''') +
scale_x_continuous(breaks=NULL) +
scale_y_continuous(breaks=df$cumulative, labels=df$level2, 5) +
theme(axis.title.x=element_blank(), axis.title.y=element_blank(), panel.border=element_blank(), panel.grid=element_blank())
Hasta ahora no he podido encontrar una biblioteca R que pueda crear una trama de rayos solares como la de John Stasko . ¿Alguien sabe cómo lograr eso en R o Python?
Como jbkunst mencionó ggsunburst, aquí publico un ejemplo para reproducir el sunburst con sirex.
No es exactamente lo mismo porque en ggsunburst el ángulo de un nodo es igual a la suma de los ángulos de sus nodos hijos.
# install ggsunburst package
if (!require("ggplot2")) install.packages("ggplot2")
if (!require("rPython")) install.packages("rPython")
install.packages("http://genome.crg.es/~didac/ggsunburst/ggsunburst_0.0.9.tar.gz", repos=NULL, type="source")
library(ggsunburst)
# dataframe
# each row corresponds to a node in the hierarchy
# parent and node are required, the rest are optional attributes
# the attributes correspond to the node, not its parent
df <- read.table(header = T, sep = ",", text = "
parent,node,size,color,dist
,/,,B,1
/,home,,D,1
home,Images, 40,E,1
home,Videos, 20,E,1
home,Documents, 5,E,1
/,usr,,D,1
usr,src,,A,1
src,linux-headers, 4,C,1.5
src,virtualbox, 1,C,1.5
usr,lib, 4,A,1
usr,share, 2,A,1
usr,bin, 1,A,1
usr,local, 1,A,1
usr,include, 1,A,1
")
write.table(df, ''df.csv'', sep = ",", row.names = F)
# compute coordinates from dataframe
# "node_attributes" is used to pass the attributes other than "size" and "dist",
# which are special attributes that alter the dimensions of the nodes
sb <- sunburst_data(''df.csv'', sep = ",", type = "node_parent", node_attributes = "color")
# plot
sunburst(sb, node_labels = T, node_labels.min = 10, rects.fill.aes = "color") +
scale_fill_brewer(palette = "Set1", guide = F)
Hay un paquete llamado ggsunburst
. Lamentablemente no está en CRAN pero puede instalar siguiendo las instrucciones en el sitio web: http://genome.crg.es/~didac/ggsunburst/ggsunburst.html .
Espero que ayude a las personas que todavía buscan un buen paquete como este.
Saludos,
Incluso puedes construir una versión interactiva con bastante facilidad con R ahora:
# devtools::install_github("timelyportfolio/sunburstR")
library(sunburstR)
# read in sample visit-sequences.csv data provided in source
# https://gist.github.com/kerryrodden/7090426#file-visit-sequences-csv
sequences <- read.csv(
system.file("examples/visit-sequences.csv",package="sunburstR")
,header=F
,stringsAsFactors = FALSE
)
sunburst(sequences)
... y cuando mueves el mouse sobre él, ocurre la magia:
Editar
El sitio oficial de este paquete se puede encontrar aquí (¡con muchos ejemplos!): https://github.com/timelyportfolio/sunburstR
Hat Tip para @timelyportfolio ¡quién creó esta impresionante pieza de código!
Puede crear algo a lo largo de las líneas de un diagrama de rayos solares usando geom_tile
del paquete ggplot2
. Primero creemos algunos datos aleatorios:
require(ggplot2); theme_set(theme_bw())
require(plyr)
dat = data.frame(expand.grid(x = 1:10, y = 1:10),
z = sample(LETTERS[1:3], size = 100, replace = TRUE))
Y luego crea la trama ráster. Aquí, el eje x
de la gráfica está acoplado a la variable x
en dat
, el eje y
a la variable y
, y el relleno de los píxeles a la variable z
. Esto produce la siguiente gráfica:
p = ggplot(dat, aes(x = x, y = y, fill = z)) + geom_tile()
print(p)
El paquete ggplot2
admite todo tipo de transformaciones de coordenadas, una de las cuales toma un eje y lo proyecta en un círculo, es decir, coordenadas polares:
p + coord_polar()
Esto hace más o menos lo que necesita, ahora puede ajustar dat
para obtener el resultado deseado.
Solo hay un par de bibliotecas que conozco que hacen esto de forma nativa:
- El Javascript Infovis Toolkit (jit) ( example ).
- D3.js
- Herramienta de trazado simple (SPT) de OCaml.
Ninguno de estos está en Python o R, pero conseguir un script de python / R para escribir un archivo JSON simple que pueda ser cargado por cualquiera de las bibliotecas de JavaScript debería ser bastante factible.
Versión de Python del diagrama de rayos solares usando barras matplotlib en proyección polar:
import numpy as np
import matplotlib.pyplot as plt
def sunburst(nodes, total=np.pi * 2, offset=0, level=0, ax=None):
ax = ax or plt.subplot(111, projection=''polar'')
if level == 0 and len(nodes) == 1:
label, value, subnodes = nodes[0]
ax.bar([0], [0.5], [np.pi * 2])
ax.text(0, 0, label, ha=''center'', va=''center'')
sunburst(subnodes, total=value, level=level + 1, ax=ax)
elif nodes:
d = np.pi * 2 / total
labels = []
widths = []
local_offset = offset
for label, value, subnodes in nodes:
labels.append(label)
widths.append(value * d)
sunburst(subnodes, total=total, offset=local_offset,
level=level + 1, ax=ax)
local_offset += value
values = np.cumsum([offset * d] + widths[:-1])
heights = [1] * len(nodes)
bottoms = np.zeros(len(nodes)) + level - 0.5
rects = ax.bar(values, heights, widths, bottoms, linewidth=1,
edgecolor=''white'', align=''edge'')
for rect, label in zip(rects, labels):
x = rect.get_x() + rect.get_width() / 2
y = rect.get_y() + rect.get_height() / 2
rotation = (90 + (360 - np.degrees(x) % 180)) % 360
ax.text(x, y, label, rotation=rotation, ha=''center'', va=''center'')
if level == 0:
ax.set_theta_direction(-1)
ax.set_theta_zero_location(''N'')
ax.set_axis_off()
Ejemplo, cómo se puede usar esta función:
data = [
(''/'', 100, [
(''home'', 70, [
(''Images'', 40, []),
(''Videos'', 20, []),
(''Documents'', 5, []),
]),
(''usr'', 15, [
(''src'', 6, [
(''linux-headers'', 4, []),
(''virtualbox'', 1, []),
]),
(''lib'', 4, []),
(''share'', 2, []),
(''bin'', 1, []),
(''local'', 1, []),
(''include'', 1, []),
]),
]),
]
sunburst(data)