It is not clear if you are wanting that exact formatting, or just the data structure.
There are also functions that can do some of this from raw data but you are starting with something close to a contingency table aleady
require(dplyr)
require(tidyr)
require(forcats)
require(flextable)
require(janitor)
df <- tibble(gender = c("M", "M", "F", "F"),
handed = c("R", "L", "R", "L"),
freq = c(43, 9, 44, 4)
)
df %>%
# replace the columns
transmute(
# make gender become Sex, recode M and F into full names (for row headers)
Sex = fct_recode(gender, Male = "M", Female = "F"),
# make handed R and L be recoded
Handedness = fct_recode(handed, `Right-handed` = "R", `Left-handed`="L"),
#keep frequency
freq = freq) %>%
# Make the contingency layout
pivot_wider(names_from = Handedness, values_from = freq) %>%
# add row and column totals
adorn_totals(c("row", "col")) %>%
# create a nice table layout
flextable()%>%
# add a merged header
add_header_row(values=c("","Handedness"), colwidths = c(1,3) ) %>%
# Apply a grid
theme_box() %>%
# make first column bold
bold(j=1)
# You can look up how to shade the boxes yourself. I don't think you can split a cell diag