You might want to consider the start of this tutorial.

Short introductions to other TF datasets:

Search Introduction

Search in Text-Fabric is a template based way of looking for structural patterns in your dataset.

It is inspired by the idea of topographic query, as worked out in MQL which has been implemented in Emdros. See also pitfalls of MQL

Within Text-Fabric we have the unique possibility to combine the ease of formulating search templates for complicated syntactical patterns with the power of programmatically processing the results.

This notebook will show you how to get up and running.

See the notebook searchFromMQL for examples how MQL queries can be expressed in Text-Fabric search.

Alternative for hand-coding

Search is a powerful feature for a wide range of purposes.

Quite a bit of the implementation work has been dedicated to optimize performance. Yet I do not pretend to have found optimal strategies for all possible search templates. Some search tasks may turn out to be somewhat costly or even very costly.

That being said, I think search might turn out helpful in many cases, especially by reducing the amount of hand-coding needed to work with special subsets of your data.

Easy command

Search is as simple as saying (just an example)

results = A.search(template)
A.show(results)

See all ins and outs in the search template docs.

In [1]:
%load_ext autoreload
%autoreload 2

Incantation

The ins and outs of installing Text-Fabric, getting the corpus, and initializing a notebook are explained in the start tutorial.

In [3]:
from tf.app import use
In [4]:
A = use('bhsa', hoist=globals())
# A = use("bhsa:clone", checkout="clone", hoist=globals())
TF-app: ~/text-fabric-data/annotation/app-bhsa/code
data: ~/text-fabric-data/etcbc/bhsa/tf/2021
data: ~/text-fabric-data/etcbc/phono/tf/2021
data: ~/text-fabric-data/etcbc/parallels/tf/2021
This is Text-Fabric 9.0.3
Api reference : https://annotation.github.io/text-fabric/tf/cheatsheet.html

121 features found and 0 ignored
Text-Fabric API: names N F E L T S C TF directly usable

Basic search command

We start with the most simple form of issuing a query. Let's look for the proper nouns in 1 Samuel. We also want to show the clauses in which they occur.

All work involved in searching takes place under the hood.

In [5]:
query = """
book book=Samuel_I
  clause
    word sp=nmpr
"""
results = A.search(query)
  0.49s 1868 results

We have the results. We only need to display them. Here are the first few in a table:

In [6]:
A.table(results, end=3)
npbookclauseword
11_Samuel 1:11_Samuelוַיְהִי֩ אִ֨ישׁ אֶחָ֜ד מִן־הָרָמָתַ֛יִם צֹופִ֖ים מֵהַ֣ר אֶפְרָ֑יִם אֶפְרָ֑יִם
21_Samuel 1:11_Samuelוּשְׁמֹ֡ו אֶ֠לְקָנָה בֶּן־יְרֹחָ֧ם בֶּן־אֱלִיה֛וּא בֶּן־תֹּ֥חוּ בֶן־צ֖וּף אֶפְרָתִֽי׃ אֶ֠לְקָנָה
31_Samuel 1:11_Samuelוּשְׁמֹ֡ו אֶ֠לְקָנָה בֶּן־יְרֹחָ֧ם בֶּן־אֱלִיה֛וּא בֶּן־תֹּ֥חוּ בֶן־צ֖וּף אֶפְרָתִֽי׃ יְרֹחָ֧ם

The hyperlinks in the p column point to SHEBANQ, to the verse most relevant to the individual results.

The columns with the book is not very informative. We can leave it out. You can leave columns out by passing skipCols=xxx where xxx is a set of numbers, which may also be passed as a space-separated string of numbers.

Note that the book column is the first column (starting after the p column, coounting starts at 1).

In [7]:
A.table(results, end=10, skipCols="1")
npclauseword
11_Samuel 1:1וַיְהִי֩ אִ֨ישׁ אֶחָ֜ד מִן־הָרָמָתַ֛יִם צֹופִ֖ים מֵהַ֣ר אֶפְרָ֑יִם אֶפְרָ֑יִם
21_Samuel 1:1וּשְׁמֹ֡ו אֶ֠לְקָנָה בֶּן־יְרֹחָ֧ם בֶּן־אֱלִיה֛וּא בֶּן־תֹּ֥חוּ בֶן־צ֖וּף אֶפְרָתִֽי׃ אֶ֠לְקָנָה
31_Samuel 1:1וּשְׁמֹ֡ו אֶ֠לְקָנָה בֶּן־יְרֹחָ֧ם בֶּן־אֱלִיה֛וּא בֶּן־תֹּ֥חוּ בֶן־צ֖וּף אֶפְרָתִֽי׃ יְרֹחָ֧ם
41_Samuel 1:1וּשְׁמֹ֡ו אֶ֠לְקָנָה בֶּן־יְרֹחָ֧ם בֶּן־אֱלִיה֛וּא בֶּן־תֹּ֥חוּ בֶן־צ֖וּף אֶפְרָתִֽי׃ אֱלִיה֛וּא
51_Samuel 1:1וּשְׁמֹ֡ו אֶ֠לְקָנָה בֶּן־יְרֹחָ֧ם בֶּן־אֱלִיה֛וּא בֶּן־תֹּ֥חוּ בֶן־צ֖וּף אֶפְרָתִֽי׃ תֹּ֥חוּ
61_Samuel 1:1וּשְׁמֹ֡ו אֶ֠לְקָנָה בֶּן־יְרֹחָ֧ם בֶּן־אֱלִיה֛וּא בֶּן־תֹּ֥חוּ בֶן־צ֖וּף אֶפְרָתִֽי׃ צ֖וּף
71_Samuel 1:2שֵׁ֤ם אַחַת֙ חַנָּ֔ה חַנָּ֔ה
81_Samuel 1:2וְשֵׁ֥ם הַשֵּׁנִ֖ית פְּנִנָּ֑ה פְּנִנָּ֑ה
91_Samuel 1:2לִפְנִנָּה֙ יְלָדִ֔ים פְנִנָּה֙
101_Samuel 1:2וּלְחַנָּ֖ה אֵ֥ין יְלָדִֽים׃ חַנָּ֖ה

Here is the first one in a pretty display:

In [8]:
A.show(results, end=1)

result 1

book 1_Samuel
book=Samuel_I
verse
book=Samuel_I
sentence
clause
phrase
sp=conj
phrase
sentence

We are going to do some more work where we want to skip column 1, so we make that the temporary default:

In [9]:
A.displaySetup(skipCols="1")

Now we show a few results without the book column:

In [10]:
A.show(results, end=2)

result 1

verse
book=Samuel_I
sentence
clause
phrase
sp=conj
phrase
sentence

result 2

verse
book=Samuel_I
sentence
clause
phrase
sp=conj
phrase
sentence

or, stopping at the clause level:

In [11]:
A.show(results, end=2, baseTypes={"clause"})

result 1

verse
book=Samuel_I
sentence
clause וַיְהִי֩ אִ֨ישׁ אֶחָ֜ד מִן־הָרָמָתַ֛יִם צֹופִ֖ים מֵהַ֣ר אֶפְרָ֑יִם
sentence
clause וּשְׁמֹ֡ו אֶ֠לְקָנָה בֶּן־יְרֹחָ֧ם בֶּן־אֱלִיה֛וּא בֶּן־תֹּ֥חוּ בֶן־צ֖וּף אֶפְרָתִֽי׃

result 2

verse
book=Samuel_I
sentence
clause וַיְהִי֩ אִ֨ישׁ אֶחָ֜ד מִן־הָרָמָתַ֛יִם צֹופִ֖ים מֵהַ֣ר אֶפְרָ֑יִם
sentence
clause וּשְׁמֹ֡ו אֶ֠לְקָנָה בֶּן־יְרֹחָ֧ם בֶּן־אֱלִיה֛וּא בֶּן־תֹּ֥חוּ בֶן־צ֖וּף אֶפְרָתִֽי׃

We can view result in phonetic representation as well:

In [12]:
A.table(results, end=3, fmt="text-phono-full")
npclauseword
11_Samuel 1:1wayᵊhˌî ʔˌîš ʔeḥˈāḏ min-rāmāṯˈayim ṣôfˌîm hˈar ʔefrˈāyim ʔefrˈāyim
21_Samuel 1:1ûšᵊmˈô ʔelqānˌā ben-yᵊrōḥˈām ben-ʔᵉlîhˈû ben-tˌōḥû ven-ṣˌûf ʔefrāṯˈî . ʔelqānˌā
31_Samuel 1:1ûšᵊmˈô ʔelqānˌā ben-yᵊrōḥˈām ben-ʔᵉlîhˈû ben-tˌōḥû ven-ṣˌûf ʔefrāṯˈî . yᵊrōḥˈām
In [13]:
A.show(results, end=1, fmt="text-phono-full")

result 1

verse
book=Samuel_I
sentence
clause
phrase
sp=conj
phrase
sp=verb
phrase
sp=subs
sp=prep
sp=art
sp=prep
sp=subs
sentence
clause
phrase
sp=conj
phrase
phrase
sp=subs
sp=subs
sp=subs
sp=subs
sp=nmpr

We are done with this query and its results. We reset the skipCols parameter.

In [14]:
A.displayReset("skipCols")

Condense results

There are two fundamentally different ways of presenting the results: condensed and uncondensed.

In uncondensed view, all results are listed individually. You can keep track of which parts belong to which results. The display can become unwieldy.

This is the default view, because it is the straightest, most logical, answer to your query.

In condensed view all nodes of all results are grouped in containers first (e.g. verses), and then presented container by container. You loose the information of what parts belong to what result.

Here is an example of the difference.

In [15]:
query = """
book book=Genesis
  chapter chapter=1
    verse verse=1
      sentence
% order is not important!
        word nu=sg
        word nu=pl
"""

Note that you can have comments in a search template. Comment lines start with a %.

In [16]:
results = A.search(query)
  1.03s 6 results

The book, chapter, verse columns are completely uninformative, so:

In [17]:
A.displaySetup(skipCols="1 2 3")
In [18]:
A.table(results, withPassage=True)
npsentencewordword
1Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ רֵאשִׁ֖ית אֱלֹהִ֑ים
2Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ רֵאשִׁ֖ית שָּׁמַ֖יִם
3Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ בָּרָ֣א אֱלֹהִ֑ים
4Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ בָּרָ֣א שָּׁמַ֖יִם
5Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ אָֽרֶץ׃ אֱלֹהִ֑ים
6Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ אָֽרֶץ׃ שָּׁמַ֖יִם

There are two plural and three singular words in Genesis 1:1. Search templates do not specify order, so all six combinations qualify as results.

Let's expand the results display:

In [19]:
A.show(results)

result 1

verse
book=Genesischapter=1verse=1

result 2

verse
book=Genesischapter=1verse=1

result 3

verse
book=Genesischapter=1verse=1

result 4

verse
book=Genesischapter=1verse=1

result 5

verse
book=Genesischapter=1verse=1

result 6

verse
book=Genesischapter=1verse=1

As you see, the results are listed per result tuple, even if they occur all in the same verse. This way you can keep track of what exactly belongs to each result.

Now in condensed mode:

In [20]:
A.show(results, condensed=True)

verse 1

verse
book=Genesischapter=1verse=1

Here we have all words of all results in one display. But we cannot see that each results has two words, let alone which ones.

Custom highlighting

Note that we can apply different highlight colors to different parts of the result. The words in the pair are member 5 and 6 of the result tuples. The members that we do not map, will not be highlighted. The members that we map to the empty string will be highlighted with the default color.

NB: Choose your colors from the CSS specification.

In [21]:
A.show(results, condensed=False, colorMap={1: "", 2: "cyan", 3: "magenta"})

result 1

verse
book=Genesischapter=1verse=1

result 2

verse
book=Genesischapter=1verse=1

result 3

verse
book=Genesischapter=1verse=1

result 4

verse
book=Genesischapter=1verse=1

result 5

verse
book=Genesischapter=1verse=1

result 6

verse
book=Genesischapter=1verse=1

Color mapping works best for uncondensed results. If you condense results, some nodes may occupy different positions in different results. It is unpredictable which color will be used for such nodes:

In [22]:
A.show(results, condensed=True, colorMap={1: "", 2: "cyan", 3: "magenta"})

verse 1

verse
book=Genesischapter=1verse=1

You can specify to what container you want to condense. By default, everything is condensed to verses.

Let's change that to phrases:

In [23]:
A.show(
    results,
    condensed=True,
    condenseType="phrase",
    colorMap={4: "", 5: "cyan", 6: "magenta"},
)

Constraining order

You can stipulate an order on the words in your template. You only have to put a relational operator between them. Say we want only results where the plural follows the singular.

In [24]:
query = """
book book=Genesis
  chapter chapter=1
    verse verse=1
      sentence
        word nu=sg
        < word nu=pl
"""

Note that we keep the skipCols="1 2 3" display setting in force, since it is relevant for this query as well.

In [25]:
results = A.search(query)
A.table(results)
  1.01s 4 results
npsentencewordword
1Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ רֵאשִׁ֖ית אֱלֹהִ֑ים
2Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ רֵאשִׁ֖ית שָּׁמַ֖יִם
3Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ בָּרָ֣א אֱלֹהִ֑ים
4Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ בָּרָ֣א שָּׁמַ֖יִם

We can also require the words to be adjacent.

In [26]:
query = """
book book=Genesis
  chapter chapter=1
    verse verse=1
      sentence
        word nu=sg
        <: word nu=pl
"""
In [27]:
results = A.search(query)
colorMap = {2: "lightsalmon", 3: "mediumaquamarine"}
A.table(results, colorMap=colorMap)
A.show(results, condensed=False, colorMap=colorMap)
  0.93s 1 result
npsentencewordword
1Genesis 1:1בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ׃ בָּרָ֣א אֱלֹהִ֑ים

result 1

verse
book=Genesischapter=1verse=1

Custom feature display

We would like to see the gender, number and person for words. The way to do that, is to perform a A.prettySetup(features) first.

In [28]:
A.displaySetup(
    extraFeatures="ps gn nu", colorMap={2: "lightsalmon", 3: "mediumaquamarine"}
)
In [29]:
A.show(results, condensed=False)

result 1

verse
book=Genesischapter=1verse=1
sentence

The features without meaningful values have been left out. We can also change that by passing a set of values we think are not meaningful. The default set is

{None, 'NA', 'none', 'unknown'}
In [30]:
A.displaySetup(noneValues=set())
A.show(results, condensed=False)

result 1

verse
book=Genesischapter=1gn=nu=ps=verse=1
sentence
book=chapter=gn=nu=ps=verse=
clause
book=chapter=gn=nu=ps=verse=
phrase
book=chapter=gn=nu=ps=verse=
book=chapter=gn=NAnu=NAps=NAverse=
book=chapter=gn=fnu=sgps=NAverse=
phrase
book=chapter=gn=nu=ps=verse=
book=chapter=gn=mnu=sgps=p3verse=
phrase
book=chapter=gn=nu=ps=verse=
book=chapter=gn=mnu=plps=NAverse=
phrase
book=chapter=gn=nu=ps=verse=
book=chapter=gn=NAnu=NAps=NAverse=
book=chapter=gn=NAnu=NAps=NAverse=
book=chapter=gn=mnu=plps=NAverse=
book=chapter=gn=NAnu=NAps=NAverse=
book=chapter=gn=NAnu=NAps=NAverse=
book=chapter=gn=NAnu=NAps=NAverse=
book=chapter=gn=unknownnu=sgps=NAverse=

This makes clear that it is convenient to keep None in the noneValues:

In [31]:
A.displaySetup(noneValues={None})
A.show(results, condensed=False)

result 1

verse
book=Genesischapter=1verse=1
sentence
clause
phrase
gn=NAnu=NAps=NA
gn=fnu=sgps=NA
phrase
gn=mnu=sgps=p3
phrase
gn=mnu=plps=NA
phrase
gn=NAnu=NAps=NA
gn=NAnu=NAps=NA
gn=mnu=plps=NA
gn=NAnu=NAps=NA
gn=NAnu=NAps=NA
gn=NAnu=NAps=NA
gn=unknownnu=sgps=NA

We can even choose to suppress other values, e.g. the male gender values and the singular number values.

In [32]:
A.displaySetup(noneValues={None, "NA", "unknown", "none", "m", "sg"})
A.show(results, condensed=False)

result 1

verse
book=Genesischapter=1verse=1

In the rest of the notebook we stick to our normal setup, so we reset the extra features.

In [33]:
A.displayReset("extraFeatures")
A.show(results, condensed=False)

result 1

Now we completely reset the display customization.

In [34]:
A.displayReset()

Show your own tuples

So far we have show()n the results of searches. But you can also construct your own tuples and show them.

Whereas you can use search to get a pretty good approximation of what you want, most of the times you do not arrive precisely at your destination.

Here is an example where we use search to come close, and then work our way to produce the end result.

Disagreement in number

We look for clauses with a one-word subject that does not agree in number with its predicate.

In our search templates we cannot formulate that a feature has different values on two nodes in the template. We could spell out all possible combinations of values and make a search template for each of them, but that is needlessly complex.

Let's first use search to find all clauses containing a one word subject and a predicate. And, to narrow down it further, we require that the word in the subject and the verb in the predicate are marked for number.

(You may want to consult the feature docs, see the link at the start of the notebook, where Bhsa() is called).

Note that the order of the phrases does not matter.

In [35]:
query = """
clause
    phrase function=Subj
        =: word nu=sg|pl
        :=
    phrase function=Pred|PreO
        word sp=verb
             nu=sg|pl
"""
results = A.search(query)
  2.07s 10638 results

Now the hand coding begins. We are going to extract the tuples we want.

In [36]:
wantedResults = tuple(
    (subj, pred)
    for (clause, phraseS, subj, phraseV, pred) in results
    if F.nu.v(subj) != F.nu.v(pred)
)
print(f"{len(wantedResults)} filtered results")
467 filtered results

And now we can show them:

In [37]:
wantedResults[0:4]
Out[37]:
((4, 3), (34, 33), (42, 41), (50, 49))
In [38]:
A.table(
    wantedResults, start=1, end=4, colorMap={1: "lightsalmon", 2: "mediumaquamarine"}
)
npwordword
1Genesis 1:1אֱלֹהִ֑ים בָּרָ֣א
2Genesis 1:3אֱלֹהִ֖ים יֹּ֥אמֶר
3Genesis 1:4אֱלֹהִ֛ים יַּ֧רְא
4Genesis 1:4אֱלֹהִ֔ים יַּבְדֵּ֣ל
In [39]:
A.show(
    wantedResults, start=1, end=4, colorMap={1: "lightsalmon", 2: "mediumaquamarine"}
)

result 1

verse
sentence
clause
phrase
function=Time
sp=prep
phrase
function=Pred
nu=sgsp=verb
phrase
function=Subj
phrase
function=Objc
sp=prep
sp=art
sp=conj
sp=prep
sp=art
nu=sgsp=subs

result 2

verse
sentence
clause
phrase
function=Conj
sp=conj
phrase
function=Pred
nu=sgsp=verb
phrase
function=Subj
sentence
clause
phrase
function=Pred
nu=sgsp=verb
phrase
function=Subj
nu=sgsp=subs
sentence
clause
phrase
function=Conj
sp=conj
phrase
function=Pred
nu=sgsp=verb
phrase
function=Subj
nu=sgsp=subs

result 3

verse
sentence
clause
phrase
function=Conj
sp=conj
phrase
function=Pred
nu=sgsp=verb
phrase
function=Subj
phrase
function=Objc
sp=prep
sp=art
nu=sgsp=subs
clause
phrase
function=Conj
sp=conj
phrase
function=Pred
nu=sgsp=verb
sentence
clause
phrase
function=Conj
sp=conj
phrase
function=Pred
phrase
function=Subj
phrase
function=Cmpl
nu=sgsp=subs
sp=art
nu=sgsp=subs
sp=conj
nu=sgsp=subs
sp=art

result 4

verse
sentence
clause
phrase
function=Conj
sp=conj
phrase
function=Pred
nu=sgsp=verb
phrase
function=Subj
phrase
function=Objc
sp=prep
sp=art
nu=sgsp=subs
clause
phrase
function=Conj
sp=conj
phrase
function=Pred
nu=sgsp=verb
sentence
clause
phrase
function=Conj
sp=conj
phrase
function=Pred
phrase
function=Subj
phrase
function=Cmpl
nu=sgsp=subs
sp=art
nu=sgsp=subs
sp=conj
nu=sgsp=subs
sp=art

Now suppose that we want to highlight the non-qal verb forms with a different color.

We have to assing colors to the members of our tuples:

In [40]:
highlights = {}
for (subj, pred) in wantedResults:
    highlights[subj] = "lightsalmon"
    highlights[pred] = "mediumaquamarine" if F.vs.v(pred) == "qal" else "yellow"

Now we can call show with the highlights parameter instead of the colorMap parameter.

In [41]:
A.table(wantedResults, start=1, end=4, highlights=highlights)
npwordword
1Genesis 1:1אֱלֹהִ֑ים בָּרָ֣א
2Genesis 1:3אֱלֹהִ֖ים יֹּ֥אמֶר
3Genesis 1:4אֱלֹהִ֛ים יַּ֧רְא
4Genesis 1:4אֱלֹהִ֔ים יַּבְדֵּ֣ל

Or in condensed pretty display:

In [42]:
A.show(
    wantedResults,
    condensed=True,
    start=3,
    end=3,
    highlights=highlights,
    extraFeatures="vs",
    withNodes=True,
)

verse 3

verse:1414392
sentence:1172315
clause:427566
phrase:651596
function=Conj
40 וַ
sp=conj
phrase:651597
function=Pred
nu=sgsp=verbvs=qal
phrase:651598
function=Subj
nu=plsp=subs
phrase:651599
function=Objc
sp=prep
44 הָ
sp=art
nu=sgsp=subs
clause:427567
phrase:651600
function=Conj
sp=conj
phrase:651601
function=Pred
nu=sgsp=verbvs=qal
sentence:1172316
clause:427568
phrase:651602
function=Conj
48 וַ
sp=conj
phrase:651603
function=Pred
nu=sgsp=verbvs=hif
phrase:651604
function=Subj
nu=plsp=subs
phrase:651605
function=Cmpl
nu=sgsp=subs
52 הָ
sp=art
nu=sgsp=subs
54 וּ
sp=conj
nu=sgsp=subs
56 הַ
sp=art
nu=sgsp=subs

As you see, you have total control.

All steps

  • start your first step in mastering the bible computationally
  • display become an expert in creating pretty displays of your text structures
  • search turbo charge your hand-coding with search templates

You know how to run queries and show off with their results.

The next thing is to dive deeper into the power of templates:

advanced sets relations quantifiers fromMQL rough gaps


  • exportExcel make tailor-made spreadsheets out of your results
  • share draw in other people's data and let them use yours
  • export export your dataset as an Emdros database
  • annotate annotate plain text by means of other tools and import the annotations as TF features
  • volumes work with selected books only
  • trees work with the BHSA data as syntax trees

CC-BY Dirk Roorda