Skip to content

Commit 7062d92

Browse files
authored
Merge pull request #141 from junder873/add-typst-support
Add support for Typst tables
2 parents b780081 + d590e97 commit 7062d92

File tree

12 files changed

+198
-11
lines changed

12 files changed

+198
-11
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "RegressionTables"
22
uuid = "d519eb52-b820-54da-95a6-98e1306fdade"
33
authors = ["Johannes Boehm <[email protected]>"]
4-
version = "0.7.2"
4+
version = "0.7.3"
55

66
[deps]
77
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"

docs/src/api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ RegressionTables.add_blank
7373
RegressionTables.missing_vars
7474
RegressionTables.add_element!
7575
RegressionTables.find_vertical_gaps
76+
RegressionTables.extra_cell_space
7677
```
7778

7879
## How Types are Displayed

docs/src/examples.md

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Setup for the following examples:
66
```@meta
77
DocTestSetup = quote # hide
88
using RegressionTables, DataFrames, RDatasets, FixedEffectModels, GLM, MixedModels;
9-
df = dataset("datasets", "iris");
9+
df = RDatasets.dataset("datasets", "iris");
1010
df[!,:isSmall] = df[!,:SepalWidth] .< 2.9;
1111
rr1 = reg(df, @formula(SepalLength ~ SepalWidth));
1212
rr2 = reg(df, @formula(SepalLength ~ SepalWidth + PetalLength + fe(Species)));
@@ -1315,7 +1315,7 @@ Pseudo R2 0.006 0.006 0.297 0.297
13151315
Displays whether or not the standard errors are clustered and in what ways.
13161316

13171317
```jldoctest
1318-
df_cigar = dataset("plm", "Cigar");
1318+
df_cigar = RDatasets.dataset("plm", "Cigar");
13191319
13201320
rr_c1 = reg(df_cigar, @formula(Sales ~ NDI + fe(State) + fe(Year)), Vcov.cluster(:State));
13211321
rr_c2 = reg(df_cigar, @formula(Sales ~ NDI + Price + fe(State) + fe(Year)), Vcov.cluster(:State, :Year));
@@ -1429,4 +1429,88 @@ Subject | Prec & Load 855.252
14291429
N 1,789 1,789 1,789
14301430
Log Likelihood -14,685.198 -14,765.033 -14,711.866
14311431
---------------------------------------------------------------
1432+
```
1433+
1434+
## Typst Support
1435+
1436+
Similar to Latex, this package can produce Typst Tables. This requires Typst v0.11.
1437+
1438+
1439+
```jldoctest
1440+
regtable(rr1,rr2,rr3,rr4; render = TypstTable())
1441+
1442+
# output
1443+
1444+
#table(
1445+
columns: (auto, auto, auto, auto, auto),
1446+
align: (left, right, right, right, right),
1447+
column-gutter: 1fr,
1448+
stroke: none,
1449+
1450+
table.hline(),
1451+
[] , table.cell(colspan: 3, align: center)[SepalLength] , table.cell(colspan: 1, align: center)[SepalWidth],
1452+
table.hline(start: 1, end: 4, stroke: 0.5pt), table.hline(start: 4, end: 5, stroke: 0.5pt),
1453+
[] , [(1)], [(2)], [(3)], [(4)],
1454+
table.hline(stroke: 0.7pt),
1455+
[(Intercept)] , [6.526$""^(***)$], [], [], [],
1456+
[] , [(0.479)], [], [], [],
1457+
[SepalWidth] , [-0.223], [0.432$""^(***)$], [0.516$""^(***)$], [],
1458+
[] , [(0.155)], [(0.081)], [(0.104)], [],
1459+
[PetalLength] , [], [0.776$""^(***)$], [0.723$""^(***)$], [-0.188$""^(*)$],
1460+
[] , [], [(0.064)], [(0.129)], [(0.083)],
1461+
[PetalWidth] , [], [], [-0.625], [0.626$""^(***)$],
1462+
[] , [], [], [(0.354)], [(0.123)],
1463+
[PetalLength $times$ PetalWidth], [], [], [0.066], [],
1464+
[] , [], [], [(0.067)], [],
1465+
[SepalLength] , [], [], [], [0.378$""^(***)$],
1466+
[] , [], [], [], [(0.066)],
1467+
table.hline(stroke: 0.7pt),
1468+
[Species Fixed Effects] , [], [Yes], [Yes], [Yes],
1469+
[isSmall Fixed Effects] , [], [], [Yes], [],
1470+
table.hline(stroke: 0.7pt),
1471+
[_N_] , [150], [150], [150], [150],
1472+
[_R_$""^2$] , [0.014], [0.863], [0.868], [0.635],
1473+
[Within-_R_$""^2$] , [], [0.642], [0.598], [0.391],
1474+
table.hline(),
1475+
)
1476+
```
1477+
1478+
```jldoctest
1479+
regtable(rr1, rr6, rr7; render = TypstTable())
1480+
1481+
# output
1482+
1483+
#table(
1484+
columns: (auto, auto, auto, auto),
1485+
align: (left, right, right, right),
1486+
column-gutter: 1fr,
1487+
stroke: none,
1488+
1489+
table.hline(),
1490+
[] , table.cell(colspan: 1, align: center)[SepalLength], table.cell(colspan: 2, align: center)[isSmall],
1491+
table.hline(start: 1, end: 2, stroke: 0.5pt), table.hline(start: 2, end: 4, stroke: 0.5pt),
1492+
[] , [(1)], [(2)], [(3)],
1493+
table.hline(stroke: 0.7pt),
1494+
[(Intercept)] , [6.526$""^(***)$], [-1.917], [10.189$""^(***)$],
1495+
[] , [(0.479)], [(1.242)], [(2.607)],
1496+
[SepalWidth] , [-0.223], [], [],
1497+
[] , [(0.155)], [], [],
1498+
[PetalLength] , [], [-0.773], [3.580$""^(***)$],
1499+
[] , [], [(0.554)], [(0.708)],
1500+
[PetalWidth] , [], [-3.782$""^(**)$], [-3.637$""^(**)$],
1501+
[] , [], [(1.256)], [(1.127)],
1502+
[Species: versicolor], [], [10.441$""^(***)$], [],
1503+
[] , [], [(1.957)], [],
1504+
[Species: virginica] , [], [13.230$""^(***)$], [],
1505+
[] , [], [(2.636)], [],
1506+
[SepalLength] , [], [], [-3.519$""^(***)$],
1507+
[] , [], [], [(0.697)],
1508+
table.hline(stroke: 0.7pt),
1509+
[Estimator] , [OLS], [Binomial], [Binomial],
1510+
table.hline(stroke: 0.7pt),
1511+
[_N_] , [150], [150], [150],
1512+
[_R_$""^2$] , [0.014], [], [],
1513+
[Pseudo _R_$""^2$] , [0.006], [0.347], [0.297],
1514+
table.hline(),
1515+
)
14321516
```

docs/src/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ To install the package, type in the Julia command prompt
2323
```@example main_data
2424
using RegressionTables, DataFrames, FixedEffectModels, RDatasets, GLM
2525
26-
df = dataset("datasets", "iris")
26+
df = RDatasets.dataset("datasets", "iris")
2727
2828
rr1 = reg(df, @formula(SepalLength ~ SepalWidth + fe(Species)))
2929
rr2 = reg(df, @formula(SepalLength ~ SepalWidth + PetalLength + fe(Species)))

docs/src/keep_drop_order.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
DocTestSetup = quote # hide
33
using RegressionTables, DataFrames, FixedEffectModels, RDatasets
44
5-
df = dataset("datasets", "iris")
5+
df = RDatasets.dataset("datasets", "iris")
66
df[!,:SpeciesDummy] = df[!,:Species]
77
88
rr1 = reg(df, @formula(SepalLength ~ SepalWidth + fe(SpeciesDummy)))

src/RegressionTables.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module RegressionTables
3737
##############################################################################
3838

3939
export regtable, LatexTable, LatexTableStar, AsciiTable, HtmlTable, AbstractRenderType,
40-
AbstractAscii, AbstractLatex, AbstractHtml
40+
AbstractAscii, AbstractLatex, AbstractHtml, TypstTable, AbstractTypst
4141
export Nobs, R2, R2McFadden, R2CoxSnell, R2Nagelkerke,
4242
R2Deviance, AdjR2, AdjR2McFadden, AdjR2Deviance, DOF, LogLikelihood, AIC, BIC, AICC,
4343
FStat, FStatPValue, FStatIV, FStatIVPValue, R2Within, PseudoR2, AdjPseudoR2
@@ -65,6 +65,7 @@ module RegressionTables
6565
include("rendersettings/ascii.jl")
6666
include("rendersettings/latex.jl")
6767
include("rendersettings/html.jl")
68+
include("rendersettings/typst.jl")
6869

6970

7071
# main settings

src/datarow.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ function calc_widths(rows::Vector{DataRow{T}}) where {T<:AbstractRenderType}
267267
end
268268
end
269269
else
270-
out_lengths[i] = max(out_lengths[i], length(s))
270+
out_lengths[i] = max(out_lengths[i], length(s) + extra_cell_space(render))
271271
end
272272
end
273273
end
@@ -280,7 +280,10 @@ end
280280
Updates the widths of each column in the row. If lengths are provided, then it should equate to the total number
281281
of columns in the table, not the number of elements in the row.
282282
"""
283-
function update_widths!(row::DataRow{T}, new_lengths=length.(repr.(T(), row.data))) where {T}
283+
function update_widths!(
284+
row::DataRow{T},
285+
new_lengths=length.(repr.(T(), row.data)) .+ extra_cell_space(T())
286+
) where {T}
284287
#@assert length(row) == length(new_lengths) "Wrong number of lengths"
285288
render = T()
286289
if length(row.data) == length(new_lengths)

src/rendersettings/default.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ RegressionTables.interaction_combine(render::AbstractLatex) = " \\& "
3434
"""
3535
interaction_combine(render::AbstractRenderType) = " & "
3636

37+
"""
38+
extra_cell_space(render::AbstractRenderType)
39+
40+
Used to add extra space to the cell and defaults to 0.
41+
"""
42+
extra_cell_space(::AbstractRenderType) = 0
43+
3744
"""
3845
categorical_equal(render::AbstractRenderType)
3946

src/rendersettings/typst.jl

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
abstract type AbstractTypst <: AbstractRenderType end
2+
struct TypstTable <: AbstractTypst end
3+
4+
function tablestart(::AbstractTypst, align)
5+
cols = [c == 'l' ? "left" : c == 'r' ? "right" : "center" for c in align]
6+
cols_align = join(cols, ", ")
7+
cols = join(fill("auto", length(cols)), ", ")
8+
9+
"""
10+
#table(
11+
columns: ($cols),
12+
align: ($cols_align),
13+
column-gutter: 1fr,
14+
stroke: none,
15+
"""
16+
end
17+
18+
wrapper(::AbstractTypst, x) = "\$\"\"^($x)\$"
19+
20+
tableend(::AbstractTypst) = ")"
21+
22+
function Base.repr(rndr::AbstractTypst, val::Pair; align="c", args...)
23+
s = Base.repr(rndr, first(val); args...)
24+
if length(s) == 0 && length(last(val)) == 1
25+
s
26+
else
27+
multicolumn(rndr, s, length(last(val)), align)
28+
end
29+
end
30+
function multicolumn(rndr::AbstractTypst, s, cols::Int, align="c")
31+
x = if align == "c" || align == 'c'
32+
"center"
33+
elseif align == "l" || align == 'l'
34+
"left"
35+
elseif align == "r" || align == 'r'
36+
"right"
37+
end
38+
"table.cell(colspan: $cols, align: $x)[$s]"
39+
end
40+
41+
underline(::AbstractTypst, colmin::Int, colmax::Int) = "table.hline(start: $(colmin-1), end: $(colmax), stroke: 0.5pt)"
42+
43+
toprule(x::AbstractTypst) = linestart(x) * "table.hline(), "
44+
midrule(x::AbstractTypst) = linestart(x) * "table.hline(stroke: 0.7pt), "
45+
bottomrule(x::AbstractTypst) = linestart(x) * "table.hline(), "
46+
linestart(::AbstractTypst) = " "
47+
lineend(::AbstractTypst) = ","
48+
tablestart(tab::RegressionTable{<:AbstractTypst}) = tablestart(tab.render, tab.align)
49+
colsep(::AbstractTypst) = ", "
50+
51+
label(::AbstractTypst, x::Type{Nobs}) = "_N_"
52+
label(::AbstractTypst, x::Type{R2}) = "_R_\$\"\"^2\$"
53+
label(::AbstractTypst, x::Type{FStat}) = "_F_"
54+
label_p(::AbstractTypst, ) = "_p_"
55+
56+
extra_cell_space(::AbstractTypst) = 2 # to account for "[]"
57+
58+
interaction_combine(::AbstractTypst) = " \$times\$ "
59+
60+
function Base.print(io::IO, row::DataRow{T}) where {T<:AbstractTypst}
61+
render = T()
62+
print(io, linestart(render))
63+
for (i, x) in enumerate(row.data)
64+
s = if isa(x, Pair)
65+
repr(render, x; align = row.align[i])
66+
else
67+
"[" * repr(render, x; align = row.align[i]) * "]"
68+
end
69+
print(io, make_padding(s, row.colwidths[i], row.align[i]))
70+
if i < length(row.data)
71+
print(io, colsep(render))
72+
end
73+
end
74+
print(io, lineend(render))
75+
if any(row.print_underlines)
76+
println(io)
77+
print(io, linestart(render))
78+
for (i, x) in enumerate(row.data)
79+
s = isa(x, Pair) ? repr(render, first(x)) : repr(render, x)
80+
if length(s) == 0 || !row.print_underlines[i]
81+
continue
82+
end
83+
if isa(x, Pair)
84+
print(io, underline(render, first(last(x)), last(last(x))))
85+
else
86+
print(io, underline(render, i,i))
87+
end
88+
print(io, colsep(render))
89+
end
90+
end
91+
end

test/GLFixedEffectModels.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using GLFixedEffectModels, GLM, RDatasets, Test
44

55
# include("src/RegressionTables.jl")
6-
df = dataset("datasets", "iris")
6+
df = RDatasets.dataset("datasets", "iris")
77
df[!, :isSmall] = df[!, :SepalWidth] .< 2.9
88
df[!, :isWide] = df[!, :SepalWidth] .> 2.5
99
df[!, :binary] = @. ifelse(df[!, :PetalWidth] .> 1.0, 1.0, 0.0)

test/RegressionTables.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using RegressionTables
22
using FixedEffectModels, GLM, RDatasets, Test
33

4-
df = dataset("datasets", "iris")
4+
df = RDatasets.dataset("datasets", "iris")
55
df[!, :isSmall] = df[!, :SepalWidth] .< 2.9
66
df[!, :isWide] = df[!, :SepalWidth] .> 2.5
77

test/default_changes.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ own test set
99
using RegressionTables
1010
using FixedEffectModels, GLM, RDatasets, Test
1111

12-
df = dataset("datasets", "iris")
12+
df = RDatasets.dataset("datasets", "iris")
1313
df[!, :isSmall] = df[!, :SepalWidth] .< 2.9
1414
df[!, :isWide] = df[!, :SepalWidth] .> 2.5
1515

0 commit comments

Comments
 (0)