1.0 Building a Database of Ascher Summands with Figure 8 Knots
Aware that there is a potential relationship between Figure-8-knots and Ascher Sums, itâs time to build dataframes of potential correspondences. Two dataframes are created:
A Sums-and-Figure-8-Knots Dataframe showing Sum Information for all pendant ascher sums, augmented with information about figure-eight-knot cords in the summand ranges.
A Left-Handed and Right Handed Eight-Knot-Sum-Summary âcontingency tableâ of sorts, which summarizes the above table by khipu.
2.0 Building the Augmented Sums-and-Eight-Knot Dataframe
2.1 Fields of the Augmented Sums-and-Eight-Knot Dataframe
First we build a database of sum/summands by concatenating the data frames for pendant-pendant-sums, colored-pendant-sums, and indexed-pendant sums, ignoring other Ascher sums due to the paucity of occurence. This database, known in the code below as the pendant_ascher_sums_df consists of the following information:
KFG Name/Sum Type
kfg_name - The Khipu Field Guide Name
sum_type - Is it a âpendant-pendant-sumâ, âcolored-pendant-sumâ, or âindexed-pendant-sumâ
Sum Cord
cord_name - The Ascher sum cord name
cord_index - The sum cordâs group/cord index
cord_value - The sum cordâs value
cord_color - The Sum Cordâs color
Summands
handedness - Is it a left-handed (<0) or right-handed (>= 0) sum?
num_summands - How many pendant cord summands in the summand range
summand_string - An internal representation for computing use
Figure-8-Knot Information
has_figure8knot_indicator - Is there a figure-8-knot âindicatorâ for the summand range. What is an indicator? For now, an indicator is defined as having a left-edge (the first/left pendant cord in a summand range) that is marked by a figure-8-knot card, or a right-edge (the last/right pendant cord in a summand range) that is marked by a figure-8-knot card. A summand edge cord is marked if it has one or more of the following conditions:
The edge cord has a subsidiary that is an eight-knot-cord
Each edge cord has a left (or right) neighbor, bordering the summand range. i.e. if the summand range is p31 to p37 then p30 is the left neighbor and p38 is the right neighbor. If it has a pendant neighbor, does that neighbor, or itâs subsidiaries have an eight-knot cord.
For each sum/summand range, these conditions are tagged in the database as:
has_left_exact_8knot_cord - a boolean
has_right_exact_8knot_cord - a boolean
has_left_close_8knot_cord - a boolean
has_right_close_8knot_cord - a boolean
left_exact_pendant_8knot_cord_name - the pendant cordname if it matches condition
right_exact_pendant_8knot_cord_name - the pendant cordname if it matches condition
left_exact_subsidiary_8knot_cord_names - the cordnames if they match condition
right_exact_subsidiary_8knot_cord_names - the cordname if they match condition
left_close_pendant_cord_names - the left neighborâs pendant cordname if it matches condition
right_close_pendant_cord_names - the right neighborâs pendant cordname if it matches condition
left_close_subsidiary_8knot_cord_names - the cordname if they match condition
right_close_subsidiary_8knot_cord_names - the cordname if they match condition
has_parity_bit
Finally there is a parity bit flag. This requires greater explanation and will be discussed in the parity bit section
Code
```{python}import osimport numpy as npfrom scipy import statsimport pandas as pdfrom pandas import Series, DataFramefrom collections import Counterimport qollqa_chuspa as qc # A Khipu Maker is known (in Quechua) as a Khipu Kamayuqimport utils_loom as uloomimport utils_khipu as ukhipuimport utils_pandas as upandaimport utils_kfg_locations as uloc# Plotlyimport plotlyfrom plotly.offline import iplot, init_notebook_modeimport plotly.graph_objects as goimport plotly.express as pximport plotly.figure_factory as ffplotly.offline.init_notebook_mode(connected = False)# Load all khipus(khipu_dict, all_khipus) = qc.fetch_khipus()KFG_Names = ukhipu.kfg_order(khipu_dict.keys())khipu_cords_dict = {KFG_Name: khipu_dict[KFG_Name].all_cords(include_bottom_cords=True, include_top_cords=True, include_subsidiaries=True) for KFG_Name in KFG_Names}total_num_khipu_cords = sum([len(khipu_cords_dict[KFG_Name]) for KFG_Name in KFG_Names])```
2.2 Building the Augmented Sums-and-Eight-Knot Dataframe
Why only choose pendant-pendant-sums, indexed-pendant-sums and colored-pendant-sums?
It may be useful to recount the number of all pendant ascher sums of the three various types (pendant-pendant-sums, colored-pendant-sums, and indexed-pendant-sums)
58% (411 of 711) khipus have pendant_pendant_sums
29% (204 of 711) khipus have indexed_pendant_sums
39% (278 of 711) khipus have colored_pendant_sums
21% (149 of 711) khipus have subsidiary_pendant_sums
Only the first three sum relations are chosen. We can then concatenate those resulting dataframes together:
Code
```{python}# Build Concatenated DataFrames for all pendant Ascher Sumspendant_ascher_sums_df = pd.concat([pendant_pendant_sums_df.copy(deep=True), indexed_pendant_sums_df.copy(deep=True), colored_pendant_sums_df.copy(deep=True)])pendant_ascher_sums_df['sum_type'] = ['pendant_pendant_sum']*len(pendant_pendant_sums_df) + ['indexed_pendant_sum']*len(indexed_pendant_sums_df) + ['colored_pendant_sum']*len(colored_pendant_sums_df)pendant_ascher_sums_df.fillna('', inplace=True) pendant_ascher_sums_df.head()```
Generated Pandas2HTML HTML table: file:///Users/ashokkhosla/Desktop/LOOM/khipufieldguide/notebook/fieldmarks/analyses/database/figure8knotsums.html
2.3 Viewing the Augmented Sums-and-Eight-Knot Dataframe
The Sums-and-Eight-Knots Dataframe can be viewed here showing Sum Information for all pendant ascher sums, augmented with information about figure-eight-knot cords in the summand ranges.
3.0 Building the Eight-Knot-Sum-Summary
3.1 Fields of the Eight-Knot Sum-Summary Dataframe
Once a detailed, sum-by-sum inventory has been done, a summary contigency table, by khipu can be built. Here called eight_knot_sums_df which has the following âfrequency countâ information by khipu.
KFG Name Index
kfg_name
Sum Information
num_ascher_sums
num_pps_sums
num_cps_sums
num_ips_sums
Summary Frequency Counts of Eight-Knot Cord Markings
total_8knot_cords - the total number of the khipuâs figure-8-knot cords (including subsidiaries), regardless of what or how they are marked.
total_sum8knots - the sum of total_exact_sole8knots + total_close_sole8knots + total_exact_trailing8knots + total_close_sole8knots
total_sole8knots - the number of summand-figure-8-knot marker cords that are sole-8-knots
total_trailing8knots - the number of summand-figure-8-knot marker cords that are trailing-8-knots
total_exact_sole8knots - the number of pendant or subsidiary summand-figure-8-knot marker cords that are sole-8-knots
total_exact_trailing8knots - the number of pendant or subsidiary summand-figure-8-knot marker cords that are trailing-8-knots
total_close_sole8knots - the number of neigboring pendant or subsidiary summand-figure-8-knot marker cords that are trailing-8-knots
total_close_trailing8knots - the number of neigboring pendant or subsidiary summand-figure-8-knot marker cords that are trailing-8-knots
Detailed Frequency Counts of Eight-Knot Cord Markings
```{python}class EightKnotSummaryViewer(Pandas2HTML): def default_type_is_number(self, column_name): start_adjectives = ["index", "total", "right", "left"] end_adjectives = ["index"] return (any([column_name.lower().startswith(x) for x in start_adjectives]) or any([column_name.lower().endswith(x) for x in end_adjectives])) def default_type_is_bar(self, column_name): return False def default_label(self, column_name): the_label = super().default_label(column_name) is_frequency_count = (column_name.startswith("left") or column_name.startswith("right")) if is_frequency_count: the_label = "# " + the_label.strip() + "s" return the_labelcolumn_specs = {}file_specs = { "output_dir":f"{uloc.fieldmark_staging_dir()}/analyses/database", "basename":"left_handed_eightknotsumsummary" } page_specs = { "title":"Left-Handed Figure-8 Knot Sum Summary", "description":"Left-Handed Summary Frequency Counts for Khipus whose Ascher Summand Ranges are Marked by Cords W/Figure-8 Knot", }left_handed_eight_knot_types_df.fillna('', inplace=True)EightKnotSummaryViewer(file_specs, page_specs, column_specs, from_df=left_handed_eight_knot_types_df).make_pandas_html(show_html=False);file_specs = { "output_dir":f"{uloc.fieldmark_staging_dir()}/analyses/database", "basename":"right_handed_eightknotsumsummary" } page_specs = { "title":"Right-Handed Figure-8 Knot Sum Summary", "description":"Right-Handed Summary Frequency Counts for Khipus whose Ascher Summand Ranges are Marked by Cords W/Figure-8 Knot", }right_handed_eight_knot_types_df.fillna('', inplace=True)EightKnotSummaryViewer(file_specs, page_specs, column_specs, from_df=right_handed_eight_knot_types_df).make_pandas_html(show_html=False);file_specs = { "output_dir":f"{uloc.fieldmark_staging_dir()}/analyses/database", "basename":"eightknotsumsummary" } page_specs = { "title":"Figure-8 Knot Sum Summary", "description":"Ascher Sum Summary Frequency Counts for Khipus whose Ascher Summand Ranges are Marked by Cords W/Figure-8 Knot", }all_eight_knot_types_df.fillna('', inplace=True)EightKnotSummaryViewer(file_specs, page_specs, column_specs, from_df=all_eight_knot_types_df).make_pandas_html(show_html=False);```
Generated Pandas2HTML HTML table: file:///Users/ashokkhosla/Desktop/LOOM/khipufieldguide/notebook/fieldmarks/analyses/database/left_handed_eightknotsumsummary.html
Generated Pandas2HTML HTML table: file:///Users/ashokkhosla/Desktop/LOOM/khipufieldguide/notebook/fieldmarks/analyses/database/right_handed_eightknotsumsummary.html
Generated Pandas2HTML HTML table: file:///Users/ashokkhosla/Desktop/LOOM/khipufieldguide/notebook/fieldmarks/analyses/database/eightknotsumsummary.html
```{python}from utils_khipu import pct_kfg_khipusdo_make_khipus_by_8knot_type_sankey_diagram = True# Provide data for Khipu Sums by % of Figure-8-Knot Marker Type # source=c("All Khipus", "All Khipus", # "(78%) W/Pendant Sums", "(78%) W/Pendant Sums", # "(77%) With 8Knot Pendant Sum Markers", "(77%) With 8Knot Pendant Sum Markers", "(77%) With 8Knot Pendant Sum Markers"),# target=c("(78%) With Pendant Sums", "(22%) With Out Pendant Sums", # "(77%) With 8Knot Pendant Sum Markers", "(23%) With Out 8Knot Pendant Sums Markers",# "(16%) Only Left-Handed 8Knot Pendant Sums","(64%) Left AND Right-Handed 8Knot Pendant Sums", "(20%) Only Right-Handed 8Knot Pendant Sums"),# value=c(416, 664-416, 320, 416-320, 52, 204, 64)if do_make_khipus_by_8knot_type_sankey_diagram: def has_left_handed_8knot_pendant_sums(aKFGName): aDF = all_eight_knot_types_df[all_eight_knot_types_df['kfg_name'] == aKFGName] has_left_handed_8knot_pendant_sum = ( (len(aDF[aDF['left_exact_pendant_8knot_cord_type_sole8knot'] > 0]) > 0) or (len(aDF[aDF['left_exact_pendant_8knot_cord_type_trailing8knot'] > 0]) > 0) or (len(aDF[aDF['left_exact_subsidiary_8knot_cord_type_sole8knot'] > 0]) > 0) or (len(aDF[aDF['left_exact_subsidiary_8knot_cord_type_trailing8knot'] > 0]) > 0) or (len(aDF[aDF['left_close_pendant_8knot_cord_type_sole8knot'] > 0]) > 0) or (len(aDF[aDF['left_close_pendant_8knot_cord_type_trailing8knot'] > 0]) > 0) or (len(aDF[aDF['left_close_subsidiary_8knot_cord_type_sole8knot'] > 0]) > 0) or (len(aDF[aDF['left_close_subsidiary_8knot_cord_type_trailing8knot'] > 0]) > 0) ) return 1 if has_left_handed_8knot_pendant_sum else 0 def has_right_handed_8knot_pendant_sums(aKFGName): aDF = all_eight_knot_types_df[all_eight_knot_types_df['kfg_name'] == aKFGName] has_right_handed_8knot_pendant_sum = ( (len(aDF[aDF['right_exact_pendant_8knot_cord_type_sole8knot'] > 0]) > 0) or (len(aDF[aDF['right_exact_pendant_8knot_cord_type_trailing8knot'] > 0]) > 0) or (len(aDF[aDF['right_exact_subsidiary_8knot_cord_type_sole8knot'] > 0]) > 0) or (len(aDF[aDF['right_exact_subsidiary_8knot_cord_type_trailing8knot'] > 0]) > 0) or (len(aDF[aDF['right_close_pendant_8knot_cord_type_sole8knot'] > 0]) > 0) or (len(aDF[aDF['right_close_pendant_8knot_cord_type_trailing8knot'] > 0]) > 0) or (len(aDF[aDF['right_close_subsidiary_8knot_cord_type_sole8knot'] > 0]) > 0) or (len(aDF[aDF['right_close_subsidiary_8knot_cord_type_trailing8knot'] > 0]) > 0) ) return 1 if has_right_handed_8knot_pendant_sum else 0 def has_both_handed_8knot_trailing_sums(aKFGName): has_both_handed_8knot_trailing_sum = has_left_handed_8knot_pendant_sums(aKFGName) and has_right_handed_8knot_pendant_sums(aKFGName) return 1 if has_both_handed_8knot_trailing_sum else 0 num_all_khipus = len(all_khipus) # Determine the number of khipus with 8-knots num_khipus_with_all_pendant_sums = len(all_eight_knot_types_df[all_eight_knot_types_df['num_ascher_sums'] > 0]) num_khipus_without_pendant_sums = num_all_khipus - num_khipus_with_all_pendant_sums num_all_pendant_sums_with_8knot_markers = len(all_eight_knot_types_df[all_eight_knot_types_df['total_sum8knots'] > 0]) num_all_pendant_sums_without_8knot_markers = num_khipus_with_all_pendant_sums - num_all_pendant_sums_with_8knot_markers num_left_handed_8knot_pendant_sums = sum(has_left_handed_8knot_pendant_sums(kfg_name) and (not has_right_handed_8knot_pendant_sums(kfg_name)) for kfg_name in all_eight_knot_types_df['kfg_name']) num_right_handed_8knot_pendant_sums = sum(has_right_handed_8knot_pendant_sums(kfg_name) and (not has_left_handed_8knot_pendant_sums(kfg_name)) for kfg_name in all_eight_knot_types_df['kfg_name']) num_both_handed_8knot_pendant_sums = sum(has_both_handed_8knot_trailing_sums(kfg_name) for kfg_name in all_eight_knot_types_df['kfg_name']) sums_pct = round(100.0* num_khipus_with_all_pendant_sums / float(num_all_khipus)) sum_markers_pct = round(100.0* num_all_pendant_sums_with_8knot_markers / float(num_khipus_with_all_pendant_sums)) left_handed_sums_pct = round(100.0* num_left_handed_8knot_pendant_sums / float(num_all_pendant_sums_with_8knot_markers)) right_handed_sums_pct = round(100.0* num_right_handed_8knot_pendant_sums / float(num_all_pendant_sums_with_8knot_markers)) both_handed_sums_pct = round(100.0* num_both_handed_8knot_pendant_sums / float(num_all_pendant_sums_with_8knot_markers)) print(f"\tsource=c(\"All Khipus\", \"All Khipus\",") print(f"\t\t\"( {sums_pct}% ) W/Pendant Sum\", \"( {sums_pct}% ) W/Pendant Sum\", ") print(f"\t\t\"( {sum_markers_pct}% ) W/8Knot Pendant Sum Marker\", \"( {sum_markers_pct}% ) W/8Knot Pendant Sum Marker\", \"( {sum_markers_pct}% ) W/8Knot Pendant Sum Marker\"),") print(f"\ttarget=c(\"( {sums_pct}% ) W/Pendant Sums\", \"( {100-sums_pct}% ) W-Out/Pendant Sums\", ") print(f"\t\t\"( {sum_markers_pct}% ) W/8Knot Pendant Sum Markers\", \"( {100-sum_markers_pct}% ) W-Out/8Knot Pendant Sums Markers\",") print(f"\t\t\"( {left_handed_sums_pct}% ) Only Left-Handed 8Knot Pendant Sums\", \"( {both_handed_sums_pct}% ) Left AND Right-Handed 8Knot Pendant Sums\", \"( {right_handed_sums_pct}% ) Only Right-Handed 8Knot Pendant Sums\"),") print(f"\tvalue=c({num_khipus_with_all_pendant_sums}, {num_all_khipus-num_khipus_with_all_pendant_sums}, {num_all_pendant_sums_with_8knot_markers}, {num_khipus_with_all_pendant_sums-num_all_pendant_sums_with_8knot_markers}, {num_left_handed_8knot_pendant_sums}, {num_both_handed_8knot_pendant_sums}, {num_right_handed_8knot_pendant_sums})")```
source=c("All Khipus", "All Khipus",
"( 61% ) W/Pendant Sum", "( 61% ) W/Pendant Sum",
"( 72% ) W/8Knot Pendant Sum Marker", "( 72% ) W/8Knot Pendant Sum Marker", "( 72% ) W/8Knot Pendant Sum Marker"),
target=c("( 61% ) W/Pendant Sums", "( 39% ) W-Out/Pendant Sums",
"( 72% ) W/8Knot Pendant Sum Markers", "( 28% ) W-Out/8Knot Pendant Sums Markers",
"( 12% ) Only Left-Handed 8Knot Pendant Sums", "( 82% ) Left AND Right-Handed 8Knot Pendant Sums", "( 13% ) Only Right-Handed 8Knot Pendant Sums"),
value=c(434, 277, 313, 121, 39, 256, 40)
3.2 Viewers for Left-Handed and Right-Handed Eight Knot Ascher Sum Summaries
Viewers are provided for the Left-Handed Eight-Knot Sum Summary âcontingency tableâ of sums marked by figure-8-knot cords and the corresponding Right Handed Eight-Knot Sum Summary.
3.3 Summary of Left-Handed and Right Handed Eight Knot Ascher Sum Types
3.3.1 Left-Handed Eight Knot Ascher Sums Summary
Summary of Left-Handed Eight Knot Ascher Sum Types
8-KNOT CORD TYPE
# 8Knot Cord Sum Markers
# Edge Matches
# Pendant Edge Matches
# Subsidiary Edge Matches
# Neighbor Matches
# Neighbor Pendant Matches
# Neighbor Subsidiary Matches
0
SOLE 8KNOT CORDS
59% (2346 of 3969)
56% (1312 of 2346)
66% (867 of 1312)
34% (445 of 1312)
44% (1034 of 2346)
59% (611 of 1034)
41% (423 of 1034)
1
TRAILING 8KNOT CORDS
41% (1623 of 3969)
56% (909 of 1623)
88% (796 of 909)
12% (113 of 909)
44% (714 of 1623)
84% (599 of 714)
16% (115 of 714)
3.3.2 Right-Handed Eight Knot Ascher Sums Summary
8-KNOT CORD TYPE
# 8Knot Cord Sum Markers
# Edge Matches
# Pendant Edge Matches
# Subsidiary Edge Matches
# Neighbor Matches
# Neighbor Pendant Matches
# Neighbor Subsidiary Matches
0
SOLE 8KNOT CORDS
58% (2997 of 5156)
54% (1613 of 2997)
58% (928 of 1613)
42% (685 of 1613)
46% (1384 of 2997)
51% (709 of 1384)
49% (675 of 1384)
1
TRAILING 8KNOT CORDS
42% (2159 of 5156)
51% (1107 of 2159)
86% (951 of 1107)
14% (156 of 1107)
49% (1052 of 2159)
83% (873 of 1052)
17% (179 of 1052)
4.0 Sankey Diagram of Figure-8-Knot Sum Cords by Type
Code
```{python}num_all_khipus = len(all_khipus)num_khipus_with_pendant_ascher_sums = pendant_ascher_sums_df['kfg_name'].nunique()only_eight_knot_ascher_sums_df = pendant_ascher_sums_df[pendant_ascher_sums_df['has_figure8knot_indicator']] num_khipus_with_figure8knot_pendant_ascher_sums = only_eight_knot_ascher_sums_df['kfg_name'].nunique()left_handed_8knotsum_khipus_df = only_eight_knot_ascher_sums_df[only_eight_knot_ascher_sums_df['handedness'] < 0]right_handed_8knotsum_khipus_df = only_eight_knot_ascher_sums_df[only_eight_knot_ascher_sums_df['handedness'] >= 0]num_left_handed_8knotsum_khipus = left_handed_8knotsum_khipus_df['kfg_name'].nunique()num_right_handed_8knotsum_khipus = right_handed_8knotsum_khipus_df['kfg_name'].nunique()left_handed_khipus = set(left_handed_8knotsum_khipus_df['kfg_name'])right_handed_khipus = set(right_handed_8knotsum_khipus_df['kfg_name'])num_left_only_8knotsum_khipus = len(left_handed_khipus - right_handed_khipus)num_left_and_right_8knotsum_khipus = len(left_handed_khipus.intersection(right_handed_khipus))num_right_only_8knotsum_khipus = len(right_handed_khipus - left_handed_khipus)do_print = Falseif do_print: print(f"# of Khipus: {num_all_khipus}") print(f"# of Khipus with All Pendant Ascher Sums: {num_khipus_with_pendant_ascher_sums}") print(f"# of Khipus with All Pendant Ascher Sums marked by Figure-8 Knots: {uloom.percent_info(num_khipus_with_figure8knot_pendant_ascher_sums, num_khipus_with_pendant_ascher_sums)}") print(f"# of Khipus with All Left-Handed Pendant Ascher Sums marked by Figure-8 Knots: {uloom.percent_info(num_left_handed_8knotsum_khipus, num_khipus_with_figure8knot_pendant_ascher_sums)}") print(f"# of Khipus with All Right-Handed Pendant Ascher Sums marked by Figure-8 Knots: {uloom.percent_info(num_right_handed_8knotsum_khipus, num_khipus_with_figure8knot_pendant_ascher_sums)}") print(f"# of Khipus with All Left-Only Pendant Ascher Sums marked by Figure-8 Knots: {uloom.percent_info(num_left_only_8knotsum_khipus, num_khipus_with_figure8knot_pendant_ascher_sums)}") print(f"# of Khipus with All Left & Right Pendant Ascher Sums marked by Figure-8 Knots: {uloom.percent_info(num_left_and_right_8knotsum_khipus, num_khipus_with_figure8knot_pendant_ascher_sums)}") print(f"# of Khipus with All Right-Only Pendant Ascher Sums marked by Figure-8 Knots: {uloom.percent_info(num_right_only_8knotsum_khipus, num_khipus_with_figure8knot_pendant_ascher_sums)}")```
Code
```{python}def has_sole_knot(aRow): return ((aRow['left_exact_pendant_8knot_cord_type'] == 'sole_8knot') or (aRow['right_exact_pendant_8knot_cord_type'] == 'sole_8knot') or (aRow['left_exact_subsidiary_8knot_cord_type'] == 'sole_8knot') or (aRow['right_exact_subsidiary_8knot_cord_type'] == 'sole_8knot') or (aRow['left_close_pendant_8knot_cord_type'] == 'sole_8knot') or (aRow['right_close_pendant_8knot_cord_type'] == 'sole_8knot') or (aRow['left_close_subsidiary_8knot_cord_type'] == 'sole_8knot') or (aRow['right_close_subsidiary_8knot_cord_type'] == 'sole_8knot'))def has_trailing_knot(aRow): return ((aRow['left_exact_pendant_8knot_cord_type'] == 'trailing_8knot') or (aRow['right_exact_pendant_8knot_cord_type'] == 'trailing_8knot') or (aRow['left_exact_subsidiary_8knot_cord_type'] == 'trailing_8knot') or (aRow['right_exact_subsidiary_8knot_cord_type'] == 'trailing_8knot') or (aRow['left_close_pendant_8knot_cord_type'] == 'trailing_8knot') or (aRow['right_close_pendant_8knot_cord_type'] == 'trailing_8knot') or (aRow['left_close_subsidiary_8knot_cord_type'] == 'trailing_8knot') or (aRow['right_close_subsidiary_8knot_cord_type'] == 'trailing_8knot'))def has_edge_match(aRow): return (aRow['has_left_exact_8knot_cord'] or aRow['has_right_exact_8knot_cord'])def has_close_match(aRow): return (aRow['has_left_close_8knot_cord'] or aRow['has_right_close_8knot_cord'])def has_pendant_edge_match(aRow): return has_edge_match(aRow) and ((len(aRow['left_exact_pendant_8knot_cord_name'])>0) or (len(aRow['right_exact_pendant_8knot_cord_name'])>0))def has_subsidiary_edge_match(aRow): return (has_edge_match(aRow) and not(has_pendant_edge_match(aRow)) and ((len(aRow['left_exact_subsidiary_8knot_cord_names'])>0) or (len(aRow['right_exact_subsidiary_8knot_cord_names'])>0)))def has_pendant_close_match(aRow): return (not (has_edge_match(aRow)) and has_close_match(aRow) and ((len(aRow['left_close_pendant_cord_names'])>0) or (len(aRow['right_close_pendant_cord_names'])>0)))def has_subsidiary_close_match(aRow): return (not (has_edge_match(aRow)) and has_close_match(aRow) and (not has_pendant_close_match(aRow)) and ((len(aRow['left_close_subsidiary_8knot_cord_names'])>0) or (len(aRow['right_close_subsidiary_8knot_cord_names'])>0)))# LEVEL 0num_fig8knot_ascher_sums = only_eight_knot_ascher_sums_df.shape[0]# LEVEL 1 - SOLE-8-KNOT, BOTH-8-KNOT, TRAILING-8-KNOTsole8knot_sum__mask = [has_sole_knot(row) for _, row in pendant_ascher_sums_df.iterrows()]trailing8knot_sum_mask = [has_trailing_knot(row) for _, row in pendant_ascher_sums_df.iterrows()]only_sole8knot_sum__mask = [(has_sole_knot(row) and (not has_trailing_knot(row))) for _, row in pendant_ascher_sums_df.iterrows()]both8knot_sum__mask = [(has_sole_knot(row) and has_trailing_knot(row)) for _, row in pendant_ascher_sums_df.iterrows()]only_trailing8knot_sum__mask = [((not has_sole_knot(row)) and has_trailing_knot(row)) for _, row in pendant_ascher_sums_df.iterrows()]only_sole8knot_sum_df = pendant_ascher_sums_df[only_sole8knot_sum__mask]both8knot_sum_df = pendant_ascher_sums_df[both8knot_sum__mask]only_trailing8knot_sum_df = pendant_ascher_sums_df[only_trailing8knot_sum__mask]num_only_sole8knot_ascher_sums = sum(only_sole8knot_sum__mask)num_both8knot_ascher_sums = sum(both8knot_sum__mask)num_only_trailing8knot_ascher_sums = sum(only_trailing8knot_sum__mask)# LEVEL 2 - EDGE vs CLOSE# 2.1edges_only_sole8knot_sum_mask = [has_edge_match(row) for _, row in only_sole8knot_sum_df.iterrows()] edges_only_sole8knot_sum_df = only_sole8knot_sum_df[edges_only_sole8knot_sum_mask]num_edges_only_sole8knot_sums = sum(edges_only_sole8knot_sum_mask)close_only_sole8knot_sum_mask = [((not has_edge_match(row)) and has_close_match(row)) for _, row in only_sole8knot_sum_df.iterrows()]close_only_sole8knot_sum_df = only_sole8knot_sum_df[close_only_sole8knot_sum_mask]num_close_only_sole8knot_sums = sum(close_only_sole8knot_sum_mask)# 2.2edges_both8knot_sum_mask = [has_edge_match(row) for _, row in both8knot_sum_df.iterrows()] edges_both8knot_sum_df = both8knot_sum_df[edges_both8knot_sum_mask]close_both8knot_sum_mask = [((not has_edge_match(row)) and has_close_match(row)) for _, row in both8knot_sum_df.iterrows()]close_both8knot_sum_df = both8knot_sum_df[close_both8knot_sum_mask]num_edges_both8knot_sums = sum(edges_both8knot_sum_mask)num_close_both8knot_sums = sum(close_both8knot_sum_mask)# 2.3edges_only_trailing8knot_sum_mask = [has_edge_match(row) for _, row in only_trailing8knot_sum_df.iterrows()] edges_only_trailing8knot_sum_df = only_trailing8knot_sum_df[edges_only_trailing8knot_sum_mask]close_only_trailing8knot_sum_mask = [((not has_edge_match(row)) and has_close_match(row)) for _, row in only_trailing8knot_sum_df.iterrows()]close_only_trailing8knot_sum_df = only_trailing8knot_sum_df[close_only_trailing8knot_sum_mask]num_edges_only_trailing8knot_edge_match_sums = sum(edges_only_trailing8knot_sum_mask)num_close_only_trailing8knot_edge_match_sums = sum(close_only_trailing8knot_sum_mask)# LEVEL 3# 3.1pendant_edges_only_sole8knot_sum_mask = [has_pendant_edge_match(row) for _, row in edges_only_sole8knot_sum_df.iterrows()] subsidiary_edges_only_sole8knot_sum_mask = [has_subsidiary_edge_match(row) for _, row in edges_only_sole8knot_sum_df.iterrows()] num_pendant_edges_only_sole8knot_sums = sum(pendant_edges_only_sole8knot_sum_mask)num_subsidiary_edges_only_sole8knot_sums = sum(subsidiary_edges_only_sole8knot_sum_mask)pendant_close_only_sole8knot_sum_mask = [has_pendant_close_match(row) for _, row in close_only_sole8knot_sum_df.iterrows()] num_pendant_close_only_sole8knot_sums = sum(pendant_close_only_sole8knot_sum_mask)subsidiary_close_only_sole8knot_sum_mask = [has_subsidiary_close_match(row) for _, row in close_only_sole8knot_sum_df.iterrows()]num_subsidiary_close_only_sole8knot_sums = sum(subsidiary_close_only_sole8knot_sum_mask)# 3.2pendant_edges_both8knot_sum_mask = [has_pendant_edge_match(row) for _, row in edges_both8knot_sum_df.iterrows()] subsidiary_edges_both8knot_sum_mask = [has_subsidiary_edge_match(row) for _, row in edges_both8knot_sum_df.iterrows()] num_pendant_edges_both8knot_sums = sum(pendant_edges_both8knot_sum_mask)num_subsidiary_edges_both8knot_sums = sum(subsidiary_edges_both8knot_sum_mask)pendant_close_both8knot_sum_mask = [has_pendant_close_match(row) for _, row in close_both8knot_sum_df.iterrows()] subsidiary_close_both8knot_sum_mask = [has_subsidiary_close_match(row) for _, row in close_both8knot_sum_df.iterrows()]num_pendant_close_both8knot_sums = sum(pendant_close_both8knot_sum_mask)num_subsidiary_close_both8knot_sums = sum(subsidiary_close_both8knot_sum_mask)# 3.3pendant_edges_only_trailing8knot_sum_mask = [has_pendant_edge_match(row) for _, row in edges_only_trailing8knot_sum_df.iterrows()]subsidiary_edges_only_trailing8knot_sum_mask = [has_subsidiary_edge_match(row) for _, row in edges_only_trailing8knot_sum_df.iterrows()]num_pendant_edges_only_trailing8knot_sums = sum(pendant_edges_only_trailing8knot_sum_mask)num_subsidiary_edges_only_trailing8knot_sums = sum(subsidiary_edges_only_trailing8knot_sum_mask)pendant_close_only_trailing8knot_sum_mask = [has_pendant_close_match(row) for _, row in close_only_trailing8knot_sum_df.iterrows()] subsidiary_close_only_trailing8knot_sum_mask = [has_subsidiary_close_match(row) for _, row in close_only_trailing8knot_sum_df.iterrows()]num_pendant_close_only_trailing8knot_sums = sum(pendant_close_only_trailing8knot_sum_mask)num_subsidiary_close_only_trailing8knot_sums = sum(subsidiary_close_only_trailing8knot_sum_mask)do_print = Trueif do_print: print(f"ALL Figure-8 Knot Pendant Sums: {num_fig8knot_ascher_sums}") print(f"# ONLY Sole-8-Knot Pendant Sums: {uloom.percent_info(num_only_sole8knot_ascher_sums, num_fig8knot_ascher_sums)}") print(f"\t# Sole-8-Knot Edge Match Pendant Sums: {uloom.percent_info(num_edges_only_sole8knot_sums, num_only_sole8knot_ascher_sums)}") print(f"\t\t# Pendant Sums: {uloom.percent_info(num_pendant_edges_only_sole8knot_sums, num_edges_only_sole8knot_sums)}") print(f"\t\t# Subsidiary Sums: {uloom.percent_info(num_subsidiary_edges_only_sole8knot_sums, num_edges_only_sole8knot_sums)}") print(f"\t# Sole-8-Knot Close Match Pendant Sums: {uloom.percent_info(num_close_only_sole8knot_sums, num_only_sole8knot_ascher_sums)}") print(f"\t\t# Pendant Sums: {uloom.percent_info(num_pendant_close_only_sole8knot_sums, num_close_only_sole8knot_sums)}") print(f"\t\t# Subsidiary Sums: {uloom.percent_info(num_subsidiary_close_only_sole8knot_sums, num_close_only_sole8knot_sums)}") print(f"# BOTH Sole-8-Knot and Trailing-8-Knot Pendant Sums: {uloom.percent_info(num_both8knot_ascher_sums, num_fig8knot_ascher_sums)}") print(f"\t# Both-8-Knot Edge Pendant Sums: {uloom.percent_info(num_edges_both8knot_sums, num_both8knot_ascher_sums)}") print(f"\t\t# Pendant Sums: {uloom.percent_info(num_pendant_edges_both8knot_sums, num_edges_both8knot_sums)}") print(f"\t\t# Subsidiary Sums: {uloom.percent_info(num_subsidiary_edges_both8knot_sums, num_edges_both8knot_sums)}") print(f"\t# Both-8-Knot Only Close Match Pendant Sums: {uloom.percent_info(num_close_both8knot_sums, num_both8knot_ascher_sums)}") print(f"\t\t# Pendant Sums: {uloom.percent_info(num_pendant_close_both8knot_sums, num_close_both8knot_sums)}") print(f"\t\t# Subsidiary Sums: {uloom.percent_info(num_subsidiary_close_both8knot_sums, num_close_both8knot_sums)}") print(f"# ONLY Trailing-8-Knot Pendant Pendant Sums: {uloom.percent_info(num_only_trailing8knot_ascher_sums, num_fig8knot_ascher_sums)}") print(f"\t# Trailing-8-Knot Edge Pendant Sums: {uloom.percent_info(num_edges_only_trailing8knot_edge_match_sums, num_only_trailing8knot_ascher_sums)}") print(f"\t\t# Pendant Sums: {uloom.percent_info(num_pendant_edges_only_trailing8knot_sums, num_edges_only_trailing8knot_edge_match_sums)}") print(f"\t\t# Subsidiary Sums: {uloom.percent_info(num_subsidiary_edges_only_trailing8knot_sums, num_edges_only_trailing8knot_edge_match_sums)}") print(f"\t# Trailing-8-Knot Only Close Pendant Ascher Sums: {uloom.percent_info(num_close_only_trailing8knot_edge_match_sums, num_only_trailing8knot_ascher_sums)}") print(f"\t\t# Pendant Sums: {uloom.percent_info(num_pendant_close_only_trailing8knot_sums, num_close_only_trailing8knot_edge_match_sums)}") print(f"\t\t# Subsidiary Sums: {uloom.percent_info(num_subsidiary_close_only_trailing8knot_sums, num_close_only_trailing8knot_edge_match_sums)}") print(f"# Other Eight-Knot Ascher Sums: {uloom.percent_info(num_fig8knot_ascher_sums - (num_only_sole8knot_ascher_sums + num_both8knot_ascher_sums + num_only_trailing8knot_ascher_sums), num_fig8knot_ascher_sums)}")```
ALL Figure-8 Knot Pendant Sums: 5751
# ONLY Sole-8-Knot Pendant Sums: 48% (2753 of 5751)
# Sole-8-Knot Edge Match Pendant Sums: 71% (1943 of 2753)
# Pendant Sums: 72% (1405 of 1943)
# Subsidiary Sums: 28% (538 of 1943)
# Sole-8-Knot Close Match Pendant Sums: 29% (810 of 2753)
# Pendant Sums: 62% (506 of 810)
# Subsidiary Sums: 38% (304 of 810)
# BOTH Sole-8-Knot and Trailing-8-Knot Pendant Sums: 13% (762 of 5751)
# Both-8-Knot Edge Pendant Sums: 88% (670 of 762)
# Pendant Sums: 76% (507 of 670)
# Subsidiary Sums: 24% (163 of 670)
# Both-8-Knot Only Close Match Pendant Sums: 12% (92 of 762)
# Pendant Sums: 89% (82 of 92)
# Subsidiary Sums: 11% (10 of 92)
# ONLY Trailing-8-Knot Pendant Pendant Sums: 38% (2181 of 5751)
# Trailing-8-Knot Edge Pendant Sums: 64% (1385 of 2181)
# Pendant Sums: 91% (1265 of 1385)
# Subsidiary Sums: 9% (120 of 1385)
# Trailing-8-Knot Only Close Pendant Ascher Sums: 36% (796 of 2181)
# Pendant Sums: 90% (719 of 796)
# Subsidiary Sums: 10% (77 of 796)
# Other Eight-Knot Ascher Sums: 1% (55 of 5751)
Code
```{python}# Code to generate R Sankey diagram source code# See src/R_src/figure8knot_sumcords_sankey_2.Rdo_make_sumcords_sankey_diagram = Falseif do_make_sumcords_sankey_diagram: n_T = num_fig8knot_ascher_sums n_A = num_only_sole8knot_ascher_sums n_B = num_both8knot_ascher_sums n_C = num_only_trailing8knot_ascher_sums n_D = num_fig8knot_ascher_sums - (num_only_sole8knot_ascher_sums + num_both8knot_ascher_sums + num_only_trailing8knot_ascher_sums) n_A1 = num_edges_only_sole8knot_sums n_A2 = num_close_only_sole8knot_sums n_A11 = num_pendant_edges_only_sole8knot_sums n_A12 = num_subsidiary_edges_only_sole8knot_sums n_A21 = num_pendant_close_only_sole8knot_sums n_A22 = num_subsidiary_close_only_sole8knot_sums n_B1 = num_edges_both8knot_sums n_B2 = num_close_both8knot_sums n_B11 = num_pendant_edges_both8knot_sums n_B12 = num_subsidiary_edges_both8knot_sums n_B21 = num_pendant_close_both8knot_sums n_B22 = num_subsidiary_close_both8knot_sums n_C1 = num_edges_only_trailing8knot_edge_match_sums n_C2 = num_close_only_trailing8knot_edge_match_sums n_C11 = num_pendant_edges_only_trailing8knot_sums n_C12 = num_subsidiary_edges_only_trailing8knot_sums n_C21 = num_pendant_close_only_trailing8knot_sums n_C22 = num_subsidiary_close_only_trailing8knot_sums def pct(n, d): return int(round(100.0 * float(n) / float(d), 0)) T = f"# of 8Knot Pendant Sums ( {n_T} )" A = f"( {pct(n_A, n_T)}% ) ONLY Sole-8-Knot Pendant Sums" B = f"( {pct(n_B, n_T)}% ) Sole AND Trailing-8-Knot Pendant Sums" C = f"( {pct(n_C, n_T)}% ) ONLY Trailing-8-Knot Pendant Sums" D = f"( {pct(n_D, n_T)}% ) Other 8-Knot Pendant Sums" A1 = f"( {pct(n_A1, n_A)}% ) ONLY Sole Edge 8Knot Markers" A2 = f"( {pct(n_A2, n_A)}% ) ONLY Sole Neighbor 8Knot Markers" A11 = f"( {pct(n_A11, n_A1)}% ) ONLY Sole-8-Knot Pendant Edge 8Knot Markers" A12 = f"( {pct(n_A12, n_A1)}% ) ONLY Sole-8-Knot Subsidiary Edge 8Knot Markers" A21 = f"( {pct(n_A21, n_A2)}% ) ONLY Sole-8-Knot Pendant Neighbor 8Knot Markers" A22 = f"( {pct(n_A22, n_A2)}% ) ONLY Sole-8-Knot Subsidiary Neighbor 8Knot Markers" B1 = f"( {pct(n_B1, n_B)}% ) Sole & Trailing Edge 8Knot Markers" B2 = f"( {pct(n_B2, n_B)}% ) Sole & Trailing Neighbor 8Knot Markers" B11 = f"( {pct(n_B11, n_B1)}% ) Sole & Trailing Pendant Edge 8Knot Markers" B12 = f"( {pct(n_B12, n_B1)}% ) Sole & Trailing Subsidiary Edge 8Knot Markers" B21 = f"( {pct(n_B21, n_B2)}% ) Sole & Trailing Pendant Neighbor 8Knot Markers" B22 = f"( {pct(n_B22, n_B2)}% ) Sole & Trailing Subsidiary Neighbor 8Knot Markers" C1 = f"( {pct(n_C1, n_C)}% ) ONLY Trailing Edge 8Knot Markers" C2 = f"( {pct(n_C2, n_C)}% ) ONLY Trailing Neighbor 8Knot Markers" C11 = f"( {pct(n_C11, n_C1)}% ) ONLY Trailing Pendant Edge 8Knot Markers" C12 = f"( {pct(n_C12, n_C1)}% ) ONLY Trailing Subsidiary Edge 8Knot Markers" C21 = f"( {pct(n_C21, n_C2)}% ) ONLY Trailing Pendant Neighbor 8Knot Markers" C22 = f"( {pct(n_C22, n_C2)}% ) ONLY Trailing Subsidiary Neighbor 8Knot Markers" print(f"\tsource = c(\"{T}\", \"{T}\", \"{T}\", \"{T}\",") print(f"\t\t\"{A}\", \"{A}\",") print(f"\t\t\"{A1}\", \"{A1}\", \"{A2}\", \"{A2}\",") print(f"\t\t\"{B}\", \"{B}\",") print(f"\t\t\"{B1}\", \"{B1}\", \"{B2}\", \"{B2}\",") print(f"\t\t\"{C}\", \"{C}\",") print(f"\t\t\"{C1}\", \"{C1}\", \"{C2}\", \"{C2}\"),") print(f"\ttarget = c(\"{A}\", \"{B}\", \"{C}\", \"{D}\",") print(f"\t\t\"{A1}\", \"{A2}\",") print(f"\t\t\"{A11}\", \"{A12}\", \"{A21}\", \"{A22}\",") print(f"\t\t\"{B1}\", \"{B2}\",") print(f"\t\t\"{B11}\", \"{B12}\", \"{B21}\", \"{B22}\",") print(f"\t\t\"{C1}\", \"{C2}\",") print(f"\t\t\"{C11}\", \"{C12}\", \"{C21}\", \"{C22}\"),") print(f"\tvalue=c({n_A}, {n_B}, {n_C}, {n_D},") print(f"\t\t{n_A1}, {n_A2},") print(f"\t\t{n_A11}, {n_A12}, {n_A21}, {n_A22},") print(f"\t\t{n_B1}, {n_B2},") print(f"\t\t{n_B11}, {n_B12}, {n_B21}, {n_B22},") print(f"\t\t{n_C1}, {n_C2},") print(f"\t\t{n_C11}, {n_C12}, {n_C21}, {n_C22})") # Print color codes for nodes print("\n# Color codes for nodes:") print(f"\tname == \"{T}\" ~ \"{T}\",") print(f"\tname %in% c(\"{A}\",\"{B}\",\"{C}\",\"{D}\") ~ name,") print(f"\tname %in% c(\"{A1}\", \"{A2}\",\"{A11}\", \"{A12}\", \"{A21}\", \"{A22}\") ~ \"{A}\",") print(f"\tname %in% c(\"{B1}\", \"{B2}\",\"{B11}\", \"{B12}\", \"{B21}\", \"{B22}\") ~ \"{B}\",") print(f"\tname %in% c(\"{C1}\", \"{C2}\",\"{C11}\", \"{C12}\", \"{C21}\", \"{C22}\") ~ \"{C}\",") print(f"\nABCD = c(\"{A}\",\"{B}\",\"{C}\",\"{D}\")")```
Finally we are ready to encapsulate this as Sankey diagrams:
4.1 Figure8Knot Sums by Percentage of Khipus
Click on image to view larger
4.2 Figure8Knot Sums by Percentage of All Pendant Ascher Sums
Click on image to view larger
5.0 - Diagrammatic Representations of the Ascher Summand Ranges by Figure-8 Knots
We can build a summand map of Ascher Sums marked by Figure8Knots for Left and Right-Handed Sums. For example here is a zoomed in snapshot of the summand map for Right-Handed Sums for KH0143 showing the relationships between Figure-8-Knots, their types, and the Ascher Summand regions.
An individual summand map for each khipu is available via its catalog page. For example here is the pendant-pendant sum drawings and information for KH0143