Code
import svgling
from svgling import draw_tree
from svgling.figure import Caption, SideBySide, RowByRow
from svgling.core import subscript_node
svgling
diagram galleryKyle Rawlins
August 20, 2024
This gallery provides several examples of relatively complex SVG tree diagrams rendering using the svgling
package. To begin with, here is an example from Carnie (2012) that illustrates multiline nodes paired with aligned leaf nodes.
The following example illustrates Quantifier Raising (QR) in the style of Heim and Kratzer (1998), involving movement arrows, subfigures, and subtree highlighting.
qrtree0 = ("TP", ("DP", ("D", "every"), ("NP", ("N", "cat"))),
("VP", ("V", "likes"), ("DP", ("D", "some"), ("NP", ("N", "dog")))))
out0 = Caption(draw_tree(qrtree0), "LF input (= Surface Structure)")
qrtree1 = ("TP", (subscript_node("DP", "1"), ("D", "every"), ("NP", ("N", "cat"))),
("VP", ("V", "likes"), (subscript_node("DP", "3"), ("D", "some"), ("NP", ("N", "dog")))))
out1 = draw_tree(qrtree1)
out1.box_constituent((0,))
out1.box_constituent((1,1))
out1 = Caption(out1, "Step 1: free indexing (1 of 2 indexings)")
qrtree2 = ("TP", ("DP", ("D", "some"), ("NP", ("N", "dog"))),
("TP", "3", ("TP", (subscript_node("DP", "1"), ("D", "every"), ("NP", ("N", "cat"))),
("VP", ("V", "likes"), ("DP", subscript_node("t", "3"))))))
out2 = draw_tree(qrtree2)
out2.movement_arrow((1,1,1,1), (0,))
out2.box_constituent((0,))
out2.box_constituent((1,1,0))
out2 = Caption(out2, "Step 2: QR an indexed DP (choosing the object)")
qrtree3 = ("TP", ("DP", ("D", "every"), ("NP", ("N", "cat"))),
("TP", "1", ("TP", ("DP", ("D", "some"), ("NP", ("N", "dog"))),
("TP", "3", ("TP", ("DP", subscript_node("t", "1")), ("VP", ("V", "likes"), ("DP", subscript_node("t", "3"))))))))
out3 = draw_tree(qrtree3)
out3.movement_arrow((1,1,1,1,0), (0,))
out3.box_constituent((0,))
out3.movement_arrow((1,1,1,1,1,1), (1,1,0))
out3.box_constituent((1,1,0))
out3 = Caption(out3, "Step 3: QR an indexed DP (choosing the subject).")
Caption(RowByRow(SideBySide(out0, out1), SideBySide(out2,out3)), "Trees illustrating a QR (Quantifier Raising) derivation in the Heim & Kratzer 1998 style")
The following example, based on a tree from McCloskey (2000), demonstrates multi-headed movement arrows.
mccloskey = ("FP", ("F", ("V", "put")),
("AgrOP", (subscript_node("DP", "Obj"), "milk"),
("", ("AgrO", subscript_node("t", "V")),
("VP", subscript_node("t", "Subj"), ("", subscript_node("t", "V"),
("VP", ("PP", "in it"), ("", ("V", subscript_node("t", "V")), subscript_node("t", "Obj"))))))))
# TODO: AgrOP should be set with a subscript O, currently not supported.
out = draw_tree(mccloskey)
out.set_edge_style((1,0,0), svgling.core.TriangleEdge())
out.set_edge_style((1,1,1,1,1,0,0), svgling.core.TriangleEdge())
out.movement_arrow((1,1,1,1,1,1,0,0), (1,1,0,0))
out.movement_arrow((1,1,0,0), (0,0,0))
out.movement_arrow((1,1,1,1,1,1,1), (1,0))
Caption(out, "Tree after ex. 58 of McCloskey (2000)")
The following example, which is based on a PCFG example from the classic Hale (2001) account of garden path sentences, illustrates how to use a custom tree parsing function together with a non-default node renderer. An nltk
probabilistic parser returns a subclass of tree that uses label()
normally, but also has a probability value indicating the “inside probability” of the subtree given its constituents. There’s a provided function svgling.core.ptree_split
that renders such trees in an ugly but functional way; this example improves on that a bit by using subscripts.
The example constructs a nltk.grammar.PCFG
object based on an example in Hale (2001), parses a sentence using that PCFG, and draws the resulting tree incorporating inside probabilities into the node labels.
import nltk, nltk.parse
from nltk.grammar import PCFG
# note: this is a binarized version of an example grammar due to Hale in the cited paper.
hale1 = PCFG.fromstring("""
S0 -> S '.' [1.0]
S -> NP VP [1.0]
NP -> DT NN [0.88]
NP -> NP VP [0.12]
PP -> IN NP [1.0]
VP -> VBD PP [0.17]
VP -> VBN PP [0.75]
VP -> VBD [0.08]
DT -> 'the' [1.0]
NN -> 'horse' [0.5]
NN -> 'barn' [0.5]
VBD -> 'fell' [0.5]
VBD -> 'raced' [0.5]
VBN -> 'raced' [1.0]
IN -> 'past' [1.0]
""")
# parse "The horse raced past the barn fell." using one of nltk's chart parsers:
hale1_parser = nltk.parse.pchart.InsideChartParser(hale1)
parses = list(hale1_parser.parse("the horse raced past the barn fell .".split()))
def ptree_split2(t):
try:
return (svgling.core.subscript_node(f"{t.label()}", f"p={t.prob()}", scale=0.85), list(t))
except AttributeError:
# indicate that this function doesn't handle `t`. (Leaf nodes of this tree
# class are `str` -- this leaves them to the default node parser.)
return None
svgling.draw_tree(parses[0], tree_split=ptree_split2)
The following tree is a typical example of how compositional semantics might be integrated into a tree structure in formal semantics. This tree is not pure SVG (which doesn’t support latex code), but is rendered using svgling.html
.
import svgling.html
svgling.html.compat(svgling.html.Compat.USE_MARKDOWN) # needed for quarto
from svgling.html import multiline_text as ml
def math(s):
# note: we are in markdown mode, so using delimiters with backslashes becomes harder...
return f"${s}$"
svgling.html.draw_tree(
ml(math(r"\text{Saw}(\iota x_e{:\:}\text{Elephant}(x),\iota x_e{:\:}\text{Rhino}(x))"), math(r"\text{Type: }t")),
(ml(math(r"\iota x_e{:\:}\text{Elephant}(x)"), math(r"\text{Type: }e")),
ml(math(r"\lambda f_{\langle e,t \rangle }{:\:}\iota x_e{:\:}f(x)"),
math(r"\text{Type: }\langle \langle e,t\rangle ,e\rangle")),
ml(math(r"\lambda x_e{:\:}\text{Elephant}(x)"), math(r"\text{Type: }\langle e,t\rangle"))),
(ml(math(r"\lambda x_e{:\:}\text{Saw}(x,\iota x_e{:\:}\text{Rhino}(x))"), math(r"\text{Type: }\langle e,t\rangle")),
ml(math(r"\lambda y_e{:\:}\lambda x_e{:\:}\text{Saw}(x,y)"),
math(r"\text{Type: }\langle e,\langle e,t\rangle\rangle")),
(ml(math(r"\iota x_e{:\:}\text{Rhino}(x)"), math(r"\text{Type: }e")),
ml(math(r"\lambda f_{\langle e,t \rangle }{:\:}\iota x_e{:\:}f(x)"),
math(r"\text{Type: }\langle \langle e,t\rangle ,e\rangle")),
ml(math(r"\lambda x_e{:\:}\text{Rhino}(x)"), math(r"\text{Type: }\langle e,t\rangle")))))
I’d be excited to get both new diagram requests, and PRs for new diagrams: https://github.com/rawlins/svgling.