Default plots are generally sufficient in many cases. The customized .graph_attrs setting offers an alternative design, but in some instances, the default may look better than the customized version.

Rules of Thumb for .graph_attrs Setting:

Key Consideration: "rank=same" Setting

To experiment another appearance of the default plot when using "rank=same":

Demo
Demo

Plot with the customized .graph_attrs setting

graph_attrs = c(
  "rankdir=LR",
  "splines=polyline",
  "{rank=same; OrgIden; Gender}",
  "{rank=same; AffJoy; AffLove}"
)
Demo
Demo
## ℹ Loading cSEM
library(cSEM)

# Sample.R

model_Bergami="
# Measurement models
OrgPres <~ cei1 + cei2 + cei3 + cei4 + cei5 + cei6 + cei7 + cei8 
OrgIden =~ ma1 + ma2 + ma3 + ma4 + ma5 + ma6
AffJoy =~ orgcmt1 + orgcmt2 + orgcmt3 + orgcmt7
AffLove  =~ orgcmt5 + orgcmt6 + orgcmt8
Gender<~ gender

Aff<~AffJoy+AffLove

# Structural model 
OrgIden ~ OrgPres 
Aff ~ OrgPres+OrgIden+Gender
"

out <- csem(.data = BergamiBagozzi2000,.model = model_Bergami,
            .disattenuate = T,
            .PLS_weight_scheme_inner = 'factorial',
            .tolerance = 1e-5,
            .resample_method = 'bootstrap',.R = 499)

# **Run `plot()` without any settings** to identify the ranks of the structural model.
# Default plot
plot(out)
# Customized setting for the default plot

graph_attrs = c(
  "rankdir=LR",
  "splines=polyline",
  "{rank=same; OrgIden; Gender}",
  "{rank=same; AffJoy; AffLove}"
)

plot(out,
     .graph_attrs = graph_attrs)
# When `.plot_correlations = "both"`:
# Default plot
plot(out,
     .plot_correlations = "both")
# Customized setting
# Add "subgraph" for the measurement indicators
# When there are too many indicators, organize them into multiple ranks.

graph_attrs_both = c(
  "rankdir=LR",
  "ranksep=1",
  "splines=polyline",

  "{rank=same; OrgIden; Gender}",
  "{rank=same; AffJoy; AffLove}",
  
  "subgraph cluster_1 {
  graph [style=invis];
  {rank=same; cei1 ; cei2 ; cei3 ; cei4};
  {rank=same; cei5 ; cei6 ; cei7 ; cei8}
  }",
  
  "subgraph cluster_2 {
  graph [style=invis];
  {rank=same; ma1; ma2; ma3};
  {rank=same; ma4; ma5; ma6}
  }",
  
  "subgraph cluster_3 {
  graph [style=invis];
  {rank=same; orgcmt1; orgcmt2};
  {rank=same; orgcmt3; orgcmt7}
  }",
  
  "subgraph cluster_4 {
  graph [style=invis];
  {rank=same; orgcmt5; orgcmt6; orgcmt8}
  }"
)

plot(out,
     .plot_correlations = "both",
     .graph_attrs = graph_attrs_both)
# When `.plot_correlations = "both"` AND `plot_labels = FALSE`
# Default plot
plot(out,
     .plot_correlations = "both",
     .plot_labels = FALSE)
# Customized setting
# Add "subgraph" for the measurement indicators
# Even when there are many indicators, organize them into one rank.

graph_attrs_both_false = c(
  "rankdir=LR",
  "ranksep=1",
  "splines=polyline",
  
  "{rank=same; OrgIden; Gender}",
  "{rank=same; AffJoy; AffLove}",
  
  "subgraph cluster_1 {
  graph [style=invis];
  {rank=same; cei1 ; cei2 ; cei3 ; cei4; cei5 ; cei6 ; cei7 ; cei8}
  }",
  
  "subgraph cluster_2 {
  graph [style=invis];
  {rank=same; ma1; ma2; ma3; ma4; ma5; ma6}
  }",
  
  "subgraph cluster_3 {
  graph [style=invis];
  {rank=same; orgcmt1; orgcmt2; orgcmt3; orgcmt7}
  }",
  
  "subgraph cluster_4 {
  graph [style=invis];
  {rank=same; orgcmt5; orgcmt6; orgcmt8}
  }"
)

plot(out,
     .plot_correlations = "both",
     .plot_labels = FALSE,
     .graph_attrs = graph_attrs_both_false)

Applying the above rank=same rule to other examples

# CCA.R
rm(list=ls())
model_IT_Flex="
# Composite models
ITComp  <~ ITCOMP1 + ITCOMP2 + ITCOMP3 + ITCOMP4
Modul   <~ MOD1 + MOD2 + MOD3 + MOD4
ITConn  <~ ITCONN1 + ITCONN2 + ITCONN3 + ITCONN4
ITPers  <~ ITPSF1 + ITPSF2 + ITPSF3 + ITPSF4

# Saturated structural model
ITPers ~ ITComp + Modul + ITConn
Modul  ~ ITComp + ITConn 
ITConn ~ ITComp 
"

# Estimate the model using PLS:
csem_results <- csem(.data = ITFlex, 
                     .model = model_IT_Flex,
                     .resample_method = "bootstrap",
                     .dominant_indicators = c("ITComp" = "ITCOMP1","ITConn"="ITCONN1",
                                              "Modul"="MOD1","ITPers"="ITPSF1"))

# Default plot
plot(csem_results,
     .title = "CCA")
# Customized plot
graph_attrs = c(
  "rankdir=LR",
  "splines=polyline",
  "{rank=same; ITConn; Modul}"
)

plot(csem_results,
     .title = "CCA",
     .graph_attrs = graph_attrs)
# Second-order constructs.R
rm(list=ls())
model_HOC='
# Measurement models
PR =~ PR1 + PR2 + PR3
IM =~ IM1 + IM2 + IM3
DI =~ DI1 + DI2 + DI3
AD =~ AD1 + AD2 + AD3
DL =~ DL1 + DL2 + DL3

# Dimensions forming the second-order construct, i.e., dimensions of brand equity
AA =~ AA1 + AA2 + AA3 + AA4 + AA5 + AA6
LO =~ LO1 + LO3
QL =~ QL1 + QL2 + QL3 + QL4 + QL5 + QL6

# SOC emergent variable (brand equity)
BE <~ QL + LO + AA

# Structural model
BE~ PR + IM + DI + AD + DL
'

# Estimate the model. 
# Internally the three-stage approach proposed by Van Riel et al. (2017) is applied.
out <- csem(.data = Yooetal2000, .model = model_HOC,
            .PLS_weight_scheme_inner = 'factorial',
            .tolerance = 1e-06,
            .resample_method = 'bootstrap'
)

# Default plot

plot(out,
     .title = "Second-order constructs")
# Customized plot

graph_attrs = c(
  "rankdir=LR",
  "{rank=same; PR; IM}",
  "{rank=same; DI; AD; DL}",
  "{rank=same; QL; LO; AA}")

plot(out,
     .graph_attrs = graph_attrs)
# Moderation.R
rm(list=ls())
model_Int <- "
# Measurement models
# Product involvement
INV =~ INV1 + INV2 + INV3 +INV4
# Satisfaction
SAT =~ SAT1 + SAT2 + SAT3
# Switching intention
INT =~ INT1 + INT2

# Structrual model containing an interaction term.
INT ~ INV + SAT + INV.SAT
"
out <- csem(.data = Switching, .model = model_Int,
            # ADANCO settings
            .PLS_weight_scheme_inner = 'factorial',
            .tolerance = 1e-06,
            .resample_method = 'bootstrap'
)

# Default plot
plot(out,
     .title = "Moderation")
# Customized plot
graph_attrs = c(
  "rankdir=LR",
  "{rank=same; SAT; INT}")

plot(out,
     .title = "Moderation",
     .graph_attrs = graph_attrs)
rm(list=ls())
model_Med='
# Measurement models
Trust =~ trust1 + trust2
PrCon =~ privcon1 + privcon2 + privcon3 + privcon4
Risk =~ risk1 + risk2 + risk3
Int =~ intent1 + intent2

# Structrual model
Int ~ Trust + PrCon + Risk
Risk ~ Trust + PrCon
Trust ~ PrCon
'

# Perform estimation
out <- csem(.data = LancelotMiltgenetal2016, .model = model_Med,
            # To reproduce the ADANCO results
            .PLS_weight_scheme_inner = 'factorial',
            .tolerance = 1e-06,
            .resample_method = 'bootstrap'
)

# Default plot

plot(out,
     .title = "Mediation")
# Customized plot

graph_attrs = c(
  "rankdir=LR",
  "{rank=same; Trust; Risk}")

plot(out,
     .title = "Mediation",
     .graph_attrs = graph_attrs)
# IPA.R
rm(list=ls())
# The original indicators ranged from 1-6 (6 point scale). They have been transformed to 0 - 100:
# xnew = (xold - 1) * 100/(6-1)
head(SQ)
##   a01 a02 a03 a04 a05 a06 a07 a08 a09 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19
## 1  80  80  80  80  80  80  80  80 100  80  80 100 100 100 100 100 100  80  80
## 2  80  80  80  80 100  80  80  80 100 100 100 100  80  80  80  80  60  80  80
## 3  80  80 100  80 100  80  80 100 100  80  80  80  80  80  80 100  80  80 100
## 4  80  80  80 100 100 100  80 100 100 100 100 100 100 100 100  80  80 100  80
## 5  60  60  40  60 100  80 100 100 100 100 100 100  80 100 100 100 100 100 100
## 6 100  80  80  80  80  80  80  80  80  80  80  80  80  80  80  80  80  80  80
##   a20 a21 a22 sat
## 1  80  80  80  80
## 2  80  60  60  80
## 3 100  80  80  80
## 4  80  60  80  80
## 5 100 100 100  80
## 6  80  60  80  80
# Specify the model
model<-'
# Specify composite models
Tangibles <~ a01+a02+a03+a04
Reliability<~ a05+a06+a07+a08+a09
Responsiveness <~ a10+a11+a12+a13
Assurance<~a14+a15+a16+a17
Empathy<~a18+a19+a20+a21+a22
Sat <~ sat

# Structural model
Sat~Tangibles+Reliability+Responsiveness+Assurance+Empathy
'

# Estimate model
out <- csem(.data = SQ,.model = model,
            .PLS_weight_scheme_inner = 'factorial',
            .tolerance = 1e-06)

# Default plot
plot(out,
     .title = "IPA")
# Customized plot
graph_attrs = c(
  "rankdir=LR",
  "ranksep=1.5",
  "splines=polyline",
  "{rank=same; Tangibles; Reliability; Responsiveness}",
  "{rank=same; Assurance; Empathy}")

plot(out,
     .title = "IPA",
     .graph_attrs = graph_attrs)
rm(list=ls())
model <- "
ETA1 ~ ETA2 + XI1 + XI2
ETA2 ~ ETA1 + XI3 +XI4
ETA1 ~~ ETA2
XI1 <~ x1 + x2 + x3
XI2 <~ x4 + x5 + x6
XI3 <~ x7 + x8 + x9
XI4 <~ x10 + x11 + x12
ETA1 <~ y1 + y2 + y3
ETA2 <~ y4 + y5 + y6
"
## Generate data
summers_dat <- MASS::mvrnorm(n = 300, mu = rep(0, 18), Sigma = Sigma_Summers_composites, empirical = TRUE)

## Estimate
res <- csem(.data = summers_dat, .model = model) # inconsistent

# Default plot
plot(res,
     .title = "Sigma_Summers_Composites 1")
# Customized plot
graph_attrs = c(
  "rankdir=LR",
  "{rank=same; XI3; XI4}",
  "{rank=same; ETA1; ETA2}")

plot(res,
     .title = "Sigma_Summers_Composites 1",
     .graph_attrs = graph_attrs)
# 2SLS
res_2SLS <- csem(.data = summers_dat, .model = model, .approach_paths = "2SLS",
                 .instruments = list(ETA1 = c('XI1','XI2','XI3','XI4'),
                                     ETA2 = c('XI1','XI2','XI3','XI4')))

# Default plot
plot(res_2SLS,
     .title = "Sigma_Summers_Composites 2")
# Customized plot
plot(res_2SLS,
     .title = "Sigma_Summers_Composites 2",
     .graph_attrs = graph_attrs)