cjvanlissa / tidySEM

55 stars 7 forks source link

Alowing parsing of text to display math expression #92

Closed dumaskvn closed 6 months ago

dumaskvn commented 6 months ago

Hello Caspar, First of all, thanks a lot for this great, and so flexible package. I was wondering whether it would be possible for you to allow controlling the "parse" argument of geom_text/label from the graph_sem function. I'll explain myself. Sometime, it can be handy to feed the label variable, especially in nodes, with expression such as math expression (in my case). If, as I guess, text in tidySEM is displayed using geom_textor geom_label, we need to set the parse argument to TRUE to use expression in the geoms. This might not make sense for lavaan users, put I'm doing SEM modelling using piecewiseSEM and am interested in adding, for exemple, R2 to my SEM plot. Furthermore I think this is related to issue #44 .

The MWE below illustrate my though.

Best regards,

Keyvan

library(piecewiseSEM)
library(magrittr)
library(dplyr)
library(tidySEM)
library(ggplot2)
data(keeley)

k_mod <- "
  rich ~ firesev + cover
  cover ~ firesev
"

k_fit <- sem(k_mod, data = keeley)

k_nodes <- mutate(
  get_nodes(k_fit),
  # create dummy label including R2
  label = paste("atop(", label, ", R^2 ==", round(runif(3, 0, 1), 2), ")")
)
ggplot(k_nodes[1,])+
  # parsing off
  geom_label(aes(x = 1.25, y=1, label=label), parse=F)+ 
  # parsing on
  geom_label(aes(x = 1.75, y=1, label=label), parse=T)+ 
  scale_x_continuous(limits = c(1,2))

Created on 2024-04-03 with reprex v2.0.2

cjvanlissa commented 6 months ago

Dear Keyvan,

as this functionality already exists in ggplot, and the output of graph_sem is a ggplot object, you can just add these labels in post. If you use the intermediate step of prepare_graph(), you have access to the plotting data.frames. Just use these to add + geom_label(aes(x = 1.75, y=1, label=label), parse=T) to the final plot.

dumaskvn commented 6 months ago

Dear Caspar, Thanks for your fast and through answer. Using prepare_graph and overlapping personally defined geom_rect and geom_textto build my own node on top of the graph_sem did the job. Many thanks for the support ! All the best

cjvanlissa commented 6 months ago

Dear @dumaskvn

Perfect! You can contribute an example to the plotting tutorial if you like, or post a reproducible example here and I can do it!

dumaskvn commented 6 months ago

@cjvanlissa Please find below a MWE of what I did based on your advises. Please not that all modification on the sem exemple are for illustration only. Thanks a lot for your help !

library(piecewiseSEM)
library(dplyr)
library(tidySEM)
library(ggplot2)
library(lavaan)
library(forcats)
data(keeley)
k_mod <- "
  rich ~ firesev + cover
  cover ~ firesev
"
# fit model
k_fit <- sem(k_mod, data = keeley)
# specify layout for consistency
layout <- matrix(data = c("firesev", "", "cover", "rich"), nrow = 2, ncol = 2)
# get data from prepare_graph
p <- prepare_graph(k_fit, layout = layout)
# add dummy information to node label
p$nodes <- mutate(p$nodes,
  name = fct_recode(name, "alpha-div" = "rich"), # include greek-letter in variable name
  label = paste("atop(", name, ", R^2 ==", round(runif(3, 0, 1), 2), ")"), # create dummy R2 variable to be displayed in node label
                    )
# standard graph
graph_sem(k_fit,
          layout = layout)

# graph with parsed node label
graph_sem(k_fit, layout = layout)+
  geom_rect(data = p$nodes, aes(xmin = node_xmin, xmax = node_xmax, ymin = node_ymin, ymax = node_ymax), fill = "white", colour="black")+
  geom_text(data=p$nodes, aes(x=x, y=y, label=label), parse=T)

Created on 2024-04-03 with reprex v2.0.2