%load_ext autoreload
%autoreload 2
from IPython.display import display, Markdown
from tf.app import use
A = use("Nino-cunei/uruk",hoist=globals())
Locating corpus resources ...
Name | # of nodes | # slots/node | % coverage |
---|---|---|---|
tablet | 6364 | 22.01 | 100 |
face | 9456 | 14.10 | 95 |
column | 14023 | 9.34 | 93 |
line | 35842 | 3.61 | 92 |
case | 9651 | 3.46 | 24 |
cluster | 32753 | 1.03 | 24 |
quad | 3794 | 2.05 | 6 |
comment | 11090 | 1.00 | 8 |
sign | 140094 | 1.00 | 100 |
3
Nino-cunei/uruk
/Users/me/text-fabric-data/github/Nino-cunei/uruk/app
7da6cb7cd9dffb12aff5e35639078029727a90e7
.contnr.cluster {
flex-flow: row wrap;
border: 0;
}
.meta .features {
background-color: #ffeedd;
}
.lbl.clusterb,.lbl.clustere {
padding: 0.5em 0.1em 0.1em 0.1em;
margin: 0.8em 0.1em 0.1em 0.1em;
color: #888844;
font-size: x-small;
}
.lbl.clusterb {
border-left: 0.3em solid #cccc99;
border-right: 0;
border-top: 0;
border-bottom: 0;
border-radius: 1rem;
}
.lbl.clustere {
border-left: 0;
border-right: 0.3em solid #cccc99;
border-top: 0;
border-bottom: 0;
border-radius: 1rem;
}
.op {
padding: 0.5em 0.1em 0.1em 0.1em;
margin: 0.8em 0.1em 0.1em 0.1em;
font-family: monospace;
font-size: x-large;
font-weight: bold;
}
.period {
font-family: monospace;
font-size: medium;
font-weight: bold;
color: #0000bb;
}
.excavation {
font-family: monospace;
font-size: medium;
font-style: italic;
color: #779900;
}
True
1
True
about
{docBase}/transcription{docExt}
''
0
True
True
True
local
/Users/me/text-fabric-data/github/Nino-cunei/uruk/_temp
Uruk IV/III: Proto-cuneiform tablets
10.5281/zenodo.1193841
sources/cdli/images
Nino-cunei
/tf
uruk
1.0
https://cdli.ucla.edu
to CDLI main page for this tablet
{webBase}/search/search_results.php?SearchMode=Text&ObjectID=<1>
cluster
comment
quad
sign
hor
{number}{prime}
2
srcLnNum
0
{number}{prime}
prime
}0
cluster
quad
sign
{type}
0
{type}
ctype
}comment
line
ver
True
{number}{prime}
3
srcLnNum
prime
}True
text
{type}
srcLnNum
column
comment
identifier fragment
hor
True
{type}
srcLnNum
0
{type}
0
case
cluster
comment
quad
sign
hor
{number}
2
srcLnNum
0
prime
}0
cluster
quad
sign
True
0
True
True
{atf}
atf
}comment
face
True
name period excavation
ver
True
srcLnNum
0
0
We want to find all the ShinPP numerals.
shinPP = dict(
N41=0.2,
N04=1,
N19=6,
N46=60,
N36=180,
N49=1800,
)
shinPPPat = "|".join(shinPP)
We make use of the fact that we can construct a search template programmatically.
query = f"""
tablet
sign grapheme={shinPPPat}
"""
print(query)
results = A.search(query)
A.table(results, end=20, showGraphics=True)
tablet sign grapheme=N41|N04|N19|N46|N36|N49 0.07s 1018 results
n | p | tablet | sign |
---|---|---|---|
1 | P448701 obverse:1:1 | P448701 | 1(N46) |
2 | P448701 obverse:1:1 | P448701 | 2(N19) |
3 | P448701 obverse:1:1 | P448701 | 4(N41) |
4 | P006005 obverse:2:1 | P006005 | 1(N04) |
5 | P002329 obverse:1:5 | P002329 | 2(N19) |
6 | P002342 obverse:3:2 | P002342 | 1(N36) |
7 | P002342 obverse:3:2 | P002342 | 2(N19) |
8 | P002344 obverse:3:3 | P002344 | 1(N04) |
9 | P002398 obverse:2:3 | P002398 | 1(N04) |
10 | P002622 obverse:1:1 | P002622 | 5(N19) |
11 | P002622 obverse:2:1 | P002622 | 1(N46) |
12 | P002622 obverse:2:1 | P002622 | 4(N19) |
13 | P002626 obverse:1:2 | P002626 | 1(N41) |
14 | P003330 reverse:1:1 | P003330 | 3(N46) |
15 | P003330 reverse:1:1 | P003330 | 2(N49) |
16 | P003330 reverse:1:1 | P003330 | 5(N19) |
17 | P003330 reverse:1:1 | P003330 | 2(N04) |
18 | P003330 reverse:1:1 | P003330 | 1(N41) |
19 | P003357 obverse:1:2 | P003357 | 1(N04) |
20 | P003542 obverse:2:5 | P003542 | 1(N04) |
Let's see a few tablets in more detail:
A.show(results, end=5, queryFeatures=False)
result 1
result 2
result 3
result 4
result 5
Rather than displaying search results, you can also process them in your program.
Search results come as tuples of nodes that correspond directly to the elements of your search template.
We query for shinPP numerals on the faces of tablets.
The result of the query is a list of tuples (t, f, s)
consisting of
a tablet node, a face node and a node for a sign of a shinPP numeral.
This task will require a higher level of programming skills and a deeper knowledge of how Python works. We include it in this tutorial to get the message across that Text-Fabric is not a black box that shields you from your data. Everything you handle in Text-Fabric is open to further programming and processing of your own design and choosing.
query = f"""
tablet
face
sign type=numeral grapheme={shinPPPat}
"""
results = A.search(query)
0.08s 1018 results
We are going to put all these numerals in buckets: for each face on each tablet a separate bucket.
numerals = {}
pNums = {}
for (tablet, face, sign) in results:
pNums[F.catalogId.v(tablet)] = tablet
numerals.setdefault(tablet, {}).setdefault(face, []).append(sign)
print(f"{len(pNums)} tablets")
print("\n".join(list(pNums)[0:10]))
print("...")
235 tablets P448701 P006005 P002329 P002342 P002344 P002398 P002622 P002626 P003330 P003357 ...
We define a function that given a tablet, adds the shinPP numerals by its faces. We also show the line art and a pretty transcription.
The function is a bit involved.
# we generate Markdown strings and send them to the notebook formatter
def dm(x):
display(Markdown(x))
def calcTablet(pNum): # pNum identifies the tablet in question
# show a horizontal line in Markdown
dm("---\n")
tablet = pNums.get(pNum, None) # look up the node for this p-number
if tablet is None:
dm(f"**no results for {pNum}**")
return # if not found the tablet has no ShinPP numerals: quit
A.lineart(tablet, withCaption="top", width="200") # show lineart
faces = numerals[tablet] # get the buckets for the faces
mySigns = []
for (face, signs) in faces.items(): # work per face
mySigns.extend(signs)
dm(f"### {F.type.v(face)}") # show the name of the face
distinctSigns = {} # collect the distinct numerals
for s in signs:
distinctSigns.setdefault(A.atfFromSign(s), []).append(s)
A.lineart(distinctSigns) # display the list of signs
total = 0 # start adding up
for (signAtf, signs) in distinctSigns.items():
value = 0
for s in signs:
value += F.repeat.v(s) * shinPP[F.grapheme.v(s)]
total += value
amount = len(signs) # we report our calculation
shinPPval = shinPP[F.grapheme.v(signs[0])]
repeat = F.repeat.v(signs[0])
print(f"{amount} x {signAtf} = {amount} x {repeat} x {shinPPval} = {value}")
dm(f"**total** = **{total}**")
A.prettyTuple(
[tablet] + mySigns, 1, queryFeatures=False
) # show pretty transcription
calcTablet("P006377")
1 x 1(N46) = 1 x 1 x 60 = 60 1 x 5(N19) = 1 x 5 x 6 = 30 4 x 3(N04) = 4 x 3 x 1 = 12 2 x 1(N41) = 2 x 1 x 0.2 = 0.4 8 x 1(N19) = 8 x 1 x 6 = 48 2 x 3(N19) = 2 x 3 x 6 = 36 5 x 1(N04) = 5 x 1 x 1 = 5 3 x 2(N04) = 3 x 2 x 1 = 6 3 x 2(N19) = 3 x 2 x 6 = 36 1 x 2(N41) = 1 x 2 x 0.2 = 0.4 2 x 4(N04) = 2 x 4 x 1 = 8 1 x 3(N41) = 1 x 3 x 0.2 = 0.6000000000000001 1 x 4(N19) = 1 x 4 x 6 = 24
total = 266.4
1 x 1(N36) = 1 x 1 x 180 = 180 1 x 1(N46) = 1 x 1 x 60 = 60 1 x 8(N19) = 1 x 8 x 6 = 48 1 x 5(N04) = 1 x 5 x 1 = 5 1 x 3(N41) = 1 x 3 x 0.2 = 0.6000000000000001
total = 293.6
result 1
Now the first 5 tablets.
for tablet in sorted(pNums)[0:5]:
calcTablet(tablet)
1 x 1(N04) = 1 x 1 x 1 = 1
total = 1
result 1
2 x 1(N36) = 2 x 1 x 180 = 360
total = 360
1 x 3(N36) = 1 x 3 x 180 = 540
total = 540
result 1
1 x 5(N36) = 1 x 5 x 180 = 900 4 x 1(N46) = 4 x 1 x 60 = 240 2 x 1(N36) = 2 x 1 x 180 = 360 1 x 2(N46) = 1 x 2 x 60 = 120 1 x 1(N04) = 1 x 1 x 1 = 1 1 x 1(N19) = 1 x 1 x 6 = 6 2 x 2(N36) = 2 x 2 x 180 = 720 1 x 2(N19) = 1 x 2 x 6 = 12
total = 2359
result 1
1 x 1(N04) = 1 x 1 x 1 = 1
total = 1
result 1
1 x 1(N36) = 1 x 1 x 180 = 180
total = 180
result 1
The capabilities of search are endless. Often it is the quickest way to focus on a phenomenon, quicker than hand coding all the logic to retrieve your patterns.
That said, it is not a matter of either-or. You can use coding to craft your templates, and you can use coding to process your results.
It's an explosive mix. A later chapter in this tutorial shows even more cases.
Have another look at the manual.