9 Estilos y formatos de tabla
En cuanto a operativa de trabajo, esta es nuestra última sección, puesto que la última es complementaria. En esta sección aprenderemos a combinar gráficos y tablas con visualizaciones especiales, de la forma más diversa.
9.1 Introducción
Los paquetes que hemos utilizado en nuestro trabajo con las tablas ya han sido referido en multitud de ocasiones. expss
nos permite además de obtener el cuadro preciso, operar con las filas y columnas de la tabla, puesto que el objeto creado es como un dataframe especial, ya que su clase de objeto es etable
. Por tanto, vamos a tener la capacidad de poder operar con las columnas (variable) así como también con las filas (registros de ese dataframe).
Existen multitud de paquetes con los que poder interactuar para poder obtener los resultados deseados. Los paquetes DT o _datatable_
, formattable
, y también kable
y kableExtra
que son nativos para utilizar junto con rmarkdown
, lo que conforma un amplio espectro de soluciones. Deberemos buscar aquella que responda a nuestras expectativas y que haga nos sintamos más cómodos. Nuestra elección será kableExtra
.
Por el lado de las operaciones en la tabla, comenzaremos sentando las bases de como se realizan las operaciones, para luego trabajar la salida aportando estilos y formatos condicionales a las mismas.
9.2 Operaciones con tablas
Como hemos indicado en la presentación anterior, nuestro primer paso será la realización de operaciones muy simples con las tablas, que seguro en nuestro trabajo estamos acostumbrados a hacer. también vamos a adentramos un poco en la creación de los elementos con los que vamos a trabajar. Ahora ya no trabajaremos sobre lo que ha sido nuestro fichero base, sino que iremos aportando nuestros propios ejemplos que se adecuen a lo que deseamos hacer.
Imaginemos que disponemos datos sobre las cifras de ventas anuales de cinco empresas muy conocidas: Apple, Amazon, Microsoft, Google y Facebook. Estas empresas ofrecen información sobre Ingresos , Beneficio Operativo y Beneficio Neto de cuatro trimestre de 2018 y primer trimestre de 2019 en millones de dólares. Con estos datos creamos un dataframe.
<-
data data.frame(
emp = c(
"Apple",
"Apple",
"Microsoft",
"Microsoft",
"Amazon",
"Amazon",
"Google",
"Google",
"Facebook",
"Facebook"
),ing = c(
84310,
91819,
32471,
36906,
72400,
87400,
39276,
46075,
16914,
21082
),bfo = c(23346, 25569, 10258, 13891, 3786, 3879, 8221, 9266, 7820, 8858),
bfn = c(19965, 22236, 8420, 11649, 3027, 3268, 8948, 10671, 6882, 7349),
per = c(
"IV-2018",
"I-2019",
"IV-2018",
"I-2019",
"IV-2018",
"I-2019",
"IV-2018",
"I-2019",
"IV-2018",
"I-2019"
)
) data
## emp ing bfo bfn per
## 1 Apple 84310 23346 19965 IV-2018
## 2 Apple 91819 25569 22236 I-2019
## 3 Microsoft 32471 10258 8420 IV-2018
## 4 Microsoft 36906 13891 11649 I-2019
## 5 Amazon 72400 3786 3027 IV-2018
## 6 Amazon 87400 3879 3268 I-2019
## 7 Google 39276 8221 8948 IV-2018
## 8 Google 46075 9266 10671 I-2019
## 9 Facebook 16914 7820 6882 IV-2018
## 10 Facebook 21082 8858 7349 I-2019
Ahora vamos a obtener la tabla con la que deseamos trabajar, que sería comparar los ingresos de las cinco compañías en los dos períodos. Para ello creamos una tabla de la siguiente forma.
as.datatable_widget(data %>%
tab_cols(per) %>%
tab_rows(emp) %>%
tab_cells(ing) %>%
tab_stat_sum() %>%
tab_pivot())
Este sería el formato estándar de salida, pero como ya hemos visto en anteriores secciones, podemos adaptar esa salida a nuestras necesidades. Nótese que aun no siendo necesario, vamos a guardar la tabla en un output llamado tab01 que luego vamos a publicar. Utilizamos la función class()
para mostrarte que tras hacer la tabla, el output almacenado es un etable
dataframe.
<- data %>%
tab01 tab_cols("|"=unvr(per)) %>%
tab_rows("|"=unvr(emp)) %>%
tab_cells("|"=unvr(ing)) %>%
tab_stat_sum(label="|") %>%
tab_pivot()
class(tab01)
## [1] "etable" "data.frame"
as.datatable_widget(tab01)
Podemos ver que esta tabla ya tiene un formato más adecuado a nuestra necesidad. Hemos quitado aquellos textos que en esta ocasión eran innecesarios.
Si convertimos (aunque ya lo es) y mostramos esta tabla como dataframe el resultado sería éste.
<- as.data.frame(tab01)
tab01 class(tab01)
## [1] "data.frame"
tab01
## row_labels I-2019 IV-2018
## 1 Amazon 87400 72400
## 2 Apple 91819 84310
## 3 Facebook 21082 16914
## 4 Google 46075 39276
## 5 Microsoft 36906 32471
Nótese que ahora ya el output no es un objeto de tipo etable
, solo es dataframe. Ya estamos en condiciones de poder operar. Calculemos la diferencia entre los dos trimestres.
$dif <- tab01[,2]-tab01[,3]
tab01 tab01
## row_labels I-2019 IV-2018 dif
## 1 Amazon 87400 72400 15000
## 2 Apple 91819 84310 7509
## 3 Facebook 21082 16914 4168
## 4 Google 46075 39276 6799
## 5 Microsoft 36906 32471 4435
Esta información puede ser presentada en un gráfico tal como veíamos en la sección anterior. Aprovechemos también para cambiar el nombre de las columnas …
colnames(tab01) <- c('empresa', '2019 (1º)', '2018 (4º)', 'dif')
highchart() %>%
hc_chart(type = 'column') %>%
hc_title(text = 'Cifra de negocio de las 5 mayores tecnológicas') %>%
hc_xAxis(categories = tab01[, 1]) %>%
hc_yAxis(min = 0, max = 100000) %>%
hc_add_series(
data = tab01[, 2],
name = "IV de 2018",
dataLabels = list(enabled = TRUE),
color = "#FA8072"
%>%
) hc_add_series(
data = tab01[, 3],
name = "I de 2019",
dataLabels = list(enabled = TRUE),
color = "#E9967A"
%>%
) hc_add_series(
data = tab01[, 4],
name = "Diferencia",
dataLabels = list(enabled = TRUE),
color = "teal"
)
Añadamos más información a la tabla. Vamos a calcular el porcentaje de incremento. Habrían muchas formas de hacerlo, pero vamos a tratar de hacerlo de la forma más simple.
$difpct <- round(((tab01[,2]/tab01[,3])-1)*100,1) #cociente entre valores y paso a porcentaje con redondeo a un decimal
tab01 tab01
## empresa 2019 (1º) 2018 (4º) dif difpct
## 1 Amazon 87400 72400 15000 20.7
## 2 Apple 91819 84310 7509 8.9
## 3 Facebook 21082 16914 4168 24.6
## 4 Google 46075 39276 6799 17.3
## 5 Microsoft 36906 32471 4435 13.7
Esto nos va a permitir probar algo que no vimos en la sección anterior, presentar en función de otro eje Y la información. Se puede observar que en el script abajo referido, estamos creando en la función hc_yAxis()
una lista de dos ejes a los que referenciar los datos, mientras que las cifras absolutas se miran con el eje Y de la izquierda, el dato relativo se mira con el eje Y a la derecha del gráfico. El resto de opciones ya fueron analizadas
highchart() %>%
hc_chart(type = "column") %>%
hc_title(text = "Cifra de negocio de las 5 mayores tecnológicas") %>%
hc_xAxis(categories = tab01[, 1]) %>%
hc_yAxis_multiples(
list(
title = list(text = "Millones de dólares"),
min = 0,
max = 100000
),list(
title = list(text = "Porcentaje"),
min = 0,
max = 100,
opposite = TRUE
)%>%
) hc_add_series(
data = tab01[, 2],
name = "IV de 2018",
dataLabels = list(enabled = TRUE),
color = "#FA8072"
%>%
) hc_add_series(
data = tab01[, 3],
name = "I de 2019",
dataLabels = list(enabled = TRUE),
color = "#E9967A"
%>%
) hc_add_series(
data = tab01[, 4],
name = "Diferencia",
dataLabels = list(enabled = TRUE),
color = "teal"
%>%
) hc_add_series(
data = tab01[, 5],
name = "Diferencia porcentual",
dataLabels = list(enabled = TRUE, format = "{point.y} %"),
color = "darkblue",
yAxis = 1
)
9.3 Estilo de las tablas
9.3.1 Estilo y posición
Vamos ahora a trabajar con la con la tabla y realizaremos algunos cambios sobre ella. Utilizaremos el paquete kableExtra
. Este paquete permite trabajar con los dataframe para formatear la manera en que se van a mostrar en la pantalla. Existen multitud de paquetes que nos permitirían hacer cosas semejantes, entre los que podríamos destacar formattable
, DT
o flextable
entre otros.
Nuestro primer cambio va a ser mostrar de forma diferente nuestra tabla. Con un estilo diferente a lo que ha aprecido hasta ahora. Le vamos a aplicar el estilo típico de Bootstrap, conocida librería JS con la que fue desarrollada Twitter. Te recomendamos visitar la viñeta del paquete en este sitio si quieres ver todas sus posibilidades.
kbl(tab01) %>%
kable_styling()
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
Se puede apreciar que el aspecto es diferente al mostrado por las tablas hasta ahora. Este sería el formato más básico de Bootstrap. Existen otras opciones entre las que vamos a ir añadiendo algunas características, aplicables a los formatos.
Usando paper
…
kbl(tab01) %>%
kable_paper("hover")
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
Usando classic
…
kbl(tab01) %>%
kable_classic("hover")
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
Usando minimal
…
kbl(tab01) %>%
kable_minimal("hover")
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
Añadimos además del efecto hover con el ratón, el oscurecimiento o striped de las filas para facilitar la lectura y usabilidad.
kbl(tab01) %>%
kable_material(c("striped","hover"))
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
Finalizamos de nuevo con el primer formato que será el que mantendremos a partir de este momento.
kbl(tab01) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"))
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
Una de las características que en algunos casos puede ser muy valiosa, es la posibilidad de establecer la tabla como flotante a derecha o izquierda del texto.
kbl(tab01) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F, position = "float_right")
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
Este texto que estamos escribiendo, se ubicaría a la izquierda de la tabla, ya que hemos indicado que ésta debe ser situada a la derecha como elemento flotante. Al mismo tiempo se le ha incluido la posibilidad de que la tabla no ocupe el 100% del espacio sino que se autoajuste al tamaño de las columna. Este efecto puede ser muy utilizado para incluir comentarios sobre la tabla que estamos publicando. Como es lógico, la tabla puede ser flotante a la derecha o a la izquierda del texto.
Existen otras muchas características que pueden ser aplicadas para conseguir posicionar la tabla de la forma deseada:
- fijar la cabecera
- incluir la tabla en una caja
- aplicar tamaños de fuente
- … y más.
9.3.2 Formato específico de fila o columna
Veamos algunas de las posibilidades que nos ofrece kableExtra
para formatear partes de la tabla. Para ello debemos saber que las columnas se identifican por número secuencial (1 a n) al igual que las filas. Se pueden aplicar formatos tanto a filas como a columnas. Para ilustrar un ejemplo, vamos a utilizar una función de R muy frecuente denominada ifelse()
que es el equivalente a la función SI()
de Excel y con una estructura idéntica. Esta función admite la concatenación y sus parámetros son por este orden:
- condición que debe cumplirse
- resultado si verdadero
- resultado si falso
En nuestro caso nuestro resultado es la aplicación de un color verde o rojo según estemos por encima o por debajo de la media de la columna. Del mismo modo, también se puede aplicar como podemos observar un color directo a una columna determinada. Usaremos la función column_spec()
.
kbl(tab01) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = F
%>%
) column_spec(2, color = "teal", bold = TRUE) %>%
column_spec(
5,
color = "white",
background = ifelse(tab01$difpct > mean(tab01$difpct), "#3CB371", "#FA8072"),
popover = paste(tab01[, 1])
)
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
Otra posibilidad es la de poder marcar celdas cell_spec() o filas con row_spec()
en particular …
kbl(tab01) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = F
%>%
) row_spec(3:5,
bold = T,
color = "white",
background = "teal")
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
Un caso particular para la fila 0, la de encabezado.
kbl(tab01) %>%
kable_styling(c("striped", "hovered"), full_width = F) %>%
row_spec(
0,
angle = -20,
align = "left",
background = "teal",
color = "white",
bold = TRUE
%>%
) row_spec(1:5, align = "center", background = "light#FA8072")
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
9.4 Adición de imágenes y de otros elementos
Ya para finalizar, es muy habitual querer utilizar imágenes para ilustrar la tabla, darle un aspecto más impactante. Vemos como hacerlo. Esta imagen puede sustituir el contenido completo de la columna o añadirse al final de la misma. En nuestro ejemplo queremos sustituir, por lo que nuestra primera instrucción limpia la columna de tab01 denominada empresa. Posteriormente se crea un vector con las cinco imágenes que aprovecharemos en la columna 1. Para no perder nuestra tabla original, hacemos un copia de la misma en tab02.
<- tab01
tab02 $empresa <- ""
tab02<-
vector.img c(
"https://download.tesigandia.com/test/20201112113121.png",
"https://download.tesigandia.com/test/20201112112927.png",
"https://download.tesigandia.com/test/20201112113240.png",
"https://download.tesigandia.com/test/20201112113259.png",
"https://download.tesigandia.com/test/20201112113048.png"
)kbl(tab02) %>%
kable_styling(bootstrap_options = c("hover"),
full_width = FALSE) %>%
column_spec(1, image = vector.img) %>%
column_spec(2, color = "teal", bold = TRUE) %>%
column_spec(5,
color = "white",
background = ifelse(tab02$difpct > mean(tab02$difpct), "#3CB371", "#FA8072"))
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
87400 | 72400 | 15000 | 20.7 | |
91819 | 84310 | 7509 | 8.9 | |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
36906 | 32471 | 4435 | 13.7 |
9.4.1 Adición de iconos de FontAwesome
En la siguiente tabla, vamos a añadir las marcas de icono llamadas fontawesome
que permite reproducir en modo texto los iconos más típicos. En nuestro caso y siguiendo el uso de la función ifelse
que hemos visto antes, añadiremos una flecha arriba verde si la media de la cifra de negocio es mayor que la media o una flecha abajo roja si es menor.
<- tab01
tab02 2] <-
tab02[, ifelse(tab02[, 2] > mean(tab02[, 2]), paste(tab02[, 2], fa("arrow-circle-up", fill =
"#3CB371")), paste(tab02[, 2], fa("arrow-circle-down", fill = "red")))
kbl(tab02, escape = FALSE) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = F
%>%
) column_spec(2, color = "teal", bold = TRUE) %>%
column_spec(
5,
color = "white",
background = ifelse(tab02$difpct > mean(tab01$difpct), "#3CB371", "#FA8072"),
popover = paste(tab02[, 1])
)
empresa | 2019 (1º) | 2018 (4º) | dif | difpct |
---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 |
Apple | 91819 | 84310 | 7509 | 8.9 |
21082 | 16914 | 4168 | 24.6 | |
46075 | 39276 | 6799 | 17.3 | |
Microsoft | 36906 | 32471 | 4435 | 13.7 |
9.4.2 Adición de gráficos de tipo sparkline
Dado que no tenemos datos para poder representar, vamos a suponer una serie de datos para cada empresa y vamos a hacer un gráfico de líneas de tipo sparkline
, que vamos a integra como una columna más de nuestra tabla. sparkline
es un paquete de R que utiliza la librería jquery sparklines
para presentar gráficos minimalistas y ser integrados en nuestros dataframe, y por tanto, publicados en tablas.
En primer lugar creamos la serie de datos para cada empresa y lo vamos a hacer usando la función sample()
que nos aportará 15 valores aleatorios entre 1 y 100 con posibilidad de repetición. Esta es una fórmula muy sencilla que se utiliza mucho en R para crear datos de test.
sparkline(0) #inicializamos la función sparkline
<- sample(1:100, 15, replace = TRUE)
amz <- sample(1:100, 15, replace = TRUE)
app <- sample(1:100, 15, replace = TRUE)
fac <- sample(1:100, 15, replace = TRUE)
goo <- sample(1:100, 15, replace = TRUE)
mic <-
df data.frame(amz, app, fac, goo, mic) # los unimos para mostrarlos en forma de tabla, aunque no sería necesario.
df
amz app fac goo mic
1 64 85 71 43 20
2 70 85 80 28 55
3 86 17 7 30 21
4 76 42 42 85 72
5 54 35 91 57 9
6 65 29 4 23 25
7 71 75 26 46 72
8 82 88 75 93 100
9 4 13 66 3 84
10 82 18 44 47 18
11 79 75 21 54 30
12 17 4 73 27 6
13 56 27 9 96 72
14 49 27 65 4 99
15 91 59 36 17 95
Una vez tenemos esto Lo hemos juntado en un dataframe para que se vea mejor, vamos a añadir una nueva columna a nuestra tabla, con la información del gráfico.
<- tab01
tab03 $sparkline = c(spk_chr(amz),
tab03spk_chr(app),
spk_chr(fac),
spk_chr(goo),
spk_chr(mic))
kbl(tab03, escape = F) %>%
kable_styling(full_width = TRUE)
empresa | 2019 (1º) | 2018 (4º) | dif | difpct | sparkline |
---|---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 | |
Apple | 91819 | 84310 | 7509 | 8.9 | |
21082 | 16914 | 4168 | 24.6 | ||
46075 | 39276 | 6799 | 17.3 | ||
Microsoft | 36906 | 32471 | 4435 | 13.7 |
La última columna de la tabla muestra los gráficos obtenidos. Nótese que los datos de la última columna han sido calculados con una fuente de datos diferente, por lo que esta tabla está presentando inputs obtenidos de dos fuentes. Por una lado nuestra vieja tabla y por otro lado la nueva información que le incorporamos.
Y finalmente, mostramos casi todo lo que hemos hecho junto, no son cosas separadas.
<- tab03
tab02 2] <-
tab02[, ifelse(tab02[, 2] > mean(tab02[, 2]), paste(tab02[, 2], fa("arrow-circle-up", fill =
"#3CB371")), paste(tab02[, 2], fa("arrow-circle-down", fill = "red")))
kbl(tab02, escape = FALSE) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = F
%>%
) column_spec(2, color = "teal", bold = TRUE) %>%
column_spec(5,
color = "white",
background = ifelse(tab02$difpct > mean(tab01$difpct), "#3CB371", "#FA8072"))
empresa | 2019 (1º) | 2018 (4º) | dif | difpct | sparkline |
---|---|---|---|---|---|
Amazon | 87400 | 72400 | 15000 | 20.7 | |
Apple | 91819 | 84310 | 7509 | 8.9 | |
21082 | 16914 | 4168 | 24.6 | ||
46075 | 39276 | 6799 | 17.3 | ||
Microsoft | 36906 | 32471 | 4435 | 13.7 |
Si deseas consultar más información sobre la librería jQuery Sparklines
accede al enlace. Enlace antiguo, pero con muchísima utilidad.