---
title: "5. Tabellen mit flextable"
subtitle: "Publikationsreife Tabellen für Word-Dokumente"
---
Die Standard-R-Ausgabe von Tabellen sieht in Word-Dokumenten unprofessionell aus — sie erscheint als Konsolen-Output mit Monospace-Schrift. In diesem Kapitel lernt man, wie man mit dem flextable-Paket professionelle, formatierte Tabellen erstellt, die sich nahtlos in Word-Dokumente einfügen.
```{r}
#| label: qrt-tables-setup
#| include: false
library(tidyverse)
library(palmerpenguins)
library(flextable)
library(officer)
adelie <- penguins %>%
filter(species == "Adelie") %>%
drop_na()
```
# Warum flextable?
Es gibt mehrere R-Pakete für Tabellen (kable, gt, huxtable, flextable), aber für Word-Output ist **flextable** die beste Wahl:
- Natives Word-Format (kein Umweg über HTML)
- Volle Kontrolle über Formatierung
- Aktiv gepflegt und gut dokumentiert
- Teil des "Officeverse"-Ökosystems
:::{.callout-note}
Das **gt**-Paket ist hervorragend für HTML-Output, aber seine Word-Unterstützung ist eingeschränkter. Für Word-Dokumente empfehle ich flextable.
:::
# Grundlagen
## Eine einfache Tabelle erstellen
Der einfachste Weg, eine flextable zu erstellen:
```{r}
#| label: qrt-tables-basic
adelie %>%
head(5) %>%
select(island, bill_length_mm, bill_depth_mm, body_mass_g) %>%
flextable()
```
Das sieht schon viel besser aus als `print(df)`! Aber die Spaltenbreiten sind noch nicht optimal.
## Automatische Spaltenbreiten
Mit `autofit()` passt flextable die Spaltenbreiten automatisch an:
```{r}
#| label: qrt-tables-autofit
adelie %>%
head(5) %>%
select(island, bill_length_mm, bill_depth_mm, body_mass_g) %>%
flextable() %>%
autofit()
```
:::{.callout-tip}
`autofit()` sollte in der Regel am Ende der flextable-Pipeline stehen, nachdem alle anderen Formatierungen angewendet wurden.
:::
# Spalten umbenennen und formatieren
## Spaltenüberschriften ändern
Die automatischen Spaltennamen aus dem Dataframe sind oft nicht ideal für einen Report:
```{r}
#| label: qrt-tables-headers
adelie %>%
head(5) %>%
select(island, bill_length_mm, bill_depth_mm, body_mass_g) %>%
flextable() %>%
set_header_labels(
island = "Insel",
bill_length_mm = "Schnabellänge (mm)",
bill_depth_mm = "Schnabeltiefe (mm)",
body_mass_g = "Körpermasse (g)"
) %>%
autofit()
```
## Zahlen formatieren
Für wissenschaftliche Tabellen braucht man oft eine bestimmte Anzahl Dezimalstellen:
```{r}
#| label: qrt-tables-colformat
adelie %>%
head(5) %>%
select(island, bill_length_mm, bill_depth_mm, body_mass_g) %>%
flextable() %>%
set_header_labels(
island = "Insel",
bill_length_mm = "Schnabellänge (mm)",
bill_depth_mm = "Schnabeltiefe (mm)",
body_mass_g = "Körpermasse (g)"
) %>%
colformat_double(j = c("bill_length_mm", "bill_depth_mm"), digits = 1) %>%
colformat_double(j = "body_mass_g", digits = 0) %>%
autofit()
```
# Formatierung und Styling
## Schriftart und -größe
```{r}
#| label: qrt-tables-font
adelie %>%
head(5) %>%
select(island, bill_length_mm, body_mass_g) %>%
flextable() %>%
font(fontname = "Arial", part = "all") %>%
fontsize(size = 10, part = "body") %>%
fontsize(size = 11, part = "header") %>%
autofit()
```
## Ausrichtung
```{r}
#| label: qrt-tables-align
adelie %>%
head(5) %>%
select(island, bill_length_mm, body_mass_g) %>%
flextable() %>%
align(j = 1, align = "left", part = "all") %>%
align(j = 2:3, align = "center", part = "all") %>%
autofit()
```
## Rahmenlinien
```{r}
#| label: qrt-tables-borders
adelie %>%
head(5) %>%
select(island, bill_length_mm, body_mass_g) %>%
flextable() %>%
border_remove() %>%
hline_top(border = fp_border(width = 2), part = "header") %>%
hline_bottom(border = fp_border(width = 1), part = "header") %>%
hline_bottom(border = fp_border(width = 2), part = "body") %>%
autofit()
```
## Header fett formatieren
```{r}
#| label: qrt-tables-bold
adelie %>%
head(5) %>%
select(island, bill_length_mm, body_mass_g) %>%
flextable() %>%
bold(part = "header") %>%
autofit()
```
# Eine Summary-Tabelle erstellen
Für unseren Pinguin-Report erstellen wir eine deskriptive Statistik-Tabelle:
```{r}
#| label: qrt-tables-summary
summary_table <- adelie %>%
summarise(
n = n(),
`Schnabellänge (mm)` = mean(bill_length_mm),
`SD` = sd(bill_length_mm),
`Schnabeltiefe (mm)` = mean(bill_depth_mm),
`SD ` = sd(bill_depth_mm),
`Körpermasse (g)` = mean(body_mass_g),
`SD ` = sd(body_mass_g)
)
summary_table %>%
flextable() %>%
colformat_double(digits = 1) %>%
colformat_double(j = "n", digits = 0) %>%
set_header_labels(n = "N") %>%
bold(part = "header") %>%
autofit()
```
# Tabelle nach Gruppen
Eine Tabelle mit Statistiken pro Insel:
```{r}
#| label: qrt-tables-grouped
adelie %>%
group_by(island) %>%
summarise(
N = n(),
`Schnabellänge` = mean(bill_length_mm),
`Körpermasse` = mean(body_mass_g),
.groups = "drop"
) %>%
flextable() %>%
set_header_labels(island = "Insel") %>%
colformat_double(j = c("Schnabellänge"), digits = 1) %>%
colformat_double(j = c("Körpermasse"), digits = 0) %>%
bold(part = "header") %>%
hline_top(border = fp_border(width = 2), part = "header") %>%
hline_bottom(border = fp_border(width = 1), part = "header") %>%
hline_bottom(border = fp_border(width = 2), part = "body") %>%
autofit()
```
# Tabellenüberschriften in Quarto
Um eine Tabellenüberschrift hinzuzufügen, verwendet man die Chunk-Option `tbl-cap`:
````markdown
```{r}
#| label: tbl-summary
#| tbl-cap: "Deskriptive Statistik der Adelie-Pinguine"
summary_table %>%
flextable() %>%
autofit()
```
````
Das Label muss mit `tbl-` beginnen, damit Quarto es als Tabelle erkennt und Cross-Referenzen ermöglicht (siehe Kapitel 7).
# Verwendung in Word-Dokumenten
Für die korrekte Darstellung in Word-Dokumenten ist die Chunk-Option `output: asis` oft nicht mehr nötig (aktuelle flextable-Versionen erkennen das Format automatisch). Falls die Tabelle nicht korrekt erscheint, kann man sie hinzufügen:
````markdown
```{r}
#| label: tbl-example
#| output: asis
my_table %>%
flextable() %>%
autofit()
```
````
# Komplettes Beispiel
Hier ist eine vollständige, publikationsreife Tabelle:
```{r}
#| label: qrt-tables-complete
adelie %>%
group_by(island, sex) %>%
summarise(
N = n(),
`Schnabellänge (mm)` = mean(bill_length_mm),
`Körpermasse (g)` = mean(body_mass_g),
.groups = "drop"
) %>%
flextable() %>%
set_header_labels(
island = "Insel",
sex = "Geschlecht"
) %>%
colformat_double(j = "Schnabellänge (mm)", digits = 1) %>%
colformat_double(j = "Körpermasse (g)", digits = 0) %>%
font(fontname = "Arial", part = "all") %>%
fontsize(size = 10, part = "all") %>%
bold(part = "header") %>%
align(align = "center", part = "header") %>%
align(j = 1:2, align = "left", part = "body") %>%
align(j = 3:5, align = "right", part = "body") %>%
border_remove() %>%
hline_top(border = fp_border(width = 1.5), part = "header") %>%
hline_bottom(border = fp_border(width = 0.75), part = "header") %>%
hline_bottom(border = fp_border(width = 1.5), part = "body") %>%
autofit()
```
:::{.callout-tip collapse="false"}
## Übung: Erstelle eine Summary-Tabelle
1. Erstelle eine Tabelle mit der Anzahl Pinguine pro Insel und Geschlecht
2. Füge eine Spalte mit dem Durchschnittsgewicht hinzu
3. Formatiere die Tabelle professionell (Schriftart, Rahmen, Ausrichtung)
4. Füge eine Tabellenüberschrift mit `tbl-cap` hinzu
:::
# Weiterführende Ressourcen
- [flextable book](https://ardata-fr.github.io/flextable-book/) — Umfassende Dokumentation
- [flextable gallery](https://ardata-fr.github.io/flextable-gallery/) — Beispiele und Inspiration
- [Officeverse](https://ardata-fr.github.io/officeverse/) — Das Ökosystem rund um flextable
# Was kommt als Nächstes
Jetzt können wir professionelle Tabellen erstellen. In Kapitel 6 lernen wir, wie man ggplot2-Grafiken optimal in Quarto-Dokumente einbindet — mit der richtigen Größe, Auflösung und Beschriftung.