Threshold-Sweep QCA (TS-QCA) is a framework for systematically
exploring how different threshold settings affect the results of
crisp-set Qualitative Comparative Analysis (QCA).
In crisp-set QCA, the researcher must choose thresholds to binarize:
Small changes in these thresholds may lead to substantial differences in truth tables and minimized solutions.
TS-QCA provides:
The TSQCA package implements four sweep methods:
| Method | What varies | What stays fixed | Purpose |
|---|---|---|---|
| CTS–QCA | One X threshold | Y + other Xs | Evaluate influence of a single condition |
| MCTS–QCA | Multiple X thresholds | Y | Explore combinations of X thresholds |
| OTS–QCA | Y threshold | All Xs | Assess robustness to Y calibration |
| DTS–QCA | X and Y thresholds | None | Full 2D sensitivity analysis |
Scope: This package focuses on sufficiency analysis—identifying condition combinations that are sufficient for an outcome. Necessity analysis (whether a condition is required for an outcome) involves different logical structures and evaluation metrics, and is planned for future versions.
QCA minimization can produce three types of solutions depending on how logical remainders (unobserved configurations) are handled:
| Solution Type | include |
dir.exp |
Logical Remainders | Description |
|---|---|---|---|---|
| Complex (default) | "" |
NULL |
Not used | Most conservative; only observed configurations |
| Parsimonious | "?" |
NULL |
All used | Most simplified; uses all remainders |
| Intermediate | "?" |
c(1,1,...) |
Theory-guided | Uses remainders consistent with theory |
As of v1.1.0, TSQCA uses the same defaults as
QCA::minimize():
include = "" → Does not include logical remaindersdir.exp = NULL → No directional expectationsThis produces the complex (conservative) solution by default.
library(TSQCA)
data(sample_data)
thrX <- c(X1 = 7, X2 = 7, X3 = 7)
# 1. Complex Solution (default, most conservative)
result_comp <- otSweep(
dat = sample_data,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 7,
thrX = thrX
# include = "" (default), dir.exp = NULL (default)
)
cat("Complex Solution:", result_comp$summary$expression, "\n")
#> Complex Solution: ~X1*X3 + ~X2*X3 + X1*X2*~X3
# 2. Parsimonious Solution (uses all logical remainders)
result_pars <- otSweep(
dat = sample_data,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 7,
thrX = thrX,
include = "?" # Include logical remainders
)
cat("Parsimonious Solution:", result_pars$summary$expression, "\n")
#> Parsimonious Solution: X3 + X1*X2
# 3. Intermediate Solution (theory-guided remainders)
result_int <- otSweep(
dat = sample_data,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 7,
thrX = thrX,
include = "?",
dir.exp = c(1, 1, 1) # All conditions expected to contribute positively
)
cat("Intermediate Solution:", result_int$summary$expression, "\n")
#> Intermediate Solution: X3 + X1*X2| Solution | When to Use | Pros | Cons |
|---|---|---|---|
| Complex | Exploratory analysis, maximum caution | No assumptions about unobserved cases | Often too complex for interpretation |
| Parsimonious | Robustness checks, simplicity | Most simplified form | May rely on implausible assumptions |
| Intermediate | Theory-driven analysis, publications | Balances parsimony and theory | Requires theoretical justification |
Note: The intermediate solution is most commonly reported in QCA publications (Ragin, 2008; Fiss, 2011), as it incorporates theoretical knowledge while avoiding implausible simplifying assumptions.
If you were using TSQCA v1.0.0, note that the default behavior has changed:
# v1.0.0 (intermediate solution by default due to bug)
result <- otSweep(dat, "Y", c("X1", "X2", "X3"), sweep_range = 7, thrX = thrX)
# v1.1.0: To get the same result as v1.0.0, explicitly specify:
result <- otSweep(
dat = sample_data,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 7,
thrX = thrX,
include = "?",
dir.exp = c(1, 1, 1) # Explicit intermediate solution
)TS-QCA assumes:
Example dataset structure:
library(TSQCA)
data("sample_data")
dat <- sample_data
str(dat)
#> 'data.frame': 80 obs. of 4 variables:
#> $ Y : int 8 4 5 7 2 2 7 5 3 8 ...
#> $ X1: int 7 2 6 8 8 9 8 8 1 5 ...
#> $ X2: int 7 5 8 4 0 5 8 4 4 2 ...
#> $ X3: int 1 6 6 5 3 4 5 3 6 8 ...Define outcome and conditions:
In real-world social science research, datasets often contain both binary variables (e.g., gender, yes/no responses) and continuous variables (e.g., sales, satisfaction scores). When using TSQCA with such mixed data, special attention is required.
sweep_listThe internal qca_bin() function uses the rule
x >= thr for binarization:
x = 0: 0 >= 1 → FALSE →
0 (preserved)x = 1: 1 >= 1 → TRUE →
1 (preserved)This ensures that binary variables remain unchanged during the binarization process.
Suppose your dataset has:
When using ctSweepM():
# CORRECT: Specify threshold explicitly for each variable
sweep_list <- list(
X1 = 1, # Binary variable: use threshold 1
X2 = 6:8, # Continuous: sweep thresholds
X3 = 6:8 # Continuous: sweep thresholds
)
# Using intermediate solution (most common in publications)
res_mixed <- ctSweepM(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_list = sweep_list,
thrY = 7,
include = "?", # Include logical remainders
dir.exp = c(1, 1, 1) # Directional expectations (intermediate)
)This explores 1 × 3 × 3 = 9 threshold combinations, treating X1 as a fixed binary condition while sweeping X2 and X3.
# WRONG: Using sweep range for binary variables
sweep_list <- list(
X1 = 6:8, # All values become 0 (since 0 < 6 and 1 < 6)
X2 = 6:8,
X3 = 6:8
)If you accidentally specify X1 = 6:8, both 0 and 1 will
fail the >= 6 condition, making all X1 values become 0.
This destroys the information in your binary variable.
Always examine your data structure before setting up threshold sweeps:
# Check variable ranges
summary(dat[, c("X1", "X2", "X3")])
# Identify binary variables (only 0 and 1)
sapply(dat[, c("X1", "X2", "X3")], function(x) {
unique_vals <- sort(unique(x))
if (length(unique_vals) == 2 && all(unique_vals == c(0, 1))) {
"Binary (use threshold = 1)"
} else {
paste("Continuous (range:", min(x), "-", max(x), ")")
}
})ctSweepS)CTS–QCA varies the threshold for one X condition, keeping the others fixed.
sweep_var <- "X3" # Condition (X) whose threshold is swept
sweep_range <- 6:9 # Candidate threshold values to evaluate
thrY <- 7 # Outcome (Y) threshold (fixed)
thrX_default <- 7 # Threshold for other X conditions (fixed)
# Default: Complex solution (include = "", dir.exp = NULL)
res_cts <- ctSweepS(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_var = sweep_var,
sweep_range = sweep_range,
thrY = thrY,
thrX_default = thrX_default,
return_details = TRUE
)
summary(res_cts)
#> CTS-QCA Summary
#> ===============
#>
#> Analysis Parameters:
#> Outcome: Y
#> Conditions: X1, X2, X3
#> Consistency cutoff: 0.8
#> Frequency cutoff: 1
#>
#> Results by Threshold:
#>
#> threshold expression inclS covS n_solutions
#> 6 X1*X2 1.000 0.303 1
#> 7 ~X1*X3 + ~X2*X3 + X1*X2*~X3 0.906 0.879 1
#> 8 ~X1*X3 + ~X2*X3 + X1*X2*~X3 1.000 0.818 1
#> 9 ~X2*X3 + X1*X2*~X3 1.000 0.515 1# Intermediate solution: specify include = "?" and dir.exp
res_cts_int <- ctSweepS(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_var = sweep_var,
sweep_range = sweep_range,
thrY = thrY,
thrX_default = thrX_default,
include = "?", # Include logical remainders
dir.exp = c(1, 1, 1), # Directional expectations
return_details = TRUE
)
summary(res_cts_int)
#> CTS-QCA Summary
#> ===============
#>
#> Analysis Parameters:
#> Outcome: Y
#> Conditions: X1, X2, X3
#> Consistency cutoff: 0.8
#> Frequency cutoff: 1
#>
#> Results by Threshold:
#>
#> threshold expression inclS covS n_solutions
#> 6 X1*X2 1.000 0.303 1
#> 7 X3 + X1*X2 0.906 0.879 1
#> 8 X3 + X1*X2 1.000 0.818 1
#> 9 X3 + X1*X2 1.000 0.515 1ctSweepM)MCTS–QCA evaluates all combinations of thresholds for multiple X conditions.
# Create a sweep list specifying thresholds for each condition
sweep_list <- list(
X1 = 6:7,
X2 = 6:7,
X3 = 6:7
)
# Default: Complex solution
res_mcts <- ctSweepM(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_list = sweep_list,
thrY = 7,
return_details = TRUE
)
summary(res_mcts)
#> MCTS-QCA Summary
#> ================
#>
#> Analysis Parameters:
#> Outcome: Y
#> Conditions: X1, X2, X3
#> Consistency cutoff: 0.8
#> Frequency cutoff: 1
#>
#> Results by Threshold:
#>
#> threshold combo_id expression inclS covS n_solutions
#> X1=6, X2=6, X3=6 1 X1*X2 0.833 0.455 1
#> X1=7, X2=6, X3=6 2 X1*X2 1.000 0.394 1
#> X1=6, X2=7, X3=6 3 X1*X2*~X3 0.818 0.273 1
#> X1=7, X2=7, X3=6 4 X1*X2 1.000 0.303 1
#> X1=6, X2=6, X3=7 5 X3 0.864 0.576 1
#> X1=7, X2=6, X3=7 6 ~X1*X3 + X1*X2 0.931 0.818 1
#> X1=6, X2=7, X3=7 7 X3 0.864 0.576 1
#> X1=7, X2=7, X3=7 8 ~X1*X3 + ~X2*X3 + X1*X2*~X3 0.906 0.879 1# Intermediate solution: specify include = "?" and dir.exp
res_mcts_int <- ctSweepM(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_list = sweep_list,
thrY = 7,
include = "?",
dir.exp = c(1, 1, 1),
return_details = TRUE
)
summary(res_mcts_int)
#> MCTS-QCA Summary
#> ================
#>
#> Analysis Parameters:
#> Outcome: Y
#> Conditions: X1, X2, X3
#> Consistency cutoff: 0.8
#> Frequency cutoff: 1
#>
#> Results by Threshold:
#>
#> threshold combo_id expression inclS covS n_solutions
#> X1=6, X2=6, X3=6 1 X1*X2 0.833 0.455 1
#> X1=7, X2=6, X3=6 2 X1*X2 1.000 0.394 1
#> X1=6, X2=7, X3=6 3 X1*X2*~X3 0.818 0.273 1
#> X1=7, X2=7, X3=6 4 X1*X2 1.000 0.303 1
#> X1=6, X2=6, X3=7 5 X3 0.864 0.576 1
#> X1=7, X2=6, X3=7 6 ~X1*X3 + X1*X2 0.931 0.818 1
#> X1=6, X2=7, X3=7 7 X3 0.864 0.576 1
#> X1=7, X2=7, X3=7 8 X3 + X1*X2 0.906 0.879 1otSweep)OTS–QCA varies only the threshold of Y, keeping X thresholds fixed.
# Default: Complex solution
res_ots <- otSweep(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 6:8,
thrX = c(X1 = 7, X2 = 7, X3 = 7),
return_details = TRUE
)
summary(res_ots)
#> OTS-QCA Summary
#> ===============
#>
#> Analysis Parameters:
#> Outcome: Y
#> Conditions: X1, X2, X3
#> Consistency cutoff: 0.8
#> Frequency cutoff: 1
#>
#> Results by Threshold:
#>
#> thrY expression inclS covS n_solutions
#> 6 ~X1*X3 + ~X2*X3 + X1*X2*~X3 0.906 0.853 1
#> 7 ~X1*X3 + ~X2*X3 + X1*X2*~X3 0.906 0.879 1
#> 8 No solution NA NA 0# Intermediate solution: specify include = "?" and dir.exp
res_ots_int <- otSweep(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 6:8,
thrX = c(X1 = 7, X2 = 7, X3 = 7),
include = "?",
dir.exp = c(1, 1, 1),
return_details = TRUE
)
summary(res_ots_int)
#> OTS-QCA Summary
#> ===============
#>
#> Analysis Parameters:
#> Outcome: Y
#> Conditions: X1, X2, X3
#> Consistency cutoff: 0.8
#> Frequency cutoff: 1
#>
#> Results by Threshold:
#>
#> thrY expression inclS covS n_solutions
#> 6 X3 + X1*X2 0.906 0.853 1
#> 7 X3 + X1*X2 0.906 0.879 1
#> 8 No solution NA NA 0dtSweep)DTS–QCA varies both X thresholds and Y thresholds, creating a full 2D grid.
sweep_list_dts_X <- list(
X1 = 6:7,
X2 = 6:7,
X3 = 6:7
)
sweep_range_dts_Y <- 6:7
# Default: Complex solution
res_dts <- dtSweep(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_list_X = sweep_list_dts_X,
sweep_range_Y = sweep_range_dts_Y,
return_details = TRUE
)
summary(res_dts)
#> DTS-QCA Summary
#> ===============
#>
#> Analysis Parameters:
#> Outcome: Y
#> Conditions: X1, X2, X3
#> Consistency cutoff: 0.8
#> Frequency cutoff: 1
#>
#> Results by Threshold:
#>
#> thrY combo_id thrX expression inclS covS
#> 6 1 X1=6, X2=6, X3=6 X1*X2 0.833 0.441
#> 7 1 X1=6, X2=6, X3=6 X1*X2 0.833 0.455
#> 6 2 X1=7, X2=6, X3=6 X1*X2 1.000 0.382
#> 7 2 X1=7, X2=6, X3=6 X1*X2 1.000 0.394
#> 6 3 X1=6, X2=7, X3=6 X1*X2*~X3 0.818 0.265
#> 7 3 X1=6, X2=7, X3=6 X1*X2*~X3 0.818 0.273
#> 6 4 X1=7, X2=7, X3=6 X1*X2 1.000 0.294
#> 7 4 X1=7, X2=7, X3=6 X1*X2 1.000 0.303
#> 6 5 X1=6, X2=6, X3=7 X3 0.864 0.559
#> 7 5 X1=6, X2=6, X3=7 X3 0.864 0.576
#> 6 6 X1=7, X2=6, X3=7 ~X1*X3 + X1*X2 0.931 0.794
#> 7 6 X1=7, X2=6, X3=7 ~X1*X3 + X1*X2 0.931 0.818
#> 6 7 X1=6, X2=7, X3=7 X3 0.864 0.559
#> 7 7 X1=6, X2=7, X3=7 X3 0.864 0.576
#> 6 8 X1=7, X2=7, X3=7 ~X1*X3 + ~X2*X3 + X1*X2*~X3 0.906 0.853
#> 7 8 X1=7, X2=7, X3=7 ~X1*X3 + ~X2*X3 + X1*X2*~X3 0.906 0.879
#> n_solutions
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1
#> 1# Intermediate solution: specify include = "?" and dir.exp
res_dts_int <- dtSweep(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_list_X = sweep_list_dts_X,
sweep_range_Y = sweep_range_dts_Y,
include = "?",
dir.exp = c(1, 1, 1),
return_details = TRUE
)
summary(res_dts_int)
#> DTS-QCA Summary
#> ===============
#>
#> Analysis Parameters:
#> Outcome: Y
#> Conditions: X1, X2, X3
#> Consistency cutoff: 0.8
#> Frequency cutoff: 1
#>
#> Results by Threshold:
#>
#> thrY combo_id thrX expression inclS covS n_solutions
#> 6 1 X1=6, X2=6, X3=6 X1*X2 0.833 0.441 1
#> 7 1 X1=6, X2=6, X3=6 X1*X2 0.833 0.455 1
#> 6 2 X1=7, X2=6, X3=6 X1*X2 1.000 0.382 1
#> 7 2 X1=7, X2=6, X3=6 X1*X2 1.000 0.394 1
#> 6 3 X1=6, X2=7, X3=6 X1*X2*~X3 0.818 0.265 1
#> 7 3 X1=6, X2=7, X3=6 X1*X2*~X3 0.818 0.273 1
#> 6 4 X1=7, X2=7, X3=6 X1*X2 1.000 0.294 1
#> 7 4 X1=7, X2=7, X3=6 X1*X2 1.000 0.303 1
#> 6 5 X1=6, X2=6, X3=7 X3 0.864 0.559 1
#> 7 5 X1=6, X2=6, X3=7 X3 0.864 0.576 1
#> 6 6 X1=7, X2=6, X3=7 ~X1*X3 + X1*X2 0.931 0.794 1
#> 7 6 X1=7, X2=6, X3=7 ~X1*X3 + X1*X2 0.931 0.818 1
#> 6 7 X1=6, X2=7, X3=7 X3 0.864 0.559 1
#> 7 7 X1=6, X2=7, X3=7 X3 0.864 0.576 1
#> 6 8 X1=7, X2=7, X3=7 X3 + X1*X2 0.906 0.853 1
#> 7 8 X1=7, X2=7, X3=7 X3 + X1*X2 0.906 0.879 1Each sweep result contains:
inclS),covS).General guidance:
When QCA minimization produces multiple equivalent intermediate solutions, researchers face a methodological challenge: which solution should be reported? Traditional approaches often report only the first solution (M1), but this may miss important causal heterogeneity.
TSQCA v0.2.0 addresses this by:
Understanding the distinction between essential and selective prime implicants is essential for robust QCA interpretation:
| Type | Definition | Interpretation |
|---|---|---|
| Essential prime implicants | Present in ALL solutions | Robust findings; essential causal factors |
| Selective prime implicants | Present in SOME but not all solutions | Context-dependent; may vary across cases |
| Unique terms | Present in only ONE specific solution | Solution-specific; least robust |
extract_modeThe extract_mode parameter controls how solutions are
extracted:
# Returns all solutions concatenated
# Useful for seeing all equivalent solutions
result_all <- otSweep(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 6:8,
thrX = c(X1 = 7, X2 = 7, X3 = 7),
extract_mode = "all"
)
# Output includes n_solutions column
head(result_all$summary)
# expression column shows: "M1: A*B + C; M2: A*B + D; M3: ..."# Returns essential prime implicants (terms common to all solutions)
# Best for identifying robust findings
result_essential <- otSweep(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 6:8,
thrX = c(X1 = 7, X2 = 7, X3 = 7),
extract_mode = "essential"
)
# Output includes:
# - expression: essential prime implicants
# - selective_terms: terms in some but not all solutions
# - unique_terms: solution-specific terms
# - n_solutions: number of equivalent solutionsConsider a scenario where QCA produces three equivalent solutions:
A*B + C → YA*B + D → YA*B + E → YThe analysis reveals:
| Component | Terms | Interpretation |
|---|---|---|
| Essential (EPI) | A*B |
Present in all three solutions; robust finding |
| Selective (SPI) | C, D, E |
Each appears in one solution; context-dependent |
| Unique (M1) | C |
Only in solution 1 |
| Unique (M2) | D |
Only in solution 2 |
| Unique (M3) | E |
Only in solution 3 |
Recommendation: Report the essential prime
implicants (A*B → Y) as your main finding, and discuss the
selective prime implicants as alternative pathways in your discussion
section.
The generate_report() function creates comprehensive
markdown reports from your analysis results. This automates the
documentation process and ensures reproducibility.
Contains comprehensive analysis details:
return_details = TRUE (default in
v0.2.0)# Complete workflow
result <- otSweep(
dat = mydata,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 6:8,
thrX = c(X1 = 7, X2 = 7, X3 = 7)
)
# For main text
generate_report(result, "manuscript_results.md", dat = mydata, format = "simple")
# For supplementary materials
generate_report(result, "supplementary_full.md", dat = mydata, format = "full")All analysis parameters are stored in result$params for
reproducibility:
# View stored parameters
result$params
# Includes:
# - outcome, conditions: variable names
# - thrX, thrY: threshold values
# - incl.cut, n.cut, pri.cut: QCA parameters
# - dir.exp, include: minimization settingsWhen using sweep functions, the number of QCA analyses grows quickly. A systematic approach prevents wasted computation:
Understanding computational complexity helps plan your analysis:
| Function | Complexity | Example | Analyses |
|---|---|---|---|
otSweep() |
O(n) | 5 Y thresholds | 5 |
ctSweepS() |
O(n) | 5 X thresholds | 5 |
ctSweepM() |
O(m^k) | 3 thresholds × 3 conditions | 27 |
dtSweep() |
O(n × m^k) | 3 Y × 3^3 X | 81 |
For dtSweep() and ctSweepM(), reduce
conditions first:
If the same solution appears across multiple thresholds, your findings are robust:
thrY | expression | inclS | covS
-----|---------------|-------|------
6 | A*B + C → Y | 0.85 | 0.72
7 | A*B + C → Y | 0.88 | 0.68
8 | A*B + C → Y | 0.91 | 0.65
Interpretation: The solution A*B + C is
robust across threshold variations.
If solutions vary significantly, investigate the threshold sensitivity:
thrY | expression | inclS | covS
-----|---------------|-------|------
6 | A*B + C → Y | 0.82 | 0.75
7 | A*B → Y | 0.89 | 0.62
8 | B*D → Y | 0.93 | 0.45
Interpretation: Results are threshold-sensitive. Consider reporting the most theoretically justified threshold with appropriate caveats.
In QCA, researchers typically analyze conditions sufficient for the presence of an outcome (Y = 1). However, understanding conditions for the absence of an outcome (~Y) can provide equally valuable insights:
~ NotationTSQCA v0.3.0 supports the QCA package’s tilde (~)
notation for negated outcomes:
# Analyze conditions for Y >= threshold (standard)
result_Y <- otSweep(
dat = dat,
outcome = "Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 6:8,
thrX = c(X1 = 7, X2 = 7, X3 = 7)
)
# Analyze conditions for Y < threshold (negated)
result_negY <- otSweep(
dat = dat,
outcome = "~Y",
conditions = c("X1", "X2", "X3"),
sweep_range = 6:8,
thrX = c(X1 = 7, X2 = 7, X3 = 7)
)When using ~Y, the solution shows conditions sufficient
for the absence of the outcome:
| Analysis | Solution Example | Interpretation |
|---|---|---|
outcome = "Y" |
X1*X2 + X3 |
High X1 AND X2, OR high X3 → High Y |
outcome = "~Y" |
~X1*~X3 + ~X2*~X3 |
Low X1 AND X3, OR low X2 AND X3 → Low Y |
Note: Negated conditions (~X1) in the
solution mean the absence of that condition (below
threshold).
# ctSweepS with negated outcome
result <- ctSweepS(
dat = dat,
outcome = "~Y",
conditions = c("X1", "X2", "X3"),
sweep_var = "X3",
sweep_range = 6:8,
thrY = 7,
thrX_default = 7
)
# ctSweepM with negated outcome
result <- ctSweepM(
dat = dat,
outcome = "~Y",
conditions = c("X1", "X2"),
sweep_list = list(X1 = 6:7, X2 = 6:7),
thrY = 7
)
# dtSweep with negated outcome
result <- dtSweep(
dat = dat,
outcome = "~Y",
conditions = c("X1", "X2"),
sweep_list_X = list(X1 = 6:7, X2 = 7),
sweep_range_Y = 6:8
)TSQCA can generate Fiss-style configuration charts (Table 5 format) commonly used in QCA publications.
Configuration charts are now automatically included in reports
generated by generate_report():
# Generate report with configuration charts (default)
generate_report(result, "my_report.md", dat = dat, format = "full")
# Disable charts if needed
generate_report(result, "my_report.md", dat = dat, include_chart = FALSE)
# Use LaTeX symbols for academic papers
generate_report(result, "my_report.md", dat = dat, chart_symbol_set = "latex")You can also generate configuration charts directly:
# From path strings
paths <- c("A*B*~C", "A*D", "B*E")
chart <- config_chart_from_paths(paths)
cat(chart)
#> | Condition | M1 | M2 | M3 |
#> |:--:|:--:|:--:|:--:|
#> | A | ● | ● | |
#> | B | ● | | ● |
#> | C | ⊗ | | |
#> | D | | ● | |
#> | E | | | ● |
#>
#> *● = presence, ⊗ = absence, blank = don't care*Three symbol sets are available:
When you have multiple equivalent solutions:
solutions <- list(
c("A*B", "C*D"),
c("A*B", "C*E")
)
chart <- config_chart_multi_solutions(solutions)
cat(chart)
#> **Note:** 2 equivalent solutions exist. Tables are shown separately below.
#>
#> ### Solution M1
#>
#> | Condition | M1 | M2 |
#> |:--:|:--:|:--:|
#> | A | ● | |
#> | B | ● | |
#> | C | | ● |
#> | D | | ● |
#>
#> ---
#>
#> ### Solution M2
#>
#> | Condition | M1 | M2 |
#> |:--:|:--:|:--:|
#> | A | ● | |
#> | B | ● | |
#> | C | | ● |
#> | E | | ● |
#>
#> *● = presence, ⊗ = absence, blank = don't care*TSQCA provides a structured and reproducible way to evaluate
how threshold choices influence QCA results.
Using CTS, MCTS, OTS, and DTS sweeps, researchers can:
New in v1.1.0:
include = "" and
dir.exp = NULL (complex solution)dir.exp handlingNew in v0.5.0:
include_chart,
chart_symbol_setconfig_chart_from_paths(),
config_chart_multi_solutions()New in v0.3.0:
outcome,
conditions)~Y notation)New in v0.2.0:
For more information on TS-QCA methodology, see:
sessionInfo()
#> R version 4.4.2 (2024-10-31 ucrt)
#> Platform: x86_64-w64-mingw32/x64
#> Running under: Windows 11 x64 (build 26200)
#>
#> Matrix products: default
#>
#>
#> locale:
#> [1] LC_COLLATE=C LC_CTYPE=Japanese_Japan.utf8
#> [3] LC_MONETARY=Japanese_Japan.utf8 LC_NUMERIC=C
#> [5] LC_TIME=Japanese_Japan.utf8
#>
#> time zone: Asia/Tokyo
#> tzcode source: internal
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] QCA_3.23 admisc_0.39 TSQCA_1.1.0
#>
#> loaded via a namespace (and not attached):
#> [1] cli_3.6.5 knitr_1.50 rlang_1.1.6 xfun_0.55
#> [5] otel_0.2.0 promises_1.5.0 shiny_1.12.1 jsonlite_2.0.0
#> [9] xtable_1.8-4 htmltools_0.5.9 httpuv_1.6.16 sass_0.4.10
#> [13] lpSolve_5.6.23 rmarkdown_2.30 evaluate_1.0.4 jquerylib_0.1.4
#> [17] fastmap_1.2.0 yaml_2.3.10 lifecycle_1.0.4 compiler_4.4.2
#> [21] Rcpp_1.1.0 rstudioapi_0.17.1 later_1.4.4 digest_0.6.39
#> [25] R6_2.6.1 magrittr_2.0.4 bslib_0.9.0 declared_0.25
#> [29] tools_4.4.2 mime_0.13 venn_1.12 cachem_1.1.0