# Arno's keyboard layout comparison

[Arno Klein](https://binarybottle.com) wrote this keyboard layout comparison software principally to evaluate the [Engram layout](https://github.com/binarybottle/engram).
An article is under review (see the [preprint](https://www.preprints.org/manuscript/202103.0287/v1)).

(c) 2021 Arno Klein, MIT license

----------------

# Contents
1. [Summary](#Summary)
2. [Scores based on the Engram scoring model](#Engram)
3. [Carpalx scores](#CarpalX)
4. [Keyboard Layout Analyzer scores](#KLAscores)
5. [Keyboard Layout Analyzer data](#KLAdata)
6. [Keyboard Layout Analyzer analysis of individual measures](#KLAmeasures)

## Summary <a name="summary">

#### Engram Scoring Model scores (x100) for layouts, based on publicly available text data

| Layout | Google bigrams | Alice | Romeo | Gita | Memento | 100K tweets | 20K tweets | MASC tweets | MASC spoken | COCA blogs | iweb | Monkey | Coder | Code |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram | 73.56 | 72.99 | 73.16 | 72.98 | 73.66 | 74.41 | 74.06 | 73.87 | 72.88 | 73.55 | 73.75 | 73.59 | 73.90 | 73.84 |
| Halmak | 73.51 | 72.95 | 73.12 | 72.94 | 73.62 | 74.35 | 74.02 | 73.82 | 72.86 | 73.50 | 73.70 | 73.54 | 73.84 | 73.80 |
| Hieamtsrn | 73.52 | 72.96 | 73.12 | 72.94 | 73.61 | 74.35 | 74.00 | 73.82 | 72.85 | 73.51 | 73.71 | 73.55 | 73.84 | 73.74 |
| Colemak Mod-DH | 73.46 | 72.91 | 73.06 | 72.91 | 73.55 | 74.25 | 73.91 | 73.74 | 72.81 | 73.44 | 73.64 | 73.48 | 73.77 | 73.68 |
| Norman | 73.43 | 72.90 | 73.04 | 72.89 | 73.54 | 74.22 | 73.90 | 73.72 | 72.79 | 73.42 | 73.60 | 73.45 | 73.73 | 73.68 |
| Workman | 73.46 | 72.91 | 73.08 | 72.90 | 73.57 | 74.28 | 73.95 | 73.77 | 72.81 | 73.45 | 73.64 | 73.49 | 73.79 | 73.74 |
| MTGap 2.0 | 73.44 | 72.91 | 73.06 | 72.89 | 73.55 | 74.24 | 73.92 | 73.74 | 72.80 | 73.43 | 73.62 | 73.47 | 73.77 | 73.69 |
| QGMLWB | 73.41 | 72.87 | 73.02 | 72.86 | 73.52 | 74.21 | 73.89 | 73.70 | 72.78 | 73.40 | 73.59 | 73.44 | 73.73 | 73.64 |
| Colemak | 73.44 | 72.88 | 73.04 | 72.88 | 73.52 | 74.23 | 73.89 | 73.73 | 72.79 | 73.42 | 73.62 | 73.46 | 73.75 | 73.70 |
| Asset | 73.39 | 72.85 | 73.01 | 72.84 | 73.50 | 74.19 | 73.86 | 73.69 | 72.75 | 73.38 | 73.57 | 73.41 | 73.72 | 73.67 |
| Capewell-Dvorak | 73.41 | 72.88 | 73.04 | 72.87 | 73.51 | 74.23 | 73.88 | 73.71 | 72.78 | 73.40 | 73.59 | 73.44 | 73.71 | 73.65 |
| Klausler | 73.42 | 72.88 | 73.04 | 72.88 | 73.52 | 74.23 | 73.90 | 73.71 | 72.79 | 73.41 | 73.60 | 73.45 | 73.72 | 73.67 |
| Dvorak | 73.41 | 72.88 | 73.04 | 72.86 | 73.51 | 74.22 | 73.89 | 73.70 | 72.79 | 73.40 | 73.59 | 73.44 | 73.70 | 73.67 |
| QWERTY | 73.23 | 72.76 | 72.89 | 72.74 | 73.35 | 74.01 | 73.70 | 73.52 | 72.66 | 73.23 | 73.41 | 73.26 | 73.52 | 73.48 |

---

[Keyboard Layout Analyzer](http://patorjk.com/keyboard-layout-analyzer/) (KLA) scores for the same text sources:

| Layout | Keyboard Layout Analyzer mean (SD) |  | CarpalX effort |
| --- | --- | --- | --- |
| Engram | 59.61 (6.17) |  |  |
| Halmak | 58.65 (6.53) |  | 2.322 |
| Hieamtsrn | 61.23 (7.60) |  | 1.948 |
| Colemak Mod-DH | 58.63 (6.17) |  | 1.958 |
| Norman | 55.35 (5.77) |  | 1.992 |
| Workman | 57.78 (5.95) |  | 1.993 |
| MTGAP 2.0 | 57.21 (6.66) |  | 1.981 |
| QGMLWB | 57.96 (6.48) |  | 1.668 |
| Colemak | 58.66 (6.17) |  | 1.842 |
| Asset | 57.08 (5.87) |  | 1.894 |
| Capewell-Dvorak | 58.92 (6.84) |  | 1.985 |
| Klausler | 59.93 (7.13) |  | 1.867 |
| Dvorak | 58.39 (6.69) |  | 2.098 |
| QWERTY | 46.59 (4.46) |  | 3 |

---

| Layout | Year | Website |
| --- | --- | --- |
| Engram | 2021 | https://engram.dev |
| [Halmak 2.2](https://keyboard-design.com/letterlayout.html?layout=halmak-2-2.en.ansi) | 2016 | https://github.com/MadRabbit/halmak |
| [Hieamtsrn](https://www.keyboard-design.com/letterlayout.html?layout=hieamtsrn.en.ansi) | 2014 | https://mathematicalmulticore.wordpress.com/the-keyboard-layout-project/#comment-4976 |
| [Colemak Mod-DH](https://keyboard-design.com/letterlayout.html?layout=colemak-mod-DH-full.en.ansi) | 2014 | https://colemakmods.github.io/mod-dh/ |
| [Norman](https://keyboard-design.com/letterlayout.html?layout=norman.en.ansi) | 2013 | https://normanlayout.info/ |
| [Workman](https://keyboard-design.com/letterlayout.html?layout=workman.en.ansi) | 2010 | https://workmanlayout.org/ |
| [MTGAP 2.0](https://www.keyboard-design.com/letterlayout.html?layout=mtgap-2-0.en.ansi) | 2010 | https://mathematicalmulticore.wordpress.com/2010/06/21/mtgaps-keyboard-layout-2-0/ |
| [QGMLWB](https://keyboard-design.com/letterlayout.html?layout=qgmlwb.en.ansi) | 2009 | http://mkweb.bcgsc.ca/carpalx/?full_optimization |
| [Colemak](https://keyboard-design.com/letterlayout.html?layout=colemak.en.ansi) | 2006 | https://colemak.com/ |
| [Asset](https://keyboard-design.com/letterlayout.html?layout=asset.en.ansi) | 2006 | http://millikeys.sourceforge.net/asset/ |
| Capewell-Dvorak | 2004 | http://michaelcapewell.com/projects/keyboard/layout_capewell-dvorak.htm |
| [Klausler](https://www.keyboard-design.com/letterlayout.html?layout=klausler.en.ansi) | 2002 | https://web.archive.org/web/20031001163722/http://klausler.com/evolved.html |
| [Dvorak](https://keyboard-design.com/letterlayout.html?layout=dvorak.en.ansi) | 1936 | https://en.wikipedia.org/wiki/Dvorak_keyboard_layout |
| [QWERTY](https://keyboard-design.com/letterlayout.html?layout=qwerty.en.ansi) | 1873 | https://en.wikipedia.org/wiki/QWERTY |

---

| Text source | Information |
| --- | --- |
| "Alice in Wonderland" | Alice in Wonderland (Ch.1) |
| "Romeo and Juliet" | [Romeo and Juliet](https://www.fulltextarchive.com/page/Romeo-and-Juliet1/) |
| "Bhagavad Gita" | [Bhagavad Gita](https://www.gutenberg.org/files/2388/2388-h/2388-h.htm) |
| "Memento screenplay" | [Memento screenplay](https://www.dailyscript.com/scripts/memento.html) |
| "100K tweets" | 100,000 tweets from: [Sentiment140 dataset](https://data.world/data-society/twitter-user-data) training data |
| "20K tweets" | 20,000 tweets from [Gender Classifier Data](https://www.kaggle.com/crowdflower/twitter-user-gender-classification) |
| "MASC tweets" | [MASC](http://www.anc.org/data/masc/corpus/) tweets (cleaned of html markup) |
| "MASC spoken" | [MASC](http://www.anc.org/data/masc/corpus/) spoken transcripts (phone and face-to-face: 25,783 words) |
| "COCA blogs" | [Corpus of Contemporary American English](https://www.english-corpora.org/coca/) [blog samples](https://www.corpusdata.org/) |
| "Google website" | [Google homepage](https://google.com) (accessed 10/20/2020) |
| "Software languages" | "Tower of Hanoi" (programming languages A-Z from [Rosetta Code](https://rosettacode.org/wiki/Towers_of_Hanoi)) |
| "Monkey text" | Ian Douglas's English-generated [monkey0-7.txt corpus](https://zenodo.org/record/4642460) |
| "Coder text" | Ian Douglas's software-generated [coder0-7.txt corpus](https://zenodo.org/record/4642460) |
| "iweb cleaned corpus" | First 150,000 lines of Shai Coleman's [iweb-corpus-samples-cleaned.txt](https://colemak.com/pub/corpus/iweb-corpus-samples-cleaned.txt.xz) |

Reference for Monkey and Coder texts:
Douglas, Ian. (2021, March 28). Keyboard Layout Analysis: Creating the Corpus, Bigram Chains, and Shakespeare's Monkeys (Version 1.0.0). Zenodo. http://doi.org/10.5281/zenodo.4642460

### Layouts

Each layout is represented by a list of 32 characters in the following order:

    1  2  3  4   25  28   13 14 15 16   31
    5  6  7  8   26  29   17 18 19 20   32
    9 10 11 12   27  30   21 22 23 24

```python
# Layouts
engram_letters = ['Q','U','O','X','D','I','E','S','G','K','Y','A','V','L','W','B','H','T','N','C','R','M','F','P', "'",',','-', '"','.','?', 'Z','J']
halmak_letters  = ['W','L','R','B', 'S','H','N','T', 'F','M','V','C', 'Q','U','D','J', 'A','E','O','I', 'P','X','K','Y', 'Z',',','/', ';','.','G', '[',"'"]
hieamtsrn_letters  = ['B','Y','O','U', 'H','I','E','A', 'X','-','"','.', 'D','C','L','P', 'T','S','R','N', 'G','F','J','Z', "'",',','?', 'K','M','W', 'Q','V']
colemakModDH_letters = ['Q','W','F','P', 'A','R','S','T', 'Z','X','C','D', 'L','U','Y',';', 'N','E','I','O', 'H',',','.','/', 'B','J','G', 'K','V','M', '[',"'"]
norman_letters  = ['Q','W','D','F', 'A','S','E','T', 'Z','X','C','V', 'U','R','L',';', 'N','I','O','H', 'M',',','.','/', 'K','G','B', 'J','Y','P', '[',"'"]
workman_letters = ['Q','D','R','W', 'A','S','H','T', 'Z','X','M','C', 'F','U','P',';', 'N','E','O','I', 'L',',','.','/', 'B','G','V', 'J','Y','K', '[',"'"]
mtgap2_letters  = [',','F','H','D', 'O','A','N','T', 'Q','X','B','P', 'C','U','L','.', 'S','E','R','I', 'W',"'",'V',';', "K",'G','Z', 'J','M','Y', '[','/'] # Michael Dickens 2010: https://mathematicalmulticore.wordpress.com/2010/06/21/mtgaps-keyboard-layout-2-0/ https://www.keyboard-design.com/letterlayout.html?layout=mtgap-2-0.en.ansi
qgmlwb_letters  = ['Q','G','M','L', 'D','S','T','N', 'Z','X','C','F', 'Y','U','V',';', 'A','E','O','H', 'P',',','.','/', 'W','R','J', 'B','I','K', '[',"'"]
colemak_letters = ['Q','W','F','P', 'A','R','S','T', 'Z','X','C','V', 'L','U','Y',';', 'N','E','I','O', 'M',',','.','/', 'G','D','B', 'J','H','K', '[',"'"]
asset_letters  = ['Q','W','J','F', 'A','S','E','T', 'Z','X','C','V', 'P','U','L',';', 'N','I','O','R', 'M',',','.','/', 'G','Y','D', 'H','B','K', '[',"'"]
capewell_letters  = ["'",',','.','P', 'O','A','E','I', 'Z','X','C','V', 'F','G','R','K', 'H','T','N','S', 'M','W','B',';', 'Y','Q','U', 'D','J','L', '/','-']
klausler_letters  = ['K',',','U','Y', 'O','A','E','I', 'Q','.',"'",';', 'L','M','F','C', 'N','T','H','S', 'V','G','B','J', 'P','D','Z', 'W','R','X', '/',"-"]
dvorak_letters  = ["'",',','.','P', 'A','O','E','U', ';','Q','J','K', 'G','C','R','L', 'H','T','N','S', 'M','W','V','Z', 'Y','F','I', 'D','X','B', '/','-']
qwerty_letters  = ['Q','W','E','R', 'A','S','D','F', 'Z','X','C','V', 'U','I','O','P', 'J','K','L',';', 'M',',','.','/', 'T','G','B', 'Y','H','N', '[',"'"]
#beakl_letters  = ['Q','H','O','U', 'Y','I','E','A', 'J','/',',','K', 'C','R','F','Z', 'S','T','N','B', 'M','L','P','V', 'X','.',"'", 'G','D','W', '',';']
#balance12_letters  = ['P','L','C','D', 'N','R','S','T', 'Z','J','F','G', 'U','O','Y','K', 'A','E','I','H', '.','"','-','X', 'W','M','B', "'",',','?', 'Q','V'] # Sasha Viminitz (2014): https://www.keyboard-design.com/letterlayout.html?layout=balance-twelve.en.ansi
#vukeys_letters  = ['Q','C','D','M', 'N','S','T','R', 'Z','F','G','L', 'W','U','K',"'", 'I','E','O','A', 'P',',','.','/', 'V','H','X', 'J','Y','B', '[',";"] # ?

layout_names = ['Engram','Halmak','Hieamtsrn','Colemak Mod-DH',
                'Norman','Workman','MTGap 2.0','QGMLWB','Colemak',
                'Asset','Capewell-Dvorak','Klausler','Dvorak','QWERTY']
layout_abbrs = ['Engram','Halmak','Hieamtsrn','ColemakModDH',
                'Norman','Workman','MTGap','QGMLWB','Colemak',
                'Asset','CapewellDvorak','Klausler','Dvorak','QWERTY']
layout_letters = [engram_letters, halmak_letters, hieamtsrn_letters, colemakModDH_letters,
                  norman_letters, workman_letters, mtgap2_letters, qgmlwb_letters, colemak_letters,
                  asset_letters, capewell_letters, klausler_letters, dvorak_letters, qwerty_letters]
```

```python
text_names = ["Alice in Wonderland (Ch.1)",
              #"Romeo and Juliet",
              #"Bhagavad Gita",
              "Memento screenplay",
              "100,000 tweets (Sentiment Classification)",
              "20,000 tweets (Gender classifier)",
              "Manually Annotated Sub-Corpus tweets",
              "Manually Annotated Sub-Corpus spoken transcripts",
              "Corpus of Contemporary American English blog samples",
              "Shai Coleman iweb corpus 1/6",
              "Ian Douglas monkey test",
              "Ian Douglas coder test",
              "Tower of Hanoi (programming languages A-Z, Rosetta Code)"]

#text_abbrs = ["Alice", "Romeo", "Gita", "Memento", "Tweets_100K", "Tweets_20K", "Tweets_MASC",
#             "MASC_spoken", "COCA_blogs", "iweb", "Monkey", "Coder", "Rosetta"]
text_abbrs = ["Alice", "Memento", "Tweets_100K", "Tweets_20K", "Tweets_MASC",
              "Spoken_MASC", "COCA_blogs", "iweb", "Monkey", "Coder", "Rosetta"]

urls = ["https://raw.githubusercontent.com/binarybottle/text_data/main/AliceInWonderland_Ch1.txt",
        #"https://raw.githubusercontent.com/binarybottle/text_data/main/Romeo_and_Juliet.txt",
        #"https://raw.githubusercontent.com/binarybottle/text_data/main/Bhaghavad_Gita.txt",
        "https://raw.githubusercontent.com/binarybottle/text_data/main/Memento_screenplay.txt",
        "https://raw.githubusercontent.com/binarybottle/text_data/main/training.1600000.processed.noemoticon_1st100000tweets.txt",
        "https://raw.githubusercontent.com/binarybottle/text_data/main/gender-classifier-tweet-column.txt",
        "https://raw.githubusercontent.com/binarybottle/text_data/main/MASC_tweets_cleaned.txt",
        "https://raw.githubusercontent.com/binarybottle/text_data/main/MASC_spoken_transcripts_of_phone_face2face.txt",
        "https://raw.githubusercontent.com/binarybottle/text_data/main/COCA_corpusdata.org_sample_text_blog_cleaned.txt",
        "https://raw.githubusercontent.com/binarybottle/text_data/main/iweb-corpus-cleaned-1.txt",
        "https://raw.githubusercontent.com/binarybottle/text_data/main/monkey0-7_IanDouglas.txt",
        "https://raw.githubusercontent.com/binarybottle/text_data/main/coder0-7_IanDouglas.txt",
        "https://raw.githubusercontent.com/binarybottle/text_data/main/rosettacode.org_TowersOfHanoi_AtoZ.txt"]
```

### Import dependencies and functions

```python
# Import dependencies
import xlrd
import numpy as np
from sympy.utilities.iterables import multiset_permutations
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns

# Print .png figures and .txt text files
print_output = False # True

# Apply strength data
apply_strength = True
min_strength_factor = 0.9

letters24 = ['E','T','A','O','I','N','S','R','H','L','D','C','U','M','F','P','G','W','Y','B','V','K','X','J']
keys24 = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, 17,18,19,20, 21,22,23,24]
instances24 = [4.45155E+11,3.30535E+11,2.86527E+11,2.72277E+11,2.69732E+11,2.57771E+11,
               2.32083E+11,2.23768E+11,1.80075E+11,1.44999E+11,1.36018E+11,1.19156E+11,
               97273082907,89506734085,85635440629,76112599849,66615316232,59712390260,
               59331661972,52905544693,37532682260,19261229433,8369138754,5657910830]

def permute_optimize_keys(fixed_letters, fixed_letter_indices, open_letter_indices,
                          all_letters, keys, data_matrix, bigrams, bigram_frequencies,
                          verbose=False, ntop=0):
    """
    Find all permutations of letters, optimize layout, and generate output.
    """
    matrix_selected = select_keys(data_matrix, keys, verbose=False)

    unassigned_letters = []
    for all_letter in all_letters:
        if all_letter not in fixed_letters:
            unassigned_letters.append(all_letter)
            if len(unassigned_letters) == len(open_letter_indices):
                break

    letter_permutations = permute_letters(unassigned_letters, verbose)
    top_permutation, scores = optimize_layout(matrix_selected, bigrams, bigram_frequencies, letter_permutations, open_letter_indices, fixed_letters, fixed_letter_indices, verbose)

    if ntop > 0:
        print_top_scores(letter_permutations, scores, ntop)

    return top_permutation, letter_permutations, scores

def permute_optimize(letters, all_letters, all_keys, data_matrix, bigrams, bigram_frequencies, verbose=False, ntop=0):
    """
    Find all permutations of letters, optimize layout, and generate output.
    """
    matrix_selected = select_keys(data_matrix, all_keys, verbose=False)
    open_positions = []
    fixed_positions = []
    open_letters = []
    fixed_letters = []
    assigned_letters = []
    for iletter, letter in enumerate(letters):
        if letter.strip() == "":
            open_positions.append(iletter)
            for all_letter in all_letters:
                if all_letter not in letters and all_letter not in assigned_letters:
                    open_letters.append(all_letter)
                    assigned_letters.append(all_letter)
                    break
        else:
            fixed_positions.append(iletter)
            fixed_letters.append(letter)
    #print(open_positions, fixed_positions, open_letters, fixed_letters)
    letter_permutations = permute_letters(open_letters, verbose)
    top_permutation, scores = optimize_layout(matrix_selected, bigrams, bigram_frequencies, letter_permutations, open_positions, fixed_letters, fixed_positions, verbose)
    if ntop > 0:
        print_top_scores(letter_permutations, scores, ntop)

    return top_permutation, letter_permutations, scores

def select_keys(data_matrix, keys, verbose=False):
    """
    Select keys to quantify pairwise relationships.
    """
    # Extract pairwise entries for the keys:
    nkeys = len(keys)
    Select = np.zeros((nkeys, nkeys))
    u = 0
    for i in keys:
        u += 1
        v = 0
        for j in keys:
            v += 1
            Select[u-1,v-1] = data_matrix[i-1,j-1]

    # Normalize matrix with min-max scaling to a range with max 1:
    newMin = np.min(Select) / np.max(Select)
    newMax = 1.0
    Select = newMin + (Select - np.min(Select)) * (newMax - newMin) / (np.max(Select) - np.min(Select))

    if verbose:
        #print("Matrix:")
        #np.set_printoptions(precision=2); print(Select)

        # Heatmap of array
        heatmap(data=Select, title="Matrix heatmap", xlabel="Key 1", ylabel="Key 2", print_output=False); plt.show()

    return Select

def permute_letters(letters, verbose=False):
    """
    Find all permutations of a given set of letters (max: 8-10 letters).
    """
    letter_permutations = []
    for p in multiset_permutations(letters):
        letter_permutations.append(p)
    letter_permutations = np.array(letter_permutations)
    #if verbose:
    #    print("First permutation: {0}".format(letter_permutations[0]))

    return letter_permutations

def score_layout(data_matrix, letters, bigrams, bigram_frequencies, verbose=False):
    """
    Compute the score for a given letter-key layout (NOTE normalization step).
    """
    # Create a matrix of bigram frequencies:
    nletters = len(letters)
    F2 = np.zeros((nletters, nletters))

    # Find the bigram frequency for each ordered pair of letters in the permutation:
    for i1 in range(nletters):
        for i2 in range(nletters):
            bigram = letters[i1] + letters[i2]
            i2gram = np.where(bigrams == bigram)
            if np.size(i2gram) > 0:
                F2[i1, i2] = bigram_frequencies[i2gram][0]

    # Normalize matrices with min-max scaling to a range with max 1:
    newMax = 1
    minF2 = np.min(F2)
    maxF2 = np.max(F2)
    newMin2 = minF2 / maxF2
    F2 = newMin + (F2 - minF2) * (newMax - newMin2) / (maxF2 - minF2)

    # Compute the score for this permutation:
    score  = np.average(data_matrix * F2)
    if verbose:
        print("Score for letter permutation {0}: {1}".format(letters, score))

    return score

def tally_bigrams(input_text, bigrams, normalize=True, verbose=False):
    """
    Compute the score for a given letter-key layout (NOTE normalization step).
    """
    # Find the bigram frequency for each ordered pair of letters in the input text
    #input_text = [str.upper(str(x)) for x in input_text]
    input_text = [str.upper(x) for x in input_text]
    nchars = len(input_text)
    F = np.zeros(len(bigrams))

    for ichar in range(0, nchars-1):
        bigram = input_text[ichar] + input_text[ichar + 1]
        i2gram = np.where(bigrams == bigram)
        if np.size(i2gram) > 0:
            F[i2gram] += 1

    # Normalize matrix with min-max scaling to a range with max 1:
    if normalize:
        newMax = 1
        newMin = np.min(F) / np.max(F)
        F = newMin + (F - np.min(F)) * (newMax - newMin) / (np.max(F) - np.min(F))

    bigram_frequencies_for_input = F

    if verbose:
        print("Bigram frequencies for input: {0}".format(bigram_frequencies_for_input))

    return bigram_frequencies_for_input

def tally_layout_samefinger_bigrams(layout, bigrams, bigram_frequencies, verbose=False):
    """
    Tally the number of same-finger bigrams within (a list of 24 letters representing) a layout:
    ['P','Y','O','U','C','I','E','A','G','K','J','X','M','D','L','B','R','T','N','S','H','V','W','F']
    """
    #    1  2  3  4   13 14 15 16
    #    5  6  7  8   17 18 19 20
    #    9 10 11 12   21 22 23 24
    same_finger_keys = [[1,5],[5,9],[1,9], [2,6],[6,10],[2,10],
                        [3,7],[7,11],[3,11], [4,8],[8,12],[4,12],
                        [13,17],[17,21],[13,21], [14,18],[18,22],[14,22],
                        [15,19],[19,23],[15,23], [16,20],[20,24],[16,24]]

    layout = [str.upper(x) for x in layout]
    max_frequency = 1.00273E+11

    samefinger_bigrams = []
    samefinger_bigram_counts = []
    for bigram_keys in same_finger_keys:
        bigram1 = layout[bigram_keys[0]-1] + layout[bigram_keys[1]-1]
        bigram2 = layout[bigram_keys[1]-1] + layout[bigram_keys[0]-1]
        i2gram1 = np.where(bigrams == bigram1)
        i2gram2 = np.where(bigrams == bigram2)
        if np.size(i2gram1) > 0:
            samefinger_bigrams.append(bigram1)
            samefinger_bigram_counts.append(max_frequency * bigram_frequencies[i2gram1] / np.max(bigram_frequencies))
        if np.size(i2gram2) > 0:
            samefinger_bigrams.append(bigram2)
            samefinger_bigram_counts.append(max_frequency * bigram_frequencies[i2gram2] / np.max(bigram_frequencies))

    samefinger_bigrams_total = np.sum(samefinger_bigram_counts)

    if verbose:
        print("    Total same-finger bigram frequencies: {0:15.0f}".format(samefinger_bigrams_total))

    return samefinger_bigrams, samefinger_bigram_counts, samefinger_bigrams_total

def optimize_layout(data_matrix, bigrams, bigram_frequencies, letter_permutations, open_positions, fixed_letters, fixed_positions=[], verbose=False):
    """
    Compute scores for all letter-key layouts.
    """
    iter = 0
    top_score = 0
    scores = []
    use_score_function = False

    nletters = len(open_positions) + len(fixed_positions)
    top_permutation = np.array(['E' for x in range(nletters)])
    F2 = np.zeros((nletters, nletters))

    # Loop through the permutations of the selected letters:
    for p in letter_permutations:
        letters = np.array(['E' for x in range(nletters)])  # KEEP to initialize!
        for imove, open_position in enumerate(open_positions):
            letters[open_position] = p[imove]
        for ifixed, fixed_position in enumerate(fixed_positions):
            letters[fixed_position] = fixed_letters[ifixed]

        # Compute the score for this permutation:
        if use_score_function:
            score = score_layout(data_matrix, letters, bigrams, bigram_frequencies, verbose=False)
        else:
            # Find the bigram frequency for each ordered pair of letters in the permutation:
            for i1 in range(nletters):
                for i2 in range(nletters):
                    bigram = letters[i1] + letters[i2]
                    i2gram = np.where(bigrams == bigram)
                    if np.size(i2gram) > 0:
                        F2[i1, i2] = bigram_frequencies[i2gram][0]

            # Normalize matrices with min-max scaling to a range with max 1:
            newMax = 1
            minF2 = np.min(F2)
            maxF2 = np.max(F2)
            newMin2 = minF2 / maxF2
            F = newMin + (F2 - minF2) * (newMax - newMin2) / (maxF2 - minF2)

            # Compute the score for this permutation:
            score  = np.average(data_matrix * F)

        # Store all scores and the top score and permutation:
        scores.append(score)
        if score > top_score:
            top_score = score
            top_permutation = letters

    #print("Topmost of {0} permutations: {1}".format(len(letter_permutations), top_score))
    if verbose:
        print("{0:0.8f}".format(top_score))
        print(*top_permutation)

    return top_permutation, scores

def exchange_letters(letters, fixed_letter_indices, all_letters, all_keys, data_matrix,
                     bigrams, bigram_frequencies, verbose=True, ntop=0):
    """
    Exchange letters, 8 keys at a time (8! = 40,320) selected twice in 32 different ways:

    Indices:
         0  1  2  3     12 13 14 15
         4  5  6  7     16 17 18 19
         8  9 10 11     20 21 22 23

    1. Top rows
         0  1  2  3     12 13 14 15
    2. Bottom rows
         8  9 10 11     20 21 22 23
    3. Top and bottom rows on the right side
                        12 13 14 15
                        20 21 22 23
    4. Top and bottom rows on the left side
         0  1  2  3
         8  9 10 11
    5. Top right and bottom left rows
                        12 13 14 15
         8  9 10 11
    6. Top left and bottom right rows
         0  1  2  3
                        20 21 22 23
    7. Center of the top and bottom rows on both sides
            1  2          13 14
            9 10          21 22
    8. The eight corners
         0        3    12       15
         8       11    20       23
    9. Left half of the top and bottom rows on both sides
         0  1          12 13
         8  9          20 21
    10. Right half of the top and bottom rows on both sides
               2  3          14 15
              10 11          22 23
    11. Left half of non-home rows on the left and right half of the same rows on the right
         0  1                14 15
         8  9                22 23
    12. Right half of non-home rows on the left and left half of the same rows on the right
               2  3    12 13
              10 11    20 21
    13. Top center and lower sides
            1  2           13 14
         8       11     20       23
    14. Top sides and lower center
         0        3     12       15
            9 10           21 22
    15. Repeat 1-14

    """
    score = score_layout(data_matrix, letters, bigrams, bigram_frequencies, verbose=False)
    print('Initial score: {0}'.format(score))
    print(*letters)
    top_permutation = letters

    lists_of_open_indices = [
        [0,1,2,3,12,13,14,15],
        [8,9,10,11,20,21,22,23],
        [12,13,14,15,20,21,22,23],
        [0,1,2,3,8,9,10,11],
        [12,13,14,15,8,9,10,11],
        [0,1,2,3,20,21,22,23],
        [1,2,13,14,9,10,21,22],
        [0,3,12,15,8,11,20,23],
        [0,1,12,13,8,9,20,21],
        [2,3,14,15,10,11,22,23],
        [0,1,14,15,8,9,22,23],
        [2,3,12,13,10,11,20,21],
        [1,2,8,11,13,14,20,23],
        [0,3,9,10,12,15,21,22]
    ]
    lists_of_print_statements = [
        '1. Top rows',
        '2. Bottom rows',
        '3. Top and bottom rows on the right side',
        '4. Top and bottom rows on the left side',
        '5. Top right and bottom left rows',
        '6. Top left and bottom right rows',
        '7. Center of the top and bottom rows on both sides',
        '8. The eight corners',
        '9. Left half of the top and bottom rows on both sides',
        '10. Right half of the top and bottom rows on both sides',
        '11. Left half of non-home rows on the left and right half of the same rows on the right',
        '12. Right half of non-home rows on the left and left half of the same rows on the right',
        '13. Top center and lower sides',
        '14. Top sides and lower center'
    ]

    for istep in [1,2]:
        if istep == 1:
            s = "First set of 14 letter exchanges: "
        elif istep == 2:
            s = "Second set of 14 letter exchanges: "

        for ilist, open_indices in enumerate(lists_of_open_indices):
            print_statement = lists_of_print_statements[ilist]

            if verbose:
                print('{0} {1}'.format(s, print_statement))

            for open_index in open_indices:
                if open_index not in fixed_letter_indices:
                    top_permutation[open_index] = ''

            top_permutation, letter_permutations, scores = permute_optimize(top_permutation, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose=True, ntop=0)
            top_permutation = top_permutation.tolist()

    if verbose:
        print('')
        print('    -------- DONE --------')
        print('')

    return top_permutation

def rank_within_epsilon(numbers, epsilon, factor=False, verbose=True):
    """
    numbers = np.array([10,9,8,7,6])
    epsilon = 1
    rank_within_epsilon(numbers, epsilon, factor=False, verbose=True)
    >>> array([1., 1., 2., 2., 3.])
    numbers = np.array([0.798900824, 0.79899900824, 0.79900824])
    epsilon = 0.9**8 - 0.9**9
    factor = ((24**2 - 1) + (1-epsilon)) / (24**2) # 0.999925266109375
    rank_within_epsilon(numbers, factor, factor=True, verbose=True)
    >>> array([2., 1., 1.])
    """
    numbers = np.array(numbers)
    Isort = np.argsort(-numbers)
    numbers_sorted = numbers[Isort]
    count = 1
    ranks = np.zeros(np.size(numbers))
    for i, num in enumerate(numbers_sorted):
        if ranks[i] == 0:
            if factor:
                lower_bound = num * epsilon
            else:
                lower_bound = num - epsilon
            bounded_nums1 = num >= numbers_sorted
            bounded_nums2 = numbers_sorted >= lower_bound
            bounded_nums = bounded_nums1 * bounded_nums2
            count += 1
            for ibounded, bounded_num in enumerate(bounded_nums):
                if bounded_num == True:
                    ranks[ibounded] = count

    uranks = np.unique(ranks)
    nranks = np.size(uranks)
    new_ranks = ranks.copy()
    new_count = 0
    for rank in uranks:
        new_count += 1
        same_ranks = ranks == rank
        for isame, same_rank in enumerate(same_ranks):
            if same_rank == True:
                new_ranks[isame] = new_count

    #ranks_sorted = new_ranks[Isort]
    ranks_sorted = [np.int(x) for x in new_ranks]

    if verbose:
        for i, num in enumerate(numbers_sorted):
            print("    ({0})    {1}".format(np.int(ranks_sorted[i]), num))

    return numbers_sorted, ranks_sorted, Isort
```

```python
def print_top_scores(letter_permutations, scores, ntop):
    """
    Print top-scored letter permutations.
    """
    scores_negative = -np.array(scores)
    isort = np.argsort(scores_negative)[:ntop]
    sorted_scores = [scores[isort[x]] for x in range(len(isort))]
    sorted_letter_permutations = [letter_permutations[isort[x]].tolist() for x in range(len(isort))]
    for ix, x in enumerate(sorted_letter_permutations):
        print("{0:0.8f}".format(sorted_scores[ix]))
        print(*x)

def print_matrix_info(matrix_data, matrix_label, nkeys, nlines=10):
    """
    Print matrix output.
    """
    print("{0} min = {1}, max = {2}".format(matrix_label, np.min(matrix_data), np.max(matrix_data)))
    matrix_flat = matrix_data.flatten()
    argsort = np.argsort(matrix_flat)
    print("{0} key number pairs with minimum values:".format(matrix_label))
    for x in argsort[0:nlines]:
        if x % nkeys == 0:
            min_row = np.int(np.ceil(x / nkeys)) + 1
            min_col = 1
        else:
            min_row = np.int(np.ceil(x / nkeys))
            min_col = x - nkeys * (min_row-1) + 1
        print("        {0} -> {1}        ({2})".format(min_row, min_col, matrix_flat[x]))
    print("{0} key number pairs with maximum values:".format(matrix_label))
    max_sort = argsort[-nlines::]
    for x in max_sort[::-1]:
        if x % nkeys == 0:
            max_row = np.int(np.ceil(x / nkeys)) + 1
            max_col = 1
        else:
            max_row = np.int(np.ceil(x / nkeys))
            max_col = x - nkeys * (max_row-1) + 1
        print("        {0} -> {1}        ({2})".format(max_row, max_col, matrix_flat[x]))

def heatmap(data, title="", xlabel="", ylabel="", x_axis_labels=[], y_axis_labels=[], print_output=True):
    """
    Plot heatmap of matrix.
    """
    # use heatmap function, set the color as viridis and
    # make each cell seperate using linewidth parameter
    plt.figure()
    sns_plot = sns.heatmap(data, xticklabels=x_axis_labels, yticklabels=y_axis_labels, linewidths=1,
                           cmap="viridis", square=True, vmin=np.min(data), vmax=np.max(data))
    plt.title(title)
    plt.xlabel(xlabel)
    plt.ylabel(ylabel)
    sns_plot.set_xticklabels(x_axis_labels)  #, rotation=75)
    sns_plot.set_yticklabels(y_axis_labels)
    if print_output:
        sns_plot.figure.savefig("{0}_heatmap.png".format(title))

def histmap(data, title="", print_output=True):
    """
    Plot histogram.
    """
    sns.distplot(data)
    plt.title(title)
    if print_output:
        sns_plot.figure.savefig("{0}_histogram.png".format(title))

def print_layout24(layout):
    """
    Print layout.
    """
    print('    {0}  {1}'.format(' '.join(layout[0:4]),
                                ' '.join(layout[12:16])))
    print('    {0}  {1}'.format(' '.join(layout[4:8]),
                                ' '.join(layout[16:20])))
    print('    {0}  {1}'.format(' '.join(layout[8:12]),
                                ' '.join(layout[20:24])))

# letters24 = ['E','T','A','O','I','N','S','R','H','L','D','C','U','M','F','P','G','W','Y','B','V','K','X','J']
instances24 = [4.45155E+11,3.30535E+11,2.86527E+11,2.72277E+11,2.69732E+11,2.57771E+11,
               2.32083E+11,2.23768E+11,1.80075E+11,1.44999E+11,1.36018E+11,1.19156E+11,
               97273082907,89506734085,85635440629,76112599849,66615316232,59712390260,
               59331661972,52905544693,37532682260,19261229433,8369138754,5657910830]

def print_layout24_instances(layout, letters24, instances24, bigrams, bigram_frequencies):
    """
    Print billions of instances per letter (not Z or Q) in layout form.
    layout = ['P','Y','O','U','C','I','E','A','G','K','J','X','M','D','L','B','R','T','N','S','H','V','W','F']
    print_layout24_instances(layout, letters24, instances24, bigrams, bigram_frequencies)
    """
    layout_instances = []
    layout_instances_strings = []
    for letter in layout:
        index = letters24.index(letter)
        layout_instances.append(instances24[index])
        layout_instances_strings.append('{0:3.0f}'.format(instances24[index]/1000000000))

    print('    {0}  {1}'.format(' '.join(layout_instances_strings[0:4]),
                                ' '.join(layout_instances_strings[12:16])))
    print('    {0}  {1}'.format(' '.join(layout_instances_strings[4:8]),
                                ' '.join(layout_instances_strings[16:20])))
    print('    {0}  {1}'.format(' '.join(layout_instances_strings[8:12]),
                                ' '.join(layout_instances_strings[20:24])))
    left_sum = np.sum(layout_instances[0:12])/1000000000000
    right_sum = np.sum(layout_instances[12:24])/1000000000000
    pL = ''
    pR = ''
    if left_sum > right_sum:
        pL = ' ({0:3.2f}%)'.format(100 * (left_sum - right_sum) / right_sum)
    elif right_sum > left_sum:
        pR = ' ({0:3.2f}%)'.format(100 * (right_sum - left_sum) / left_sum)

    print('\n    left: {0:3.3f}T{1}  right: {2:3.3f}T{3}'.format(left_sum, pL,
                                                                 right_sum, pR))

    tally_layout_samefinger_bigrams(layout, bigrams, bigram_frequencies, verbose=True)
```

### Bigram frequencies <a name="ngrams">

[Peter Norvig's ngrams table](http://www.norvig.com/mayzner.html](http://www.norvig.com/mayzner.html)

[NOTE: If you want to compute an optimized layout for another language, or based on another corpus, you can run the tally_bigrams() function above and replace bigram_frequencies below before running the rest of the code.]

```python
load_original_ngram_files = False
if load_original_ngram_files:
    ngrams_table = "data/bigrams-trigrams-frequencies.xlsx"
    wb = xlrd.open_workbook(ngrams_table)
    ngrams_sheet = wb.sheet_by_index(0)
    # 1-grams and frequencies
    onegrams = np.array(())
    onegram_frequencies = np.array(())
    i = 0
    start1 = 0
    stop1 = 0
    while stop1 == 0:
        if ngrams_sheet.cell_value(i, 0) == "2-gram":
            stop1 = 1
        elif ngrams_sheet.cell_value(i, 0) == "1-gram":
            start1 = 1
        elif start1 == 1:
            onegrams = np.append(onegrams, ngrams_sheet.cell_value(i, 0))
            onegram_frequencies = np.append(onegram_frequencies, ngrams_sheet.cell_value(i, 1))
        i += 1
    onegram_frequencies = onegram_frequencies / np.sum(onegram_frequencies)

    # 2-grams and frequencies
    bigrams = np.array(())
    bigram_frequencies = np.array(())
    i = 0
    start1 = 0
    stop1 = 0
    while stop1 == 0:
        if ngrams_sheet.cell_value(i, 0) == "3-gram":
            stop1 = 1
        elif ngrams_sheet.cell_value(i, 0) == "2-gram":
            start1 = 1
        elif start1 == 1:
            bigrams = np.append(bigrams, ngrams_sheet.cell_value(i, 0))
            bigram_frequencies = np.append(bigram_frequencies, ngrams_sheet.cell_value(i, 1))
        i += 1
    bigram_frequencies = bigram_frequencies / np.sum(bigram_frequencies)

    # Save:
    file = open("onegrams.txt", "w+")
    file.write(str(onegrams))
    file.close()
    file = open("onegram_frequencies.txt", "w+")
    file.write(str(onegram_frequencies))
    file.close()
    file = open("bigrams.txt", "w+")
    file.write(str(bigrams))
    file.close()
    file = open("bigram_frequencies.txt", "w+")
    file.write(str(bigram_frequencies))
    file.close()

    # Print:
    print(repr(onegrams))
    print(repr(onegram_frequencies))
    print(repr(bigrams))
    print(repr(bigram_frequencies))

else:
    onegrams = np.array(['E', 'T', 'A', 'O', 'I', 'N', 'S', 'R', 'H', 'L', 'D', 'C', 'U',
       'M', 'F', 'P', 'G', 'W', 'Y', 'B', 'V', 'K', 'X', 'J', 'Q', 'Z'],
      dtype='<U32')
    onegram_frequencies = np.array([0.12492063, 0.09275565, 0.08040605, 0.07640693, 0.07569278,
       0.07233629, 0.06512767, 0.06279421, 0.05053301, 0.04068986,
       0.03816958, 0.03343774, 0.02729702, 0.02511761, 0.02403123,
       0.02135891, 0.01869376, 0.01675664, 0.0166498 , 0.01484649,
       0.01053252, 0.00540513, 0.00234857, 0.00158774, 0.00120469,
       0.00089951])
    bigrams = np.array(['TH', 'HE', 'IN', 'ER', 'AN', 'RE', 'ON', 'AT', 'EN', 'ND', 'TI',
       'ES', 'OR', 'TE', 'OF', 'ED', 'IS', 'IT', 'AL', 'AR', 'ST', 'TO',
       'NT', 'NG', 'SE', 'HA', 'AS', 'OU', 'IO', 'LE', 'VE', 'CO', 'ME',
       'DE', 'HI', 'RI', 'RO', 'IC', 'NE', 'EA', 'RA', 'CE', 'LI', 'CH',
       'LL', 'BE', 'MA', 'SI', 'OM', 'UR', 'CA', 'EL', 'TA', 'LA', 'NS',
       'DI', 'FO', 'HO', 'PE', 'EC', 'PR', 'NO', 'CT', 'US', 'AC', 'OT',
       'IL', 'TR', 'LY', 'NC', 'ET', 'UT', 'SS', 'SO', 'RS', 'UN', 'LO',
       'WA', 'GE', 'IE', 'WH', 'EE', 'WI', 'EM', 'AD', 'OL', 'RT', 'PO',
       'WE', 'NA', 'UL', 'NI', 'TS', 'MO', 'OW', 'PA', 'IM', 'MI', 'AI',
       'SH', 'IR', 'SU', 'ID', 'OS', 'IV', 'IA', 'AM', 'FI', 'CI', 'VI',
       'PL', 'IG', 'TU', 'EV', 'LD', 'RY', 'MP', 'FE', 'BL', 'AB', 'GH',
       'TY', 'OP', 'WO', 'SA', 'AY', 'EX', 'KE', 'FR', 'OO', 'AV', 'AG',
       'IF', 'AP', 'GR', 'OD', 'BO', 'SP', 'RD', 'DO', 'UC', 'BU', 'EI',
       'OV', 'BY', 'RM', 'EP', 'TT', 'OC', 'FA', 'EF', 'CU', 'RN', 'SC',
       'GI', 'DA', 'YO', 'CR', 'CL', 'DU', 'GA', 'QU', 'UE', 'FF', 'BA',
       'EY', 'LS', 'VA', 'UM', 'PP', 'UA', 'UP', 'LU', 'GO', 'HT', 'RU',
       'UG', 'DS', 'LT', 'PI', 'RC', 'RR', 'EG', 'AU', 'CK', 'EW', 'MU',
       'BR', 'BI', 'PT', 'AK', 'PU', 'UI', 'RG', 'IB', 'TL', 'NY', 'KI',
       'RK', 'YS', 'OB', 'MM', 'FU', 'PH', 'OG', 'MS', 'YE', 'UD', 'MB',
       'IP', 'UB', 'OI', 'RL', 'GU', 'DR', 'HR', 'CC', 'TW', 'FT', 'WN',
       'NU', 'AF', 'HU', 'NN', 'EO', 'VO', 'RV', 'NF', 'XP', 'GN', 'SM',
       'FL', 'IZ', 'OK', 'NL', 'MY', 'GL', 'AW', 'JU', 'OA', 'EQ', 'SY',
       'SL', 'PS', 'JO', 'LF', 'NV', 'JE', 'NK', 'KN', 'GS', 'DY', 'HY',
       'ZE', 'KS', 'XT', 'BS', 'IK', 'DD', 'CY', 'RP', 'SK', 'XI', 'OE',
       'OY', 'WS', 'LV', 'DL', 'RF', 'EU', 'DG', 'WR', 'XA', 'YI', 'NM',
       'EB', 'RB', 'TM', 'XC', 'EH', 'TC', 'GY', 'JA', 'HN', 'YP', 'ZA',
       'GG', 'YM', 'SW', 'BJ', 'LM', 'CS', 'II', 'IX', 'XE', 'OH', 'LK',
       'DV', 'LP', 'AX', 'OX', 'UF', 'DM', 'IU', 'SF', 'BT', 'KA', 'YT',
       'EK', 'PM', 'YA', 'GT', 'WL', 'RH', 'YL', 'HS', 'AH', 'YC', 'YN',
       'RW', 'HM', 'LW', 'HL', 'AE', 'ZI', 'AZ', 'LC', 'PY', 'AJ', 'IQ',
       'NJ', 'BB', 'NH', 'UO', 'KL', 'LR', 'TN', 'GM', 'SN', 'NR', 'FY',
       'MN', 'DW', 'SB', 'YR', 'DN', 'SQ', 'ZO', 'OJ', 'YD', 'LB', 'WT',
       'LG', 'KO', 'NP', 'SR', 'NQ', 'KY', 'LN', 'NW', 'TF', 'FS', 'CQ',
       'DH', 'SD', 'VY', 'DJ', 'HW', 'XU', 'AO', 'ML', 'UK', 'UY', 'EJ',
       'EZ', 'HB', 'NZ', 'NB', 'MC', 'YB', 'TP', 'XH', 'UX', 'TZ', 'BV',
       'MF', 'WD', 'OZ', 'YW', 'KH', 'GD', 'BM', 'MR', 'KU', 'UV', 'DT',
       'HD', 'AA', 'XX', 'DF', 'DB', 'JI', 'KR', 'XO', 'CM', 'ZZ', 'NX',
       'YG', 'XY', 'KG', 'TB', 'DC', 'BD', 'SG', 'WY', 'ZY', 'AQ', 'HF',
       'CD', 'VU', 'KW', 'ZU', 'BN', 'IH', 'TG', 'XV', 'UZ', 'BC', 'XF',
       'YZ', 'KM', 'DP', 'LH', 'WF', 'KF', 'PF', 'CF', 'MT', 'YU', 'CP',
       'PB', 'TD', 'ZL', 'SV', 'HC', 'MG', 'PW', 'GF', 'PD', 'PN', 'PC',
       'RX', 'TV', 'IJ', 'WM', 'UH', 'WK', 'WB', 'BH', 'OQ', 'KT', 'RQ',
       'KB', 'CG', 'VR', 'CN', 'PK', 'UU', 'YF', 'WP', 'CZ', 'KP', 'DQ',
       'WU', 'FM', 'WC', 'MD', 'KD', 'ZH', 'GW', 'RZ', 'CB', 'IW', 'XL',
       'HP', 'MW', 'VS', 'FC', 'RJ', 'BP', 'MH', 'HH', 'YH', 'UJ', 'FG',
       'FD', 'GB', 'PG', 'TK', 'KK', 'HQ', 'FN', 'LZ', 'VL', 'GP', 'HZ',
       'DK', 'YK', 'QI', 'LX', 'VD', 'ZS', 'BW', 'XQ', 'MV', 'UW', 'HG',
       'FB', 'SJ', 'WW', 'GK', 'UQ', 'BG', 'SZ', 'JR', 'QL', 'ZT', 'HK',
       'VC', 'XM', 'GC', 'FW', 'PZ', 'KC', 'HV', 'XW', 'ZW', 'FP', 'IY',
       'PV', 'VT', 'JP', 'CV', 'ZB', 'VP', 'ZR', 'FH', 'YV', 'ZG', 'ZM',
       'ZV', 'QS', 'KV', 'VN', 'ZN', 'QA', 'YX', 'JN', 'BF', 'MK', 'CW',
       'JM', 'LQ', 'JH', 'KJ', 'JC', 'GZ', 'JS', 'TX', 'FK', 'JL', 'VM',
       'LJ', 'TJ', 'JJ', 'CJ', 'VG', 'MJ', 'JT', 'PJ', 'WG', 'VH', 'BK',
       'VV', 'JD', 'TQ', 'VB', 'JF', 'DZ', 'XB', 'JB', 'ZC', 'FJ', 'YY',
       'QN', 'XS', 'QR', 'JK', 'JV', 'QQ', 'XN', 'VF', 'PX', 'ZD', 'QT',
       'ZP', 'QO', 'DX', 'HJ', 'GV', 'JW', 'QC', 'JY', 'GJ', 'QB', 'PQ',
       'JG', 'BZ', 'MX', 'QM', 'MZ', 'QF', 'WJ', 'ZQ', 'XR', 'ZK', 'CX',
       'FX', 'FV', 'BX', 'VW', 'VJ', 'MQ', 'QV', 'ZF', 'QE', 'YJ', 'GX',
       'KX', 'XG', 'QD', 'XJ', 'SX', 'VZ', 'VX', 'WV', 'YQ', 'BQ', 'GQ',
       'VK', 'ZJ', 'XK', 'QP', 'HX', 'FZ', 'QH', 'QJ', 'JZ', 'VQ', 'KQ',
       'XD', 'QW', 'JX', 'QX', 'KZ', 'WX', 'FQ', 'XZ', 'ZX'], dtype='<U32')
    bigram_frequencies = np.array([3.55620339e-02, 3.07474124e-02, 2.43274529e-02, 2.04826481e-02,
       1.98515108e-02, 1.85432319e-02, 1.75804642e-02, 1.48673230e-02,
       1.45424846e-02, 1.35228145e-02, 1.34257882e-02, 1.33939375e-02,
       1.27653906e-02, 1.20486963e-02, 1.17497528e-02, 1.16812337e-02,
       1.12842988e-02, 1.12327374e-02, 1.08744953e-02, 1.07489847e-02,
       1.05347566e-02, 1.04126653e-02, 1.04125115e-02, 9.53014842e-03,
       9.32114579e-03, 9.25763559e-03, 8.71095073e-03, 8.70002319e-03,
       8.34931851e-03, 8.29254235e-03, 8.25280566e-03, 7.93859725e-03,
       7.93006486e-03, 7.64818391e-03, 7.63241814e-03, 7.27618866e-03,
       7.26724441e-03, 6.98707488e-03, 6.91722265e-03, 6.88165290e-03,
       6.85633031e-03, 6.51417363e-03, 6.24352184e-03, 5.97765978e-03,
       5.76571076e-03, 5.76283716e-03, 5.65269345e-03, 5.50057242e-03,
       5.46256885e-03, 5.42747781e-03, 5.38164098e-03, 5.30301559e-03,
       5.29886071e-03, 5.27529444e-03, 5.08937452e-03, 4.92966405e-03,
       4.87753568e-03, 4.84902069e-03, 4.77989185e-03, 4.77282719e-03,
       4.74470916e-03, 4.64574958e-03, 4.60971757e-03, 4.54257059e-03,
       4.47772200e-03, 4.42103298e-03, 4.31534618e-03, 4.25820178e-03,
       4.25013516e-03, 4.15745843e-03, 4.12608242e-03, 4.05151268e-03,
       4.05075209e-03, 3.97732158e-03, 3.96527277e-03, 3.94413046e-03,
       3.86884200e-03, 3.85337077e-03, 3.85189513e-03, 3.84646388e-03,
       3.78793431e-03, 3.77605408e-03, 3.74420703e-03, 3.73663638e-03,
       3.67956418e-03, 3.65492648e-03, 3.61676413e-03, 3.61373182e-03,
       3.60899233e-03, 3.47234973e-03, 3.45829494e-03, 3.39212478e-03,
       3.37488213e-03, 3.36877623e-03, 3.30478042e-03, 3.23572471e-03,
       3.17759946e-03, 3.17691369e-03, 3.16447752e-03, 3.15240004e-03,
       3.15172398e-03, 3.11176534e-03, 2.95503911e-03, 2.89966768e-03,
       2.87848219e-03, 2.86282435e-03, 2.84865969e-03, 2.84585627e-03,
       2.81484803e-03, 2.69544349e-03, 2.62987083e-03, 2.54961380e-03,
       2.54906719e-03, 2.54783715e-03, 2.52606379e-03, 2.47740122e-03,
       2.39175226e-03, 2.36573195e-03, 2.33400171e-03, 2.29786417e-03,
       2.27503360e-03, 2.27277101e-03, 2.23911052e-03, 2.21754315e-03,
       2.18017446e-03, 2.17360835e-03, 2.14044590e-03, 2.13767970e-03,
       2.13188615e-03, 2.10259217e-03, 2.04932647e-03, 2.04724906e-03,
       2.03256516e-03, 2.02845908e-03, 1.96777866e-03, 1.95449429e-03,
       1.95410531e-03, 1.91254221e-03, 1.89316385e-03, 1.88234971e-03,
       1.87652262e-03, 1.84944194e-03, 1.83351654e-03, 1.78086545e-03,
       1.76468430e-03, 1.75132925e-03, 1.71573739e-03, 1.70683303e-03,
       1.66405086e-03, 1.63999785e-03, 1.62732115e-03, 1.62613977e-03,
       1.60361051e-03, 1.54749379e-03, 1.51636562e-03, 1.51067364e-03,
       1.49901610e-03, 1.49455831e-03, 1.49011351e-03, 1.48460771e-03,
       1.48077067e-03, 1.47541326e-03, 1.47480347e-03, 1.46316579e-03,
       1.46204465e-03, 1.43745726e-03, 1.41513491e-03, 1.39980075e-03,
       1.38382616e-03, 1.36545598e-03, 1.36333253e-03, 1.36012483e-03,
       1.35189358e-03, 1.32127808e-03, 1.30185876e-03, 1.28328757e-03,
       1.27907576e-03, 1.26260675e-03, 1.23637099e-03, 1.23094105e-03,
       1.21386641e-03, 1.20743055e-03, 1.19536134e-03, 1.19032774e-03,
       1.17626124e-03, 1.16805780e-03, 1.14618533e-03, 1.11559852e-03,
       1.06597119e-03, 1.05782134e-03, 1.04699320e-03, 1.04540205e-03,
       1.01153313e-03, 9.97734501e-04, 9.86028683e-04, 9.84491816e-04,
       9.79174450e-04, 9.78784303e-04, 9.70343472e-04, 9.68322624e-04,
       9.66708177e-04, 9.60690121e-04, 9.59749105e-04, 9.43900197e-04,
       9.40242103e-04, 9.28331656e-04, 9.26685761e-04, 9.14014864e-04,
       9.02555222e-04, 8.92112065e-04, 8.85803335e-04, 8.77507468e-04,
       8.62646840e-04, 8.57695087e-04, 8.54499050e-04, 8.43925356e-04,
       8.31382851e-04, 8.23722323e-04, 8.16643644e-04, 7.89875969e-04,
       7.86444549e-04, 7.42072946e-04, 7.36927617e-04, 7.27646949e-04,
       7.25004577e-04, 7.11071849e-04, 6.92833068e-04, 6.71807283e-04,
       6.68638321e-04, 6.56391013e-04, 6.51990243e-04, 6.49048818e-04,
       6.43397537e-04, 6.43118050e-04, 6.37839069e-04, 6.21864133e-04,
       6.06367626e-04, 5.99162639e-04, 5.87024289e-04, 5.74860663e-04,
       5.72519573e-04, 5.68447140e-04, 5.58806800e-04, 5.45711864e-04,
       5.37896691e-04, 5.34768852e-04, 5.20071483e-04, 5.18874875e-04,
       5.16054649e-04, 5.14388309e-04, 5.11931727e-04, 5.04227393e-04,
       5.00890900e-04, 4.97325634e-04, 4.75088970e-04, 4.66605249e-04,
       4.58324041e-04, 4.29127437e-04, 4.27514542e-04, 4.17186146e-04,
       4.16199437e-04, 3.94646924e-04, 3.94183167e-04, 3.86306652e-04,
       3.61812839e-04, 3.50841120e-04, 3.49059129e-04, 3.23402665e-04,
       3.22604151e-04, 3.11527347e-04, 3.10032877e-04, 3.07611603e-04,
       2.96010489e-04, 2.88197255e-04, 2.77494857e-04, 2.70735751e-04,
       2.67122244e-04, 2.64790886e-04, 2.64597695e-04, 2.63237166e-04,
       2.61362824e-04, 2.59399816e-04, 2.58614910e-04, 2.57579773e-04,
       2.49143242e-04, 2.49036616e-04, 2.47547306e-04, 2.36748821e-04,
       2.35282013e-04, 2.32245156e-04, 2.30209194e-04, 2.28229670e-04,
       2.27822992e-04, 2.20319919e-04, 2.17945603e-04, 2.13543715e-04,
       1.97145202e-04, 1.90526970e-04, 1.90304866e-04, 1.88393786e-04,
       1.85754127e-04, 1.85322815e-04, 1.81767370e-04, 1.74089940e-04,
       1.71644610e-04, 1.71039222e-04, 1.69557657e-04, 1.66839046e-04,
       1.64718022e-04, 1.59561636e-04, 1.57658164e-04, 1.54026397e-04,
       1.52211752e-04, 1.51115808e-04, 1.47564559e-04, 1.46841709e-04,
       1.36432949e-04, 1.35005671e-04, 1.32141796e-04, 1.27573620e-04,
       1.27432415e-04, 1.26388914e-04, 1.25919175e-04, 1.23965197e-04,
       1.21174483e-04, 1.18691292e-04, 1.18219114e-04, 1.17637524e-04,
       1.17526303e-04, 1.13037594e-04, 1.10863960e-04, 1.09331046e-04,
       1.08837112e-04, 1.06567401e-04, 1.05698197e-04, 1.00512685e-04,
       1.00106518e-04, 9.85814937e-05, 9.17495595e-05, 9.15174736e-05,
       9.09807382e-05, 8.79007001e-05, 8.16240791e-05, 7.91627682e-05,
       7.79158645e-05, 7.56940333e-05, 7.44394656e-05, 7.18101849e-05,
       6.97589276e-05, 6.81802488e-05, 6.69029567e-05, 6.54143249e-05,
       6.08786925e-05, 6.07607969e-05, 6.03570614e-05, 5.98994801e-05,
       5.95001291e-05, 5.94970869e-05, 5.86983574e-05, 5.79700512e-05,
       5.66119466e-05, 5.50952209e-05, 5.47453912e-05, 5.43839597e-05,
       5.25861529e-05, 4.89722417e-05, 4.78187439e-05, 4.77415865e-05,
       4.77107257e-05, 4.62616737e-05, 4.60653783e-05, 4.60409299e-05,
       4.56730211e-05, 4.54645078e-05, 4.52324283e-05, 4.38982745e-05,
       4.36906610e-05, 4.33593810e-05, 4.31226640e-05, 4.29912118e-05,
       4.29446346e-05, 4.17137339e-05, 3.93478837e-05, 3.84895449e-05,
       3.84390172e-05, 3.81834469e-05, 3.53827628e-05, 3.47222349e-05,
       3.37168917e-05, 3.18518637e-05, 3.15951703e-05, 3.12905207e-05,
       3.10605585e-05, 3.02567524e-05, 2.91709879e-05, 2.89567711e-05,
       2.85652293e-05, 2.82994071e-05, 2.80417376e-05, 2.77861205e-05,
       2.77303518e-05, 2.76273746e-05, 2.72172235e-05, 2.69880432e-05,
       2.66503046e-05, 2.66033916e-05, 2.62086568e-05, 2.59259584e-05,
       2.57640153e-05, 2.56299050e-05, 2.54449453e-05, 2.51909823e-05,
       2.47409597e-05, 2.46797892e-05, 2.42472084e-05, 2.35748710e-05,
       2.24438116e-05, 2.24317329e-05, 2.23097275e-05, 2.21249597e-05,
       2.17815183e-05, 2.15248592e-05, 2.09465192e-05, 2.09125513e-05,
       1.96913177e-05, 1.95330853e-05, 1.91064697e-05, 1.88952009e-05,
       1.85746459e-05, 1.81220081e-05, 1.78919334e-05, 1.73267658e-05,
       1.61874055e-05, 1.60765855e-05, 1.58740992e-05, 1.45486411e-05,
       1.40812264e-05, 1.36678429e-05, 1.32768479e-05, 1.31460479e-05,
       1.30872012e-05, 1.29588223e-05, 1.25748548e-05, 1.24146066e-05,
       1.22821602e-05, 1.22486357e-05, 1.20714645e-05, 1.20448925e-05,
       1.19866728e-05, 1.18936663e-05, 1.17590888e-05, 1.17001978e-05,
       1.16346360e-05, 1.11092945e-05, 1.08992577e-05, 1.06740258e-05,
       1.06735218e-05, 1.06144296e-05, 1.05679067e-05, 1.03656570e-05,
       1.03317955e-05, 9.98437559e-06, 9.01036943e-06, 8.85768061e-06,
       8.76035160e-06, 8.60019167e-06, 8.19227801e-06, 7.80479658e-06,
       7.53516931e-06, 7.44150882e-06, 7.30644125e-06, 7.26777599e-06,
       7.06747616e-06, 6.95177332e-06, 6.85925126e-06, 6.74132156e-06,
       6.71322068e-06, 6.70106994e-06, 6.66133186e-06, 6.47626505e-06,
       6.38130476e-06, 6.29576510e-06, 6.24612583e-06, 5.93271496e-06,
       5.92132104e-06, 5.83947722e-06, 5.76779879e-06, 5.76465728e-06,
       5.53187023e-06, 5.47131015e-06, 5.33180695e-06, 5.22417954e-06,
       5.20732008e-06, 5.15949060e-06, 5.11569104e-06, 4.95336950e-06,
       4.94557425e-06, 4.73636484e-06, 4.63955858e-06, 4.53340156e-06,
       4.22935422e-06, 4.19307790e-06, 4.17347414e-06, 4.12142146e-06,
       4.11855764e-06, 3.80541311e-06, 3.36707879e-06, 3.29563656e-06,
       3.17577578e-06, 3.05442971e-06, 2.98983688e-06, 2.97762691e-06,
       2.95066092e-06, 2.91720550e-06, 2.89840858e-06, 2.77497857e-06,
       2.76265227e-06, 2.74176112e-06, 2.70310579e-06, 2.61648976e-06,
       2.60275585e-06, 2.56616744e-06, 2.55465117e-06, 2.49712549e-06,
       2.42815484e-06, 2.37933375e-06, 2.35040476e-06, 2.33914845e-06,
       2.33036549e-06, 2.32978989e-06, 2.28930419e-06, 2.28804340e-06,
       2.26346210e-06, 2.24353844e-06, 2.23182640e-06, 2.23165865e-06,
       2.22696341e-06, 2.22115030e-06, 2.21572164e-06, 2.20668084e-06,
       2.19243658e-06, 2.17382266e-06, 2.08159887e-06, 2.07762818e-06,
       1.95415065e-06, 1.88693410e-06, 1.83219245e-06, 1.81431726e-06,
       1.67631850e-06, 1.67169206e-06, 1.63803449e-06, 1.57770706e-06,
       1.56577585e-06, 1.53130790e-06, 1.52519015e-06, 1.52439998e-06,
       1.49350905e-06, 1.47212210e-06, 1.45715861e-06, 1.40331777e-06,
       1.38641504e-06, 1.29786439e-06, 1.27069447e-06, 1.25613209e-06,
       1.23105569e-06, 1.22268909e-06, 1.21688094e-06, 1.18065108e-06,
       1.18060143e-06, 1.16794389e-06, 1.13216621e-06, 1.12716419e-06,
       1.12418866e-06, 1.12412659e-06, 1.05684621e-06, 1.05049722e-06,
       1.04986594e-06, 1.03676402e-06, 1.03482230e-06, 9.96847192e-07,
       9.75926251e-07, 9.54397081e-07, 9.36101632e-07, 9.30100914e-07,
       9.27467975e-07, 8.92801774e-07, 8.85217179e-07, 8.58891337e-07,
       7.80484800e-07, 7.67724409e-07, 7.54031637e-07, 7.45052550e-07,
       7.32511689e-07, 7.06828122e-07, 6.59585949e-07, 6.40055245e-07,
       6.18628925e-07, 6.17142222e-07, 6.09904832e-07, 6.07242457e-07,
       5.72270900e-07, 5.49823535e-07, 5.22568859e-07, 5.01838721e-07,
       4.91372576e-07, 4.82981856e-07, 4.69688423e-07, 4.59727658e-07,
       4.54795508e-07, 4.22875379e-07, 4.13494116e-07, 3.99834682e-07,
       3.97288987e-07, 3.87644926e-07, 3.84245584e-07, 3.81268632e-07,
       3.67029696e-07, 3.57267536e-07, 3.52642869e-07, 3.51058992e-07,
       3.44112772e-07, 3.36167495e-07, 3.24215712e-07, 3.23810344e-07,
       3.21814716e-07, 3.21505459e-07, 3.10936465e-07, 2.88018831e-07,
       2.86309762e-07, 2.76140106e-07, 2.63218703e-07, 2.56899508e-07,
       2.51244222e-07, 2.25386521e-07, 2.15766576e-07, 2.03018243e-07,
       1.99078411e-07, 1.97551987e-07, 1.96981706e-07, 1.92415912e-07,
       1.84391194e-07, 1.81253585e-07, 1.78663913e-07, 1.77747846e-07,
       1.59541769e-07, 1.38003378e-07, 1.36499298e-07, 1.22889160e-07,
       1.22576357e-07, 1.19711121e-07, 1.09597855e-07, 9.97477409e-08,
       9.65292710e-08, 9.36271510e-08, 9.35785637e-08, 9.34540807e-08,
       8.40270671e-08, 7.82629028e-08, 7.54898762e-08, 6.64058115e-08,
       5.96748649e-08, 5.79118882e-08, 5.73650143e-08, 5.65688198e-08,
       5.34673852e-08, 5.34237630e-08, 5.29956976e-08, 4.84174907e-08,
       3.83818937e-08])
```

## Speed matrix  <a name="speed">
### 24x24 relative Speed matrix between key pair (averaged for left/right symmetry)

  - does not take into account order of key pairs (see Flow24x24 matrix)
  - the original version was constructed with data from right-handed people
  - 24 keys that don't require extending index or little fingers ("vertical range keys")

### Vertical range keys

        Left:            Right:
     1  2  3  4       13 14 15 16
     5  6  7  8       17 18 19 20
     9 10 11 12       21 22 23 24

Interkey stroke times in milliseconds from Table 3 of <br>
"Estimation of digraph costs for keyboard layout optimization", <br>
A Iseri, Ma Eksioglu, International Journal of Industrial Ergonomics, 48, 127-138, 2015. <br>
Key numbering in article and in spreadsheet:

         Left:           Right:
     1 4 7 10 13   16 19 22 25 28 31
     2 5 8 11 14   17 20 23 26 29 32
     3 6 9 12 15   18 21 24 27 30

### Load table of interkey speeds

```python
load_original_interkey_timings_table = False
if load_original_interkey_timings_table:

    interkey_table = "data/interkey-timings.xlsx"
    wb = xlrd.open_workbook(interkey_table)
    interkey_sheet = wb.sheet_by_index(0)

    # Convert interkey stroke times table to array:
    Time32x32 = np.zeros((32,32))
    for i in range(1,33):
        for j in range(1,33):
            if interkey_sheet.cell_value(i,j):
                Time32x32[i-1,j-1] = interkey_sheet.cell_value(i,j)

    # Fill empty (symmetric) portion of the array:
    for i in range(1,33):
        for j in range(1,33):
            if interkey_sheet.cell_value(i,j):
                Time32x32[j-1,i-1] = interkey_sheet.cell_value(i,j)

    # Extract pairwise entries for the 24 vertical range keys:
    table_24_positions = [1,4,7,10, 2,5,8,11, 3,6,9,12,  19,22,25,28, 20,23,26,29, 21,24,27,30]
    Time24x24 = np.zeros((24, 24))
    u = 0
    for i in table_24_positions:
        u += 1
        v = 0
        for j in table_24_positions:
            v += 1
            Time24x24[u-1,v-1] = Time32x32[i-1,j-1]

    # Save:
    if print_output:
        file = open("Time24x24.txt", "w+")
        file.write(str(Time24x24))
        file.close()

    # Print:
    print(repr(Time24x24))

else:
    Time24x24 = np.array([[196., 225., 204., 164., 266., 258., 231., 166., 357., 325., 263.,
        186., 169., 176., 178., 186., 156., 156., 158., 163., 171., 175., 177., 185.],
       [225., 181., 182., 147., 239., 245., 196., 150., 289., 296., 229.,
        167., 162., 169., 170., 178., 148., 148., 150., 155., 163., 167., 169., 177.],
       [204., 182., 170., 149., 196., 194., 232., 155., 237., 214., 263.,
        166., 157., 164., 165., 173., 143., 143., 145., 150., 158., 163., 164., 172.],
       [164., 147., 149., 169., 160., 161., 157., 226., 165., 185., 234.,
        257., 154., 162., 163., 171., 141., 141., 143., 148., 156., 160., 162., 170.],
       [266., 239., 196., 160., 196., 240., 208., 166., 271., 267., 208.,
        169., 143., 150., 151., 160., 129., 129., 132., 137., 145., 149., 151., 159.],
       [258., 245., 194., 161., 240., 181., 183., 149., 245., 256., 184.,
        150., 138., 145., 146., 154., 124., 124., 126., 131., 139., 144., 145., 153.],
       [231., 196., 232., 157., 208., 183., 170., 149., 201., 215., 239.,
        151., 134., 141., 142., 150., 120., 120., 122., 127., 135., 140., 141., 149.],
       [166., 150., 155., 226., 166., 149., 149., 169., 160., 147., 170.,
        221., 133., 140., 141., 150., 119., 119., 122., 126., 135., 139., 141., 149.],
       [357., 289., 237., 165., 271., 245., 201., 160., 196., 236., 194.,
        161., 171., 178., 179., 188., 157., 157., 160., 164., 173., 177., 179., 187.],
       [325., 296., 214., 185., 267., 256., 215., 147., 236., 181., 184.,
        157., 166., 173., 174., 182., 152., 152., 154., 159., 167., 172., 173., 181.],
       [263., 229., 263., 234., 208., 184., 239., 170., 194., 184., 170.,
        150., 159., 166., 167., 176., 145., 145., 148., 153., 161., 165., 167., 175.],
       [186., 167., 166., 257., 169., 150., 151., 221., 161., 157., 150.,
        169., 153., 160., 161., 169., 139., 139., 141., 146., 154., 159., 160., 168.],
       [169., 162., 157., 154., 143., 138., 134., 133., 171., 166., 159.,
        153., 151., 147., 141., 145., 188., 151., 142., 164., 213., 204., 162., 145.],
       [176., 169., 164., 162., 150., 145., 141., 140., 178., 173., 166.,
        160., 147., 151., 189., 209., 137., 207., 191., 206., 149., 227.,  208., 226.],
       [178., 170., 165., 163., 151., 146., 142., 141., 179., 174., 167.,
        161., 141., 189., 157., 253., 136., 188., 210., 231., 155., 226.,   239., 225.],
       [186., 178., 173., 171., 160., 154., 150., 150., 188., 182., 176.,
        169., 145., 209., 253., 170., 147., 206., 251., 233., 164., 268.,  362., 236.],
       [156., 148., 143., 141., 129., 124., 120., 119., 157., 152., 145.,
        139., 188., 137., 136., 147., 151., 133., 138., 152., 192., 149.,  139., 143.],
       [156., 148., 143., 141., 129., 124., 120., 119., 157., 152., 145.,
        139., 151., 207., 188., 206., 133., 151., 179., 183., 145., 204.,  183., 194.],
       [158., 150., 145., 143., 132., 126., 122., 122., 160., 154., 148.,
        141., 142., 191., 210., 251., 138., 179., 157., 240., 145., 185.,  208., 235.],
       [163., 155., 150., 148., 137., 131., 127., 126., 164., 159., 153.,
        146., 164., 206., 231., 233., 152., 183., 240., 170., 160., 220.,  293., 230.],
       [171., 163., 158., 156., 145., 139., 135., 135., 173., 167., 161.,
        154., 213., 149., 155., 164., 192., 145., 145., 160., 151., 140.,  142., 175.],
       [175., 167., 163., 160., 149., 144., 140., 139., 177., 172., 165.,
        159., 204., 227., 226., 268., 149., 204., 185., 220., 140., 151.,  175., 265.],
       [177., 169., 164., 162., 151., 145., 141., 141., 179., 173., 167.,
        160., 162., 208., 239., 362., 139., 183., 208., 293., 142., 175.,  157., 265.],
       [185., 177., 172., 170., 159., 153., 149., 149., 187., 181., 175.,
        168., 145., 226., 225., 236., 143., 194., 235., 230., 175., 265.,  265., 170.]])

# Left/right symmetric version of the Time24x24 matrix
# (The original version was constructed with data from right-handed people.)
TimeSymmetric24x24 = np.ones((24,24))

#        Left:            Right:
#     1  2  3  4       13 14 15 16
#     5  6  7  8       17 18 19 20
#     9 10 11 12       21 22 23 24

I = [1,2,3,4, 5,6,7,8, 9,10,11,12,  16,15,14,13, 20,19,18,17, 24,23,22,21]
J = [16,15,14,13, 20,19,18,17, 24,23,22,21,  1,2,3,4, 5,6,7,8, 9,10,11,12]

for i1, I1 in enumerate(I):
    for i2, I2 in enumerate(I):
        J1 = J[i1] - 1
        J2 = J[i2] - 1
        #print(i1,i2,I1-1,I2-1,J1,J2)
        avgvalue = (Time24x24[I1-1,I2-1] + Time24x24[J1,J2]) / 2
        TimeSymmetric24x24[I1-1,I2-1] = avgvalue
        TimeSymmetric24x24[J1,J2] = avgvalue

# Normalize matrix with min-max scaling to a range with maximum = 1:
newMin = np.min(TimeSymmetric24x24) / np.max(TimeSymmetric24x24)
newMax = 1.0
TimeSymmetric24x24 = newMin + (TimeSymmetric24x24 - np.min(TimeSymmetric24x24)) * (newMax - newMin) / (np.max(TimeSymmetric24x24) - np.min(TimeSymmetric24x24))

# Convert relative interkey stroke times to relative speeds by subtracting from 1:
Speed24x24 = 1 - TimeSymmetric24x24 + np.min(TimeSymmetric24x24)

# Print:
print_matrix_info(matrix_data=Speed24x24, matrix_label="Speed24x24", nkeys=24, nlines=50)
heatmap(data=Speed24x24, title="Speed24x24", xlabel="Key 1", ylabel="Key 2", print_output=print_output)

# Print:
#print(repr(Speed24x24))

# Save:
if print_output:
    file = open("Speed24x24.txt", "w+")
    file.write(str(Speed24x24))
    file.close()

```

## Strength matrix  <a name="strength">

### 24x24 relative finger position STRENGTH matrix

Finger strengths are based on peak keyboard reaction forces (in newtons) from Table 4 of <br>
"Keyboard Reaction Force and Finger Flexor Electromyograms during Computer Keyboard Work" <br>
BJ Martin, TJ Armstrong, JA Foulke, S Natarajan, Human Factors,1996,38(4),654-664:

    middle     2.36
    index      2.26
    ring       2.02
    little     1.84

    2.36/1.84 = 1.28
    2.36/2.02 = 1.17

For reference, Table 1 of "Ergonomic keyboard layout designed for the Filipino language", 2016 (doi: 10.1007/978-3-319-41694-6_41) presents "average finger strength of Filipinos [n=30, ages 16-36] measured in pounds":

                L       R
    little     3.77   4.27
    ring       4.54   5.08
    middle     5.65   6.37
    index      6.09   6.57

    6.57/4.27 = 1.54
    6.09/3.77 = 1.62
    6.37/5.08 = 1.25
    5.65/4.54 = 1.24

We won't use these results as I don't feel they represent relative strength relevant for typing: "Respondents were asked to sit in upright position, with their wrists resting on a flat surface. A pinch gauge was placed within each finger's reach. The respondents were asked to exert maximum pressure on the device."

The following does not take into account order of key pairs (see Flow matrix).

```python
if apply_strength:

    # Normalize by the highest peak force (middle finger):
    middle_force = 2.36
    index_force = 2.26
    ring_force = 2.02
    little_force = 1.84
    middle_norm = 1.0
    index_norm = index_force / middle_force
    ring_norm = ring_force / middle_force
    little_norm = little_force / middle_force
    print('index/middle: {0}'.format(index_norm))
    print('ring/middle: {0}'.format(ring_norm))
    print('little/middle: {0}'.format(little_norm))

    # Relative left/right hand strength (assume equal):
    lf = 1.0
    rf = 1.0

    strengths24 = np.array((
                        lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,
                        lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,
                        lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,
                        rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm,
                        rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm,
                        rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm))

    # Create a finger-pair position strength matrix by adding pairs of strength values:
    Strength24x24 = np.zeros((24, 24))
    for i in range(24):
        Strength24x24[i,:] = strengths24
    Strength24x24 = (Strength24x24 + Strength24x24.transpose())

    # Normalize matrix with min-max scaling to a range with maximum = 1:
    #newMin = strength_factor
    newMin = min_strength_factor  # np.min(Strength24x24) / np.max(Strength24x24)
    newMax = 1.0
    Strength24x24 = newMin + (Strength24x24 - np.min(Strength24x24)) * (newMax - newMin) / (np.max(Strength24x24) - np.min(Strength24x24))

    # Print:
    print_matrix_info(matrix_data=Strength24x24, matrix_label="Strength24x24", nkeys=24, nlines=10)
    heatmap(data=Strength24x24, title="Strength24x24", xlabel="Key 1", ylabel="Key 2", print_output=print_output)

    # Save:
    if print_output:
        file = open("Strength24x24.txt", "w+")
        file.write(str(Strength24x24))
        file.close()
```

```python
if apply_strength:

    penalty = 1.0  # Penalty for lateral (index, little) finger placement (1 = no penalty)

    strengths32 = np.array((lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,
                            lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,
                            lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,
                            rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm,
                            rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm,
                            rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm,
                            lf * index_norm * penalty, lf * index_norm * penalty, lf * index_norm * penalty,
                            rf * index_norm * penalty, rf * index_norm * penalty, rf * index_norm * penalty,
                            rf * little_norm * penalty, rf * little_norm * penalty))

    # Create a finger-pair position strength matrix by adding pairs of strength values:
    Strength32x32 = np.zeros((32, 32))
    for i in range(32):
        Strength32x32[i,:] = strengths32
    Strength32x32 = (Strength32x32 + Strength32x32.transpose())

    # Normalize matrix with min-max scaling to a range with maximum = 1:
    newMin = np.min(Strength32x32) / np.max(Strength32x32)
    newMax = 1.0
    Strength32x32 = newMin + (Strength32x32 - np.min(Strength32x32)) * (newMax - newMin) / (np.max(Strength32x32) - np.min(Strength32x32))

    # Print:
    print_matrix_info(matrix_data=Strength32x32, matrix_label="Strength32x32", nkeys=32, nlines=10)
    heatmap(data=Strength32x32, title="Strength32x32", xlabel="Key 1", ylabel="Key 2", print_output=print_output)

    # Save:
    if print_output:
        file = open("Strength32x32.txt", "w+")
        file.write(str(Strength32x32))
        file.close()
```

## Flow matrix and Engram scoring model  <a name="flow">

The Flow24x24 matrix takes into account ease of transition between ordered pairs of keys.

Our optimization algorithm finds every permutation of a given set of letters, maps these letter permutations to a set of keys, and ranks these letter-key mappings according to a score reflecting ease of typing key pairs and frequency of letter pairs (bigrams). The score is the average of the scores for all possible bigrams in this arrangement. The score for each bigram is a product of the frequency of occurrence of that bigram, the frequency of each of the bigram’s characters, and flow, strength (and optional speed) factors for the key pair.

#### Dvorak et al. (1936) defined eleven criteria for the design and evaluation of keyboard layouts:
1.  Deviation from the balance of hand and finger loads should be as low as possible.
2.  Percentage of tapping with the same fingers should be as low as possible.
3.  Percentage of tapping that includes top row should be as low as possible.
4.  Percentage of tapping that includes bottom row should be as low as possible.
5.  Percentage of tapping in the home row should be as high as possible.
6.  Percentage of tapping by alternating hands should be as high as possible.
7.  Percentage of hurdles with the same finger should be as low as possible.
8.  Percentage of hurdles with adjacent offset fingers should be as low as possible.
9.  Percentage of hurdles with remote fingers should be as low as possible.
10. Percentage of reach with the same finger should be as low as possible.
11. Percentage of reach with adjacent offset fingers should be as low as possible.

#### Synopsis of above criteria for pairwise key presses when touch typing:
1. Alternate between hands.
2. Balance finger loads, and avoid using the same finger.
3. Avoid the upper and lower rows, and avoid skipping over the home row.
4. Avoid tapping adjacent offset rows with the same or adjacent offset fingers.

### Factors to penalize strenuous key transitions

Direction:

    - outward = 0.9: outward roll of fingers from the index to little finger (same hand)

Dexterity:

    - side_above_3away = 0.9
        - index and little finger type two keys, one or more rows apart (same hand)
    - side_above_2away = 0.9^2 = 0.81
        - index finger types key a row or two above ring finger key, or
        - little finger types key a row or two above middle finger key (same hand)
    - side_above_1away = 0.9^3 = 0.729
        - index finger types key a row or two above middle finger key, or
        - little finger types key a row or two above ring finger key (same hand)
    - middle_above_ring = 0.9
        - middle finger types key a row or two above ring finger key (same hand)
    - ring_above_middle = 0.9^3 = 0.729
        - ring finger types key a row or two above middle finger key (same hand)
    - lateral = 0.9
        - lateral movement of (index or little) finger outside of 8 vertical columns

Distance:

    - skip_row_3away = 0.9
        - index and little fingers type two keys that skip over home row (same hand)
        - (e.g., one on bottom row, the other on top row)
    - skip_row_2away = 0.9^3 = 0.729
        - little and middle or index and ring fingers type two keys that skip over home row (same hand)
    - skip_row_1away = 0.9^5 = 0.59049
        - little and ring or middle and index fingers type two keys that skip over home row (same hand)

Repetition:

    - skip_row_0away = 0.9^4 = 0.6561
        - same finger types two keys that skip over home row
    - same_finger = 0.9^5 = 0.59049
        - use same finger again for a different key
        - cannot accompany outward, side_above, or adjacent_shorter_above

Strength: Accounted for by the strength matrix (minimum value for the little finger = 0.9)

```python
# Penalizing factors for 24 keys  (1 = no penalty; set to less than 1 to penalize):

# Dexterity
side_above_3away = 0.9     # index and little finger type two keys, one or more rows apart (same hand)
side_above_2away = 0.81    # index finger types key a row or two above ring finger key, or
                           # little finger types key a row or two above middle finger key (same hand)
side_above_1away = 0.729   # index finger types key a row or two above middle finger key, or
                           # little finger types key a row or two above ring finger key (same hand)
middle_above_ring = 0.9    # middle finger types key a row or two above ring finger key (same hand)
ring_above_middle = 0.729  # ring finger types key a row or two above middle finger key (same hand)
lateral = 0.9              # lateral movement of (index or little) finger outside of 8 vertical columns

# Direction
outward = 0.9              # outward roll of fingers from the index to little finger (same hand)

# Distance
skip_row_3away = 0.9       # index and little fingers type two keys that skip over home row (same hand)
                           # (e.g., one on bottom row, the other on top row)
skip_row_2away = 0.729     # little and middle or index and ring fingers type two keys that skip over home row (same hand)
skip_row_1away = 0.59049   # little and ring or middle and index fingers type two keys that skip over home row (same hand)

# Repetition
skip_row_0away = 0.6561    # same finger types two keys that skip over home row
same_finger = 0.59049      # use same finger again for a different key

# Unused or redundant parameters
same_hand = 1.0            # (addressed by splitting up the most frequent letters across left/right sides above)
not_home_row = 1.0         # at least one key not on home row
side_top = 1.0             # index or little finger types top corner key
shorter_above = 1.0        # (taken care of by side_above_[1,2,3]away parameters)
adjacent_offset = 1.0      # (taken care of by side_above_1away, middle_above_ring, ring_above_middle parameters)
inside_top = 1.0           # index finger types top corner key (taken care of by side_above_1away parameter)
index_above = 1.0          # index finger types top corner key (unless other bigram key is in the top row for the same hand)
                           # (taken care of by side_above_[1,2,3]away parameters)
```

#### 24 keys:

```python
def create_24x24_flow_matrix(not_home_row, side_top, side_above_3away, side_above_2away, side_above_1away,
                             middle_above_ring, ring_above_middle, outward, skip_row_3away,
                             skip_row_2away, skip_row_1away, skip_row_0away, same_finger, lateral,
                             same_hand, shorter_above, adjacent_offset, inside_top, index_above):

    all_24_keys = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, 17,18,19,20, 21,22,23,24]

    # Create a matrix and multiply by flow factors that promote easy interkey transitions:
    T = np.ones((24, 24))

    # 7.  Promote alternating between hands over uncomfortable transitions with the same hand.
    if same_hand < 1.0:
    #    1  2  3  4   13 14 15 16
    #    5  6  7  8   17 18 19 20
    #    9 10 11 12   21 22 23 24
        for i in range(0,12):
            for j in range(0,12):
                T[i,j] *= same_hand
        for i in range(12,24):
            for j in range(12,24):
                T[i,j] *= same_hand

    # 8.  Promote little-to-index-finger roll-ins over index-to-little-finger outwards.
    #    1  2  3  4   13 14 15 16
    #    5  6  7  8   17 18 19 20
    #    9 10 11 12   21 22 23 24
    if outward < 1.0:

        # same-row roll-outs:
        roll_ins = [[1,2],[2,3],[3,4], [5,6],[6,7],[7,8], [9,10],[10,11],[11,12],
                    [16,15],[15,14],[14,13], [20,19],[19,18],[18,17], [24,23],[23,22],[22,21]]
        for x in roll_ins:
            T[x[1]-1, x[0]-1] *= outward

        # same-row roll-outs, skipping keys:
        roll_ins_skip_keys = [[1,3],[2,4],[1,4], [5,7],[6,8],[5,8], [9,11],[10,12],[9,12],
                              [16,14],[15,13],[16,13], [20,18],[19,17],[20,17], [24,22],[23,21],[24,21]]
        for x in roll_ins_skip_keys:
            T[x[1]-1, x[0]-1] *= outward

        # adjacent-row roll-outs:
        roll_ins_adj_rows = [[1,6],[1,7],[1,8],[2,7],[2,8],[3,8], [5,2],[5,3],[5,4],[6,3],[6,4],[7,4],
                             [5,10],[5,11],[5,12],[6,11],[6,12],[7,12], [9,6],[9,7],[9,8],[10,7],[10,8],[11,8],
                             [16,19],[16,18],[16,17],[15,18],[15,17],[14,17], [20,15],[20,14],[20,13],[19,14],[19,13],[18,13],
                             [20,23],[20,22],[20,21],[19,22],[19,21],[18,21], [24,19],[24,18],[24,17],[23,18],[23,17],[22,17]]
        for x in roll_ins_adj_rows:
            T[x[1]-1, x[0]-1] *= outward

        # upper<->lower row roll-outs:
        roll_ins_skip_home = [[1,10],[1,11],[1,12],[2,11],[2,12],[3,12], [9,2],[9,3],[9,4],[10,3],[10,4],[11,4],
                              [16,23],[16,22],[16,21],[15,22],[15,21],[14,21], [24,15],[24,14],[24,13],[23,14],[23,13],[22,13]]
        for x in roll_ins_skip_home:
            T[x[1]-1, x[0]-1] *= outward

    # 9.  Avoid stretching shorter fingers up and longer fingers down.
    #    1  2  3  4   13 14 15 16
    #    5  6  7  8   17 18 19 20
    #    9 10 11 12   21 22 23 24
    if index_above < 1.0:
        for x in [4]:
            for y in [4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]:
                T[x-1, y-1] *= index_above
                T[y-1, x-1] *= index_above
        for x in [13]:
            for y in [1,2,3,4,5,6,7,8,9,10,11,12,13,17,18,19,20,21,22,23,24]:
                T[x-1, y-1] *= index_above
                T[y-1, x-1] *= index_above
    if inside_top < 1.0:
        for x in [4,13]:
            for j in range(0,24):
                T[x-1, j] *= inside_top
                T[j, x-1] *= inside_top
    if side_top < 1.0:
        for x in [1,4,13,16]:
            for j in range(0,24):
                T[x-1, j] *= side_top
                T[j, x-1] *= side_top
    if side_above_1away < 1.0:
        for x in [1]:
            for y in [6,10]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [5]:
            for y in [10]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [4]:
            for y in [7,11]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [8]:
            for y in [11]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [13]:
            for y in [18,22]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [17]:
            for y in [22]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [16]:
            for y in [19,23]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [20]:
            for y in [23]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
    if side_above_2away < 1.0:
        for x in [1]:
            for y in [7,11]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [5]:
            for y in [11]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [4]:
            for y in [6,10]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [8]:
            for y in [10]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [13]:
            for y in [19,23]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [17]:
            for y in [23]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [16]:
            for y in [18,22]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [20]:
            for y in [22]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
    if side_above_3away < 1.0:
        for x in [1]:
            for y in [8,12]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [5]:
            for y in [12]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [4]:
            for y in [5,9]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [8]:
            for y in [9]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [13]:
            for y in [20,24]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [17]:
            for y in [24]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [16]:
            for y in [17,21]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [20]:
            for y in [21]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
    if shorter_above < 1.0:
        for x in [1]:
            for y in [6,7,8,10,11,12]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [2]:
            for y in [7,11]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [4]:
            for y in [6,7,10,11]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above

        for x in [5]:
            for y in [10,11,12]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [6]:
            for y in [11]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [8]:
            for y in [10,11]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above

        for x in [16]:
            for y in [17,18,19,21,22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [15]:
            for y in [18,22]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [13]:
            for y in [18,19,22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above

        for x in [20]:
            for y in [21,22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [19]:
            for y in [22]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [17]:
            for y in [22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above

    if ring_above_middle < 1.0:
        ring_above_middles =  [[2,7],[6,11],[2,11],
                            [15,18],[19,22],[15,22]]
        for x in ring_above_middles:
            T[x[0]-1, x[1]-1] *= ring_above_middle
            T[x[1]-1, x[0]-1] *= ring_above_middle

    if middle_above_ring < 1.0:
        middle_above_rings =  [[6,3],[10,7],[10,3],
                            [19,14],[23,18],[23,14]]
        for x in middle_above_rings:
            T[x[0]-1, x[1]-1] *= middle_above_ring
            T[x[1]-1, x[0]-1] *= middle_above_ring

    # 10. Avoid using the same finger.
    #    1  2  3  4   13 14 15 16
    #    5  6  7  8   17 18 19 20
    #    9 10 11 12   21 22 23 24
    if same_finger < 1.0:
        same_fingers = [[1,5],[5,9],[1,9], [2,6],[6,10],[2,10], [3,7],[7,11],[3,11], [4,8],[8,12],[4,12],
                        [13,17],[17,21],[13,21], [14,18],[18,22],[14,22], [15,19],[19,23],[15,23], [16,20],[20,24],[16,24]]
        for x in same_fingers:
            T[x[0]-1, x[1]-1] *= same_finger
            T[x[1]-1, x[0]-1] *= same_finger

    # 11. Avoid the upper and lower rows.
    #    1  2  3  4   13 14 15 16
    #    5  6  7  8   17 18 19 20
    #    9 10 11 12   21 22 23 24
    if not_home_row < 1.0:
        not_home_row_keys = [1,2,3,4, 9,10,11,12, 13,14,15,16, 21,22,23,24]
        for x in not_home_row_keys:
            for j in range(0,23):
                T[x-1, j] *= not_home_row
                T[j, x-1] *= not_home_row

    # 12. Avoid skipping over the home row.
    #    1  2  3  4   13 14 15 16
    #    5  6  7  8   17 18 19 20
    #    9 10 11 12   21 22 23 24
    if skip_row_0away < 1.0:
        skip_top = [1, 2, 3, 4, 13,14,15,16]
        skip_bot = [9,10,11,12, 21,22,23,24]
        for ix, x in enumerate(skip_top):
            y = skip_bot[ix]
            T[x-1, y-1] *= skip_row_0away
            T[y-1, x-1] *= skip_row_0away
    if skip_row_1away < 1.0:
        skip_top = [1, 2, 2, 3, 3, 4, 13,14,14,15,15,16]
        skip_bot = [10,9,11,10,12,11, 22,21,23,22,24,23]
        for ix, x in enumerate(skip_top):
            y = skip_bot[ix]
            T[x-1, y-1] *= skip_row_1away
            T[y-1, x-1] *= skip_row_1away
    if skip_row_2away < 1.0:
        skip_top = [1,  2,3, 4, 13,14,15,16]
        skip_bot = [11,12,9,10, 23,24,21,22]
        for ix, x in enumerate(skip_top):
            y = skip_bot[ix]
            T[x-1, y-1] *= skip_row_2away
            T[y-1, x-1] *= skip_row_2away
    if skip_row_3away < 1.0:
        skip_top = [1, 4, 13,16]
        skip_bot = [12,9, 24,21]
        for ix, x in enumerate(skip_top):
            y = skip_bot[ix]
            T[x-1, y-1] *= skip_row_3away
            T[y-1, x-1] *= skip_row_3away

    Flow24x24 = T

    # Normalize matrix with min-max scaling to a range with maximum = 1:
    newMin = np.min(Flow24x24) / np.max(Flow24x24)
    newMax = 1.0
    Flow24x24 = newMin + (Flow24x24 - np.min(Flow24x24)) * (newMax - newMin) / (np.max(Flow24x24) - np.min(Flow24x24))

    return Flow24x24

Flow24x24 = create_24x24_flow_matrix(not_home_row, side_top,
    side_above_3away, side_above_2away, side_above_1away, middle_above_ring, ring_above_middle, outward,
    skip_row_3away, skip_row_2away, skip_row_1away, skip_row_0away, same_finger, lateral, same_hand,
    shorter_above, adjacent_offset, inside_top, index_above)

# Print:
print_matrix_info(matrix_data=Flow24x24, matrix_label="Flow24x24", nkeys=24, nlines=30)
heatmap(data=Flow24x24, title="Flow24x24", xlabel="Key 1", ylabel="Key 2", print_output=print_output)

# Save:
if print_output:
    file = open("Flow24x24.txt", "w+")
    file.write(str(Flow24x24))
    file.close()

#    1  2  3  4   13 14 15 16
#    5  6  7  8   17 18 19 20
#    9 10 11 12   21 22 23 24
```

#### 32 keys:

         Left:             Right:
     1  2  3  4 25   28 13 14 15 16 31
     5  6  7  8 26   29 17 18 19 20 32
     9 10 11 12 27   30 21 22 23 24

```python
def create_32x32_flow_matrix(not_home_row, side_top, side_above_3away, side_above_2away, side_above_1away,
                             middle_above_ring, ring_above_middle, outward, skip_row_3away,
                             skip_row_2away, skip_row_1away, skip_row_0away, same_finger, lateral,
                             same_hand, shorter_above, adjacent_offset, inside_top, index_above):

    all_32_keys = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, 17,18,19,20, 21,22,23,24,
                   25,26,27, 28,29,30, 31,32]

    # Create a matrix and multiply by flow factors that promote easy interkey transitions:
    T = np.ones((32, 32))

    if lateral < 1.0:
        for x in all_32_keys:
            for y in [25,26,27, 28,29,30, 31,32]:
                T[x-1, y-1] *= lateral
                T[y-1, x-1] *= lateral

    # 7.  Promote alternating between hands over uncomfortable transitions with the same hand.
    if same_hand < 1.0:
        for i in [1,2,3,4,5,6,7,8,9,10,11,12, 25,26,27]:
            for j in [1,2,3,4,5,6,7,8,9,10,11,12, 25,26,27]:
                T[i-1,j-1] *= same_hand
        for i in [13,14,15,16,17,18,19,20,21,22,23,24, 28,29,30,31,32]:
            for j in [13,14,15,16,17,18,19,20,21,22,23,24, 28,29,30,31,32]:
                T[i-1,j-1] *= same_hand

    # 8.  Promote little-to-index-finger roll-ins over index-to-little-finger outsward rolls.
    # Penalize (index, little) finger lateral movements:
    #  1  2  3  4 25   28 13 14 15 16 31
    #  5  6  7  8 26   29 17 18 19 20 32
    #  9 10 11 12 27   30 21 22 23 24
    if outward < 1.0:

        # same-row roll-outs:
        roll_ins = [[1,2],[2,3],[3,4], [5,6],[6,7],[7,8], [9,10],[10,11],[11,12],
                    [4,25],[8,26],[12,27],
                    [16,15],[15,14],[14,13], [20,19],[19,18],[18,17], [24,23],[23,22],[22,21],
                    [13,28],[17,29],[21,30], [31,16],[32,20]]
        for x in roll_ins:
            T[x[1]-1, x[0]-1] *= outward

        # same-row roll-outs, skipping keys:
        roll_ins_skip_keys = [[1,3],[2,4],[1,4], [5,7],[6,8],[5,8], [9,11],[10,12],[9,12],
                              [1,25],[2,25],[3,25],
                              [5,26],[6,26],[7,26],
                              [9,27],[10,27],[11,27],
                              [16,14],[15,13],[16,13], [20,18],[19,17],[20,17], [24,22],[23,21],[24,21],
                              [16,28],[15,28],[14,28],
                              [20,29],[19,29],[18,29],
                              [24,30],[23,30],[22,30],
                              [31,15],[31,14],[31,13],[31,28],
                              [32,19],[32,18],[32,17],[32,29]]
        for x in roll_ins_skip_keys:
            T[x[1]-1, x[0]-1] *= outward

        # adjacent-row roll-outs:
        #  1  2  3  4 25   28 13 14 15 16 31
        #  5  6  7  8 26   29 17 18 19 20 32
        #  9 10 11 12 27   30 21 22 23 24
        roll_ins_adj_rows = [[1,6],[1,7],[1,8],[2,7],[2,8],[3,8],
                             [5,2],[5,3],[5,4],[6,3],[6,4],[7,4],
                             [5,10],[5,11],[5,12],[6,11],[6,12],[7,12],
                             [9,6],[9,7],[9,8],[10,7],[10,8],[11,8],
                             [5,25],[6,25],[7,25],[8,25],
                             [5,27],[6,27],[7,27],[8,27],
                             [1,26],[2,26],[3,26],[4,26],
                             [9,26],[10,26],[11,26],[12,26],
                             [16,19],[16,18],[16,17],[15,18],[15,17],[14,17],
                             [20,15],[20,14],[20,13],[19,14],[19,13],[18,13],
                             [20,23],[20,22],[20,21],[19,22],[19,21],[18,21],
                             [24,19],[24,18],[24,17],[23,18],[23,17],[22,17],
                             [16,29],[15,29],[14,29],[13,29],
                             [24,29],[23,29],[22,29],[21,29],
                             [20,28],[19,28],[18,28],[17,28],
                             [20,30],[19,30],[18,30],[17,30],
                             [31,20],[31,19],[31,18],[31,17],[31,29],
                             [32,16],[32,15],[32,14],[32,13],[32,28],
                             [32,24],[32,23],[32,22],[32,21],[32,30]]
        for x in roll_ins_adj_rows:
            T[x[1]-1, x[0]-1] *= outward

        # upper<->lower row roll-outs:
        roll_ins_skip_home = [[1,10],[1,11],[1,12],[1,27],[2,11],[2,12],[2,27],[3,12],[3,27],[4,27],
                              [9,2],[9,3],[9,4],[9,25],[10,3],[10,4],[10,25],[11,4],[11,25],[12,25],
                              [16,23],[16,22],[16,21],[16,30],[15,22],[15,21],[15,30],[14,21],[14,30],[13,30],
                              [24,15],[24,14],[24,13],[24,28],[23,14],[23,13],[23,28],[22,13],[22,28],[21,28],
                              [31,24],[31,23],[31,22],[31,21],[31,30]]
        for x in roll_ins_skip_home:
            T[x[1]-1, x[0]-1] *= outward

    # 9.  Avoid stretching shorter fingers up and longer fingers down.
    #  1  2  3  4 25   28 13 14 15 16 31
    #  5  6  7  8 26   29 17 18 19 20 32
    #  9 10 11 12 27   30 21 22 23 24
    if index_above < 1.0:
        for x in [4]:
            for y in [4,5,6,7,8,26,9,10,11,12,27,28,13,14,15,16,31,29,17,18,19,20,32,30,21,22,23,24]:
                T[x-1, y-1] *= index_above
                T[y-1, x-1] *= index_above
        for x in [25]:
            for y in [25,5,6,7,8,26,9,10,11,12,27,28,13,14,15,16,31,29,17,18,19,20,32,30,21,22,23,24]:
                T[x-1, y-1] *= index_above
                T[y-1, x-1] *= index_above
        for x in [13]:
            for y in [1,2,3,4,25,5,6,7,8,26,9,10,11,12,27,13,29,17,18,19,20,32,30,21,22,23,24]:
                T[x-1, y-1] *= index_above
                T[y-1, x-1] *= index_above
        for x in [28]:
            for y in [1,2,3,4,25,5,6,7,8,26,9,10,11,12,27,28,29,17,18,19,20,32,30,21,22,23,24]:
                T[x-1, y-1] *= index_above
                T[y-1, x-1] *= index_above
    if inside_top < 1.0:
        for x in [4,25,28,13]:
            for j in range(0,32):
                T[x-1, j] *= inside_top
                T[j, x-1] *= inside_top
    if side_top < 1.0:
        for x in [1,4,25,28,13,16,31]:
            for j in range(0,32):
                T[x-1, j] *= side_top
                T[j, x-1] *= side_top
    if side_above_1away < 1.0:
        for x in [1]:
            for y in [6,10]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [5]:
            for y in [10]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [4,25]:
            for y in [7,11]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [8,26]:
            for y in [11]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [13,28]:
            for y in [18,22]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [17,29]:
            for y in [22]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [16,31]:
            for y in [19,23]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
        for x in [20,32]:
            for y in [23]:
                T[x-1, y-1] *= side_above_1away
                T[y-1, x-1] *= side_above_1away
    if side_above_2away < 1.0:
        for x in [1]:
            for y in [7,11]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [5]:
            for y in [11]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [4,25]:
            for y in [6,10]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [8,26]:
            for y in [10]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [13,28]:
            for y in [19,23]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [17,29]:
            for y in [23]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [16,31]:
            for y in [18,22]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
        for x in [20,32]:
            for y in [22]:
                T[x-1, y-1] *= side_above_2away
                T[y-1, x-1] *= side_above_2away
    if side_above_3away < 1.0:
        for x in [1]:
            for y in [8,12,26,27]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [5]:
            for y in [12,27]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [4,25]:
            for y in [5,9]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [8,26]:
            for y in [9]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [13,28]:
            for y in [20,24,32]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [17,29]:
            for y in [24]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [16,31]:
            for y in [17,21,29,30]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away
        for x in [20,32]:
            for y in [21,30]:
                T[x-1, y-1] *= side_above_3away
                T[y-1, x-1] *= side_above_3away

    #  1  2  3  4 25   28 13 14 15 16 31
    #  5  6  7  8 26   29 17 18 19 20 32
    #  9 10 11 12 27   30 21 22 23 24
    if shorter_above < 1.0:
        for x in [1]:
            for y in [6,7,8,26,10,11,12,27]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [2]:
            for y in [7,11]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [4]:
            for y in [6,7,10,11]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [25]:
            for y in [6,7,10,11]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above

        for x in [5]:
            for y in [10,11,12,27]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [6]:
            for y in [11]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [8]:
            for y in [10,11]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [26]:
            for y in [10,11]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above

        for x in [16]:
            for y in [29,17,18,19,30,21,22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [31]:
            for y in [29,17,18,19,30,21,22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [15]:
            for y in [18,22]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [13]:
            for y in [18,19,22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [28]:
            for y in [18,19,22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above

        for x in [20]:
            for y in [30,21,22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [32]:
            for y in [30,21,22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [19]:
            for y in [22]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [17]:
            for y in [22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above
        for x in [29]:
            for y in [22,23]:
                T[x-1, y-1] *= shorter_above
                T[y-1, x-1] *= shorter_above

    if ring_above_middle < 1.0:
        ring_above_middles =  [[2,7],[6,11],[2,11],
                            [15,18],[19,22],[15,22]]
        for x in ring_above_middles:
            T[x[0]-1, x[1]-1] *= ring_above_middle
            T[x[1]-1, x[0]-1] *= ring_above_middle

    if middle_above_ring < 1.0:
        middle_above_rings =  [[6,3],[10,7],[10,3],
                            [19,14],[23,18],[23,14]]
        for x in middle_above_rings:
            T[x[0]-1, x[1]-1] *= middle_above_ring
            T[x[1]-1, x[0]-1] *= middle_above_ring

    # 10. Avoid using the same finger.
    #  1  2  3  4 25   28 13 14 15 16 31
    #  5  6  7  8 26   29 17 18 19 20 32
    #  9 10 11 12 27   30 21 22 23 24
    if same_finger < 1.0:
        same_fingers = [[1,5],[5,9],[1,9], [2,6],[6,10],[2,10],
                        [3,7],[7,11],[3,11], [4,8],[8,12],[4,12],
                        [25,26],[26,27],[25,27], [28,29],[29,30],[28,30], [31,32],
                        [4,25],[4,26],[4,27], [8,25],[8,26],[8,27], [12,25],[12,26],[12,27],
                        [13,28],[13,29],[13,30], [17,28],[17,29],[17,30], [21,28],[21,29],[21,30],
                        [31,16],[31,20],[31,24], [32,16],[32,20],[32,24],
                        [13,17],[17,21],[13,21], [14,18],[18,22],[14,22],
                        [15,19],[19,23],[15,23], [16,20],[20,24],[16,24]]
        for x in same_fingers:
            T[x[0]-1, x[1]-1] *= same_finger
            T[x[1]-1, x[0]-1] *= same_finger

    # 11. Avoid the upper and lower rows.
    if not_home_row < 1.0:
        not_home_row_keys = [1,2,3,4,25, 9,10,11,12,27, 28,13,14,15,16,31, 30,21,22,23,24]
        for x in not_home_row_keys:
            for j in range(0,32):
                T[x-1, j] *= not_home_row
                T[j, x-1] *= not_home_row

    # 12. Avoid skipping over the home row.
    #  1  2  3  4 25   28 13 14 15 16 31
    #  5  6  7  8 26   29 17 18 19 20 32
    #  9 10 11 12 27   30 21 22 23 24
    if skip_row_0away < 1.0:
        skip_top = [1, 2, 3, 4, 4,25,25, 28,28,13,13,14,15,16,31]
        skip_bot = [9,10,11,12,27,12,27, 30,21,30,21,22,23,24,24]
        for ix, x in enumerate(skip_top):
            y = skip_bot[ix]
            T[x-1, y-1] *= skip_row_0away
            T[y-1, x-1] *= skip_row_0away
    if skip_row_1away < 1.0:
        skip_top = [1, 2, 2, 3, 3, 4, 4,25, 28,13,13,14,14,15,15,16,31]
        skip_bot = [10,9,11,10,12,11,27,11, 22,30,22,21,23,22,24,23,23]
        for ix, x in enumerate(skip_top):
            y = skip_bot[ix]
            T[x-1, y-1] *= skip_row_1away
            T[y-1, x-1] *= skip_row_1away
    if skip_row_2away < 1.0:
        skip_top = [1,  2,3, 4,25, 28,13,14,15,16,31]
        skip_bot = [11,12,9,10,10, 23,23,24,21,22,22]
        for ix, x in enumerate(skip_top):
            y = skip_bot[ix]
            T[x-1, y-1] *= skip_row_2away
            T[y-1, x-1] *= skip_row_2away
    if skip_row_3away < 1.0:
        skip_top = [1, 4,25, 28,13,16,16,31,31]
        skip_bot = [12,9, 9, 24,24,21,30,21,30]
        for ix, x in enumerate(skip_top):
            y = skip_bot[ix]
            T[x-1, y-1] *= skip_row_3away
            T[y-1, x-1] *= skip_row_3away

    Flow32x32 = T

    # Normalize matrix with min-max scaling to a range with maximum = 1:
    newMin = np.min(Flow32x32) / np.max(Flow32x32)
    newMax = 1.0
    Flow32x32 = newMin + (Flow32x32 - np.min(Flow32x32)) * (newMax - newMin) / (np.max(Flow32x32) - np.min(Flow32x32))

    return Flow32x32

Flow32x32 = create_32x32_flow_matrix(not_home_row, side_top,
    side_above_3away, side_above_2away, side_above_1away, middle_above_ring, ring_above_middle, outward,
    skip_row_3away, skip_row_2away, skip_row_1away, skip_row_0away, same_finger, lateral, same_hand,
    shorter_above, adjacent_offset, inside_top, index_above)

# Print:
print_matrix_info(matrix_data=Flow32x32, matrix_label="Flow32x32", nkeys=32, nlines=30)
heatmap(data=Flow32x32, title="Flow32x32", xlabel="Key 1", ylabel="Key 2", print_output=print_output)

# Save:
if print_output:
    file = open("Flow32x32.txt", "w+")
    file.write(str(Flow32x32))
    file.close()

#  1  2  3  4 25   28 13 14 15 16 31
#  5  6  7  8 26   29 17 18 19 20 32
#  9 10 11 12 27   30 21 22 23 24
```

## Combine Speed, Strength, and Flow matrices  <a name="speedstrengthflow">

```python
# 24 keys:
Factors24x24 = Flow24x24
if apply_strength:
    Factors24x24 = Strength24x24 * Factors24x24

# Print:
print_matrix_info(matrix_data=Factors24x24, matrix_label="Factors24x24", nkeys=24, nlines=30)
heatmap(data=Factors24x24, title="Factors24x24", xlabel="Key 1", ylabel="Key 2", print_output=print_output)

# Save:
if print_output:
    file = open("Factors24x24.txt", "w+")
    file.write(str(Factors24x24))
    file.close()
```

```python
# 32 keys:
Factors32x32 = Flow32x32
if apply_strength:
    Factors32x32 = Strength32x32 * Factors32x32

# Print:
print_matrix_info(matrix_data=Factors32x32, matrix_label="Factors32x32", nkeys=32, nlines=30)
heatmap(data=Factors32x32, title="Factors32x32", xlabel="Key 1", ylabel="Key 2", print_output=print_output)

# Save:
if print_output:
    file = open("Factors32x32.txt", "w+")
    file.write(str(Factors32x32))
    file.close()
```

## Compare layouts based on interkey speed <a name="speed">

The Speed matrix contains left-right averaged versions of the normalized interkey stroke times derived from the study (averaged to compensate for right-handedness of participants in the study):

"Estimation of digraph costs for keyboard layout optimization",
A Iseri, Ma Eksioglu, International Journal of Industrial Ergonomics, 48, 127-138, 2015.

```python
data_matrix_speed = Speed32x32
time_range = 243  # ms
norm_range = 0.1  # 1.0 - 0.9
ms_norm = norm_range / time_range  # 0.000411522633744856
epsilon = 131.58 * ms_norm / (24**2)  # 0.000411522633744856
speed_scores = []
for letters in layout_letters:
    score = score_layout(data_matrix_speed, letters, bigrams, bigram_frequencies, verbose = False)
    speed_scores.append(score)
speed_scores_sorted, speed_ranks_sorted, Isort_speed = rank_within_epsilon(speed_scores, epsilon,
                                                                           factor=False, verbose=False)
print('\nRank:   Layout                                             Speed score\n')
for i, rank in enumerate(speed_ranks_sorted):
    print('    {0}:  {1}    {2}'.format(rank, layout_names[Isort_speed[i]], speed_scores_sorted[i]))
```

    Rank:   Layout                                             Speed score

        1:  QGMLWB    0.6861533242912506
        1:  Klausler    0.6860694668614524
        2:  Capewell-Dvorak    0.6859513060623683
        2:  Colemak    0.6859470551002004
        2:  Halmak    0.685862612295209
        3:  Dvorak    0.6858445848850323
        3:  Colemak Mod-DH    0.6857730319204565
        3:  Asset    0.685754337946507
        4:  Norman    0.685665752679605
        4:  Workman    0.6855719203274142
        5:  Hieamtsrn    0.6855318822756586
        6:  MTGap 2.0    0.6854281396438425
        7:  Engram    0.6852535258142791
        8:  QWERTY    0.6843830181015049

## Score layouts using Engram's scoring model  <a name="Engram">

```python
layout_strings = []
layout_scores = []
for layout in layout_letters:
    layout_string = ' '.join(layout)
    score = score_layout(Factors32x32, layout, bigrams, bigram_frequencies, verbose=False)
    layout_strings.append(layout_string)
    layout_scores.append(score)

# Establish which layouts are within a negligible difference of the top-scoring layout
# (the smallest difference between two penalties, 0.9^8 - 0.9^9, in one of 24^2 key pairs):
delta = 0.9**9 - 0.9**10
factor = ((24**2 - 1) + (1-delta)) / (24**2)
print('delta = {0}'.format(delta))    # delta  = 0.030205665244067793
print('factor = {0}'.format(factor))  # factor = 0.9999475596089513
scores_sorted, ranks_sorted, Isort = rank_within_epsilon(layout_scores, factor, factor=True, verbose=False)
print('\nRank:   Layout    Score\n')
for i, rank in enumerate(ranks_sorted):
    print('    {0}:  {1}    {2}'.format(rank, layout_names[Isort[i]], scores_sorted[i]))
```

    delta = 0.03874204889999999
    factor = 0.9999327394984375

    Rank:   Layout    Score

        1:  Engram    0.7502800189214918
        2:  Hieamtsrn    0.7500834009709707
        3:  Halmak    0.7497573328046871
        4:  Colemak Mod-DH    0.7495486801335415
        5:  Workman    0.7494146282157065
        6:  MTGap 2.0    0.7493590057152013
        6:  Colemak    0.749323071527497
        7:  Klausler    0.7491985680682132
        8:  Norman    0.7491174419277558
        8:  QGMLWB    0.749104616280684
        9:  Dvorak    0.749046337831136
        9:  Capewell-Dvorak    0.7490444795507138
        10:  Asset    0.7489782990946122
        11:  QWERTY    0.7476139840325112

delta = 0.03874204889999999
factor = 0.9999327394984375

Rank:   Layout    Score

    1:  Engram    0.7502800189214918
    2:  Hieamtsrn    0.7500834009709707
    3:  Halmak    0.7497573328046871
    4:  Colemak Mod-DH    0.7495486801335415
    5:  Workman    0.7494146282157065
    6:  MTGap 2.0    0.7493590057152013
    6:  Colemak    0.749323071527497
    7:  Klausler    0.7491985680682132
    8:  Norman    0.7491174419277558
    8:  QGMLWB    0.749104616280684
    9:  Dvorak    0.749046337831136
    9:  Capewell-Dvorak    0.7490444795507138
    10:  Asset    0.7489782990946122
    11:  QWERTY    0.7476139840325112

## Score layouts using Engram's scoring model and on **bigram frequency of input text**

```python
import requests
data_matrix = Factors32x32
score_table = []
for iurl, url in enumerate(urls):
    print("")
    print(text_names[iurl])
    input_text = requests.get(url).text
    bigram_frequencies_for_input = tally_bigrams(input_text, bigrams, normalize=True, verbose=False)
    scores = []
    for letters in layout_letters:
        score = score_layout(data_matrix, letters, bigrams, bigram_frequencies_for_input, verbose=False)
        scores.append(score)
    score_table.append(scores)

    scores_sorted, ranks_sorted, Isort = rank_within_epsilon(scores, factor, factor=True, verbose=False)
    print('Rank:   Layout    Score\n')
    for i, rank in enumerate(ranks_sorted):
        print('    {0}:  {1}    {2}'.format(rank, layout_names[Isort[i]], scores_sorted[i]))

```

    Alice in Wonderland (Ch.1)
    Rank:   Layout    Score

        1:  Engram    0.7445255116363066
        1:  Hieamtsrn    0.744493247399194
        2:  Halmak    0.7442057522674784
        3:  Colemak Mod-DH    0.7440356104330337
        4:  Workman    0.7439343955531742
        4:  MTGap 2.0    0.7438995028076142
        5:  Klausler    0.7437895427905579
        5:  Norman    0.7437646134256715
        6:  Colemak    0.7437360174144916
        6:  Dvorak    0.7437064077057469
        6:  QGMLWB    0.7437042138107322
        7:  Capewell-Dvorak    0.7436828469800179
        8:  Asset    0.7435558904639417
        9:  QWERTY    0.7427495880005877

    Romeo and Juliet
    Rank:   Layout    Score

        1:  Engram    0.7462377983440776
        2:  Hieamtsrn    0.7460656954751297
        3:  Halmak    0.7458215328584193
        4:  Workman    0.7455477191686165
        4:  Colemak Mod-DH    0.7455256248234188
        5:  Klausler    0.7453959154393313
        5:  MTGap 2.0    0.7453842638318341
        6:  Colemak    0.7453252513174218
        6:  Dvorak    0.7452977776069954
        7:  Capewell-Dvorak    0.7452314494639884
        7:  Norman    0.745223159420264
        7:  QGMLWB    0.7451915241331577
        8:  Asset    0.7451023744367409
        9:  QWERTY    0.744081753045933

    Bhagavad Gita
    Rank:   Layout    Score

        1:  Engram    0.7445033030573653
        2:  Hieamtsrn    0.7442748977532957
        3:  Halmak    0.7440452984963499
        4:  Colemak Mod-DH    0.7439342924524047
        5:  Workman    0.7438122187336434
        5:  MTGap 2.0    0.7437662911568246
        6:  Colemak    0.7436881695039714
        6:  Norman    0.7436867028525271
        6:  Klausler    0.7436685333496726
        7:  Capewell-Dvorak    0.7435464823703208
        7:  QGMLWB    0.7435306808518158
        8:  Dvorak    0.7434626744010637
        8:  Asset    0.7434623523413765
        9:  QWERTY    0.7425000899359803

    Memento screenplay
    Rank:   Layout    Score

        1:  Engram    0.7512152417182343
        2:  Hieamtsrn    0.7510946267517449
        3:  Halmak    0.7508156056439149
        4:  Workman    0.7505223925174471
        4:  Colemak Mod-DH    0.7504919649032535
        5:  MTGap 2.0    0.7504656165787917
        6:  Klausler    0.7502677083821565
        6:  Norman    0.7502270589073867
        7:  Colemak    0.7501786479496046
        7:  QGMLWB    0.7501687105387891
        8:  Dvorak    0.7501129491835481
        8:  Asset    0.7500924821648107
        8:  Capewell-Dvorak    0.7500775044779536
        9:  QWERTY    0.7487788244686439

    100,000 tweets (Sentiment Classification)
    Rank:   Layout    Score

        1:  Engram    0.7587999922922919
        2:  Hieamtsrn    0.7586168740935535
        3:  Halmak    0.7582395052093746
        4:  Workman    0.7577024398478142
        4:  Colemak Mod-DH    0.7576779309668868
        5:  Klausler    0.7575363748102988
        6:  MTGap 2.0    0.7574813328516148
        6:  Colemak    0.7574556435729025
        7:  Capewell-Dvorak    0.7573431687255685
        7:  QGMLWB    0.757320932589792
        7:  Dvorak    0.7572958623751398
        8:  Norman    0.7571830591612143
        8:  Asset    0.7571405619681301
        9:  QWERTY    0.7555352038036853

    20,000 tweets (Gender classifier)
    Rank:   Layout    Score

        1:  Engram    0.7552965804045838
        2:  Hieamtsrn    0.7550272024359316
        3:  Halmak    0.7548698754255334
        4:  Workman    0.7544061351998617
        5:  Colemak Mod-DH    0.7542576164427959
        6:  MTGap 2.0    0.7541862651670737
        6:  Klausler    0.7541543581594552
        7:  QGMLWB    0.7540478766683447
        7:  Colemak    0.7540154496489697
        8:  Dvorak    0.7539848148930088
        9:  Norman    0.7539294799193212
        9:  Capewell-Dvorak    0.7539273986075242
        10:  Asset    0.7538682010194889
        11:  QWERTY    0.7524505187684718

    Manually Annotated Sub-Corpus tweets
    Rank:   Layout    Score

        1:  Engram    0.7533480668588272
        2:  Hieamtsrn    0.7531820679715767
        3:  Halmak    0.7529324116257463
        4:  Workman    0.7525105553955649
        4:  Colemak Mod-DH    0.7525080965567097
        5:  Colemak    0.7523565520021861
        5:  MTGap 2.0    0.7523433819792806
        6:  Klausler    0.7522483472854136
        7:  Capewell-Dvorak    0.7521326792734249
        7:  Norman    0.7521038803161461
        8:  Asset    0.7520775593833018
        8:  QGMLWB    0.7520768580635181
        8:  Dvorak    0.7520330473326271
        9:  QWERTY    0.7505885443443292

    Manually Annotated Sub-Corpus spoken transcripts
    Rank:   Layout    Score

        1:  Engram    0.7434425867319531
        2:  Hieamtsrn    0.7433517532910301
        3:  Halmak    0.7432427823998995
        4:  Colemak Mod-DH    0.7429249638168247
        5:  Workman    0.7428572062163613
        5:  Klausler    0.7428276880174356
        5:  MTGap 2.0    0.7428240293514123
        6:  Colemak    0.7427099901825774
        6:  Dvorak    0.7427060150669405
        6:  Norman    0.7427020077511466
        6:  QGMLWB    0.7426988315541281
        6:  Capewell-Dvorak    0.7426714144608173
        7:  Asset    0.7425384406227465
        8:  QWERTY    0.7416605861014668

    Corpus of Contemporary American English blog samples
    Rank:   Layout    Score

        1:  Engram    0.7501455184936774
        2:  Hieamtsrn    0.749994950272338
        3:  Halmak    0.749700591743684
        4:  Colemak Mod-DH    0.7494009108078719
        5:  Workman    0.7492640087504288
        5:  MTGap 2.0    0.7492386935334041
        6:  Colemak    0.7492021340914676
        7:  Klausler    0.7491392455141934
        8:  Norman    0.7490127631985506
        8:  QGMLWB    0.7489940237147004
        8:  Dvorak    0.7489734586791237
        8:  Capewell-Dvorak    0.7489658091510272
        9:  Asset    0.7488977328623273
        10:  QWERTY    0.7475868749135686

    Shai Coleman iweb corpus 1/6
    Rank:   Layout    Score

        1:  Engram    0.7521347709412141
        2:  Hieamtsrn    0.7520036729279335
        3:  Halmak    0.75166180756771
        4:  Colemak Mod-DH    0.7513771807941114
        5:  Workman    0.7512407288435894
        5:  MTGap 2.0    0.7511903871554869
        6:  Colemak    0.7511728954367094
        7:  Klausler    0.7510475615168046
        8:  QGMLWB    0.7509120402120495
        8:  Norman    0.7508933637286321
        9:  Dvorak    0.7508568692529449
        9:  Capewell-Dvorak    0.7508385848273469
        10:  Asset    0.7508000892455673
        11:  QWERTY    0.7493885522364304

    Ian Douglas monkey test
    Rank:   Layout    Score

        1:  Engram    0.7505454213423466
        2:  Hieamtsrn    0.7503639994522184
        3:  Halmak    0.7500371827818993
        4:  Colemak Mod-DH    0.7498143793410694
        5:  Workman    0.7496926152167988
        5:  MTGap 2.0    0.7496466647443003
        6:  Colemak    0.7495841296139549
        7:  Klausler    0.7494730953935685
        8:  Norman    0.7493731369594069
        8:  QGMLWB    0.7493554938530738
        8:  Capewell-Dvorak    0.7493255732707832
        9:  Dvorak    0.7493181552668314
        10:  Asset    0.7492490284295575
        11:  QWERTY    0.7479005682987844

    Ian Douglas coder test
    Rank:   Layout    Score

        1:  Engram    0.7536961822613741
        2:  Hieamtsrn    0.7533973461263298
        3:  Halmak    0.7531060564037025
        4:  Colemak Mod-DH    0.7527937283736892
        5:  MTGap 2.0    0.7527241488318342
        5:  Workman    0.7527164432424885
        6:  Colemak    0.7526280882900735
        7:  Klausler    0.7523386658724818
        7:  QGMLWB    0.7523245037534942
        8:  Asset    0.7522622878375567
        9:  Norman    0.7521804570942231
        9:  Capewell-Dvorak    0.7521666879809245
        10:  Dvorak    0.7520437296522012
        11:  QWERTY    0.7506074021395333

    Tower of Hanoi (programming languages A-Z, Rosetta Code)
    Rank:   Layout    Score

        1:  Engram    0.7532761173759639
        2:  Halmak    0.7526329210384023
        3:  Hieamtsrn    0.7523366408821551
        4:  Workman    0.7522024863650978
        5:  Colemak    0.752027511093843
        6:  Colemak Mod-DH    0.7518905851775592
        6:  MTGap 2.0    0.7518484418995561
        7:  Asset    0.7518262567944902
        8:  Klausler    0.7517367700623173
        8:  Dvorak    0.7517180298601622
        8:  Norman    0.7516863991804899
        9:  Capewell-Dvorak    0.7514798352785976
        10:  QGMLWB    0.7512629231413269
        11:  QWERTY    0.7500582925513382

```python
score_matrix = np.array(score_table).transpose()
#print(score_matrix)
print("")
print("| Layout | Google bigrams |", end='')
for itext in range(len(text_names)):
    print(" {0} |".format(text_abbrs[itext]), end='')
print("")
print("| --- | --- |", end='')
for itext in range(len(text_names)):
    print(" --- |", end='')
for ilayout in range(len(layout_names)):
    print("")
    print("| {0} | {1:0.2f} |".format(layout_names[ilayout], 100*layout_scores[ilayout]), end='')
    for itext in range(len(text_names)):
        print(" {0:0.2f} |".format(100*score_matrix[ilayout, itext]), end='')
```

    | Layout | Google bigrams | Alice | Romeo | Gita | Memento | 100K tweets | 20K tweets | MASC tweets | MASC spoken | COCA blogs | iweb | Monkey | Coder | Code |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
    | Engram | 75.03 | 74.45 | 74.62 | 74.45 | 75.12 | 75.88 | 75.53 | 75.33 | 74.34 | 75.01 | 75.21 | 75.05 | 75.37 | 75.33 |
    | Halmak | 74.98 | 74.42 | 74.58 | 74.40 | 75.08 | 75.82 | 75.49 | 75.29 | 74.32 | 74.97 | 75.17 | 75.00 | 75.31 | 75.26 |
    | Hieamtsrn | 75.01 | 74.45 | 74.61 | 74.43 | 75.11 | 75.86 | 75.50 | 75.32 | 74.34 | 75.00 | 75.20 | 75.04 | 75.34 | 75.23 |
    | Colemak Mod-DH | 74.95 | 74.40 | 74.55 | 74.39 | 75.05 | 75.77 | 75.43 | 75.25 | 74.29 | 74.94 | 75.14 | 74.98 | 75.28 | 75.19 |
    | Norman | 74.91 | 74.38 | 74.52 | 74.37 | 75.02 | 75.72 | 75.39 | 75.21 | 74.27 | 74.90 | 75.09 | 74.94 | 75.22 | 75.17 |
    | Workman | 74.94 | 74.39 | 74.55 | 74.38 | 75.05 | 75.77 | 75.44 | 75.25 | 74.29 | 74.93 | 75.12 | 74.97 | 75.27 | 75.22 |
    | MTGap 2.0 | 74.94 | 74.39 | 74.54 | 74.38 | 75.05 | 75.75 | 75.42 | 75.23 | 74.28 | 74.92 | 75.12 | 74.96 | 75.27 | 75.18 |
    | QGMLWB | 74.91 | 74.37 | 74.52 | 74.35 | 75.02 | 75.73 | 75.40 | 75.21 | 74.27 | 74.90 | 75.09 | 74.94 | 75.23 | 75.13 |
    | Colemak | 74.93 | 74.37 | 74.53 | 74.37 | 75.02 | 75.75 | 75.40 | 75.24 | 74.27 | 74.92 | 75.12 | 74.96 | 75.26 | 75.20 |
    | Asset | 74.90 | 74.36 | 74.51 | 74.35 | 75.01 | 75.71 | 75.39 | 75.21 | 74.25 | 74.89 | 75.08 | 74.92 | 75.23 | 75.18 |
    | Capewell-Dvorak | 74.90 | 74.37 | 74.52 | 74.35 | 75.01 | 75.73 | 75.39 | 75.21 | 74.27 | 74.90 | 75.08 | 74.93 | 75.22 | 75.15 |
    | Klausler | 74.92 | 74.38 | 74.54 | 74.37 | 75.03 | 75.75 | 75.42 | 75.22 | 74.28 | 74.91 | 75.10 | 74.95 | 75.23 | 75.17 |
    | Dvorak | 74.90 | 74.37 | 74.53 | 74.35 | 75.01 | 75.73 | 75.40 | 75.20 | 74.27 | 74.90 | 75.09 | 74.93 | 75.20 | 75.17 |
    | QWERTY | 74.76 | 74.27 | 74.41 | 74.25 | 74.88 | 75.55 | 75.25 | 75.06 | 74.17 | 74.76 | 74.94 | 74.79 | 75.06 | 75.01 |

## Engram Scoring Model scores (x100) for layouts, based on publicly available text data

| Layout | Google bigrams | Alice | Romeo | Gita | Memento | 100K tweets | 20K tweets | MASC tweets | MASC spoken | COCA blogs | iweb | Monkey | Coder | Code |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram | 75.03 | 74.45 | 74.62 | 74.45 | 75.12 | 75.88 | 75.53 | 75.33 | 74.34 | 75.01 | 75.21 | 75.05 | 75.37 | 75.33 |
| Halmak | 74.98 | 74.42 | 74.58 | 74.40 | 75.08 | 75.82 | 75.49 | 75.29 | 74.32 | 74.97 | 75.17 | 75.00 | 75.31 | 75.26 |
| Hieamtsrn | 75.01 | 74.45 | 74.61 | 74.43 | 75.11 | 75.86 | 75.50 | 75.32 | 74.34 | 75.00 | 75.20 | 75.04 | 75.34 | 75.23 |
| Colemak Mod-DH | 74.95 | 74.40 | 74.55 | 74.39 | 75.05 | 75.77 | 75.43 | 75.25 | 74.29 | 74.94 | 75.14 | 74.98 | 75.28 | 75.19 |
| Norman | 74.91 | 74.38 | 74.52 | 74.37 | 75.02 | 75.72 | 75.39 | 75.21 | 74.27 | 74.90 | 75.09 | 74.94 | 75.22 | 75.17 |
| Workman | 74.94 | 74.39 | 74.55 | 74.38 | 75.05 | 75.77 | 75.44 | 75.25 | 74.29 | 74.93 | 75.12 | 74.97 | 75.27 | 75.22 |
| MTGap 2.0 | 74.94 | 74.39 | 74.54 | 74.38 | 75.05 | 75.75 | 75.42 | 75.23 | 74.28 | 74.92 | 75.12 | 74.96 | 75.27 | 75.18 |
| QGMLWB | 74.91 | 74.37 | 74.52 | 74.35 | 75.02 | 75.73 | 75.40 | 75.21 | 74.27 | 74.90 | 75.09 | 74.94 | 75.23 | 75.13 |
| Colemak | 74.93 | 74.37 | 74.53 | 74.37 | 75.02 | 75.75 | 75.40 | 75.24 | 74.27 | 74.92 | 75.12 | 74.96 | 75.26 | 75.20 |
| Asset | 74.90 | 74.36 | 74.51 | 74.35 | 75.01 | 75.71 | 75.39 | 75.21 | 74.25 | 74.89 | 75.08 | 74.92 | 75.23 | 75.18 |
| Capewell-Dvorak | 74.90 | 74.37 | 74.52 | 74.35 | 75.01 | 75.73 | 75.39 | 75.21 | 74.27 | 74.90 | 75.08 | 74.93 | 75.22 | 75.15 |
| Klausler | 74.92 | 74.38 | 74.54 | 74.37 | 75.03 | 75.75 | 75.42 | 75.22 | 74.28 | 74.91 | 75.10 | 74.95 | 75.23 | 75.17 |
| Dvorak | 74.90 | 74.37 | 74.53 | 74.35 | 75.01 | 75.73 | 75.40 | 75.20 | 74.27 | 74.90 | 75.09 | 74.93 | 75.20 | 75.17 |
| QWERTY | 74.76 | 74.27 | 74.41 | 74.25 | 74.88 | 75.55 | 75.25 | 75.06 | 74.17 | 74.76 | 74.94 | 74.79 | 75.06 | 75.01 |

## [Carpalx](http://mkweb.bcgsc.ca/carpalx/?keyboard_layouts) scores <a name="CarpalX">

These scores are computed based on literature from the Gutenberg Project.

| Layout | home row use (%) | hand symmetry (%, right<0) | hand switching (%) | finger switching (%) | hand runs without row jumps (%) | base effort  | penalties | path effort | total effort |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram |  |  |  |  |  |  |  |  |  |
| Hieamtsrn | 65 | -96 | 59 | 93 | 85 | 0.38 | 0.848 | 0.720 | 1.948 |
| Halmak | 64 | 99 | 63 | 93 | 81 | 0.325 | 1.175 | 0.823 | 2.322 |
| Norman | 68 | 95 | 52 | 90 | 77 | 0.342 | 0.812 | 0.838 | 1.992 |
| Workman | 68 | 95 | 52 | 93 | 79 | 0.336 | 0.848 | 0.809 | 1.993 |
| MTGAP 2.0 | 68 | 98 | 48 | 93 | 76 | 0.327 | 0.839 | 0.815 | 1.981 |
| QGMLWB | 74 | -97 | 57 | 91 | 84 | 0.382 | 0.570 | 0.716 | 1.668 |
| BEAKL 15 | 57 | -95 | 59 | 91 | 80 | 0.473 | 0.663 | 0.809 | 1.945 |
| Colemak Mod-DH | 68 | -94 | 52 | 93 | 78 | 0.335 | 0.842 | 0.781 | 1.958 |
| Colemak | 74 | -94 | 52 | 93 | 83 | 0.344 | 0.763 | 0.735 | 1.842 |
| Asset | 74 | 96 | 52 | 91 | 82 | 0.356 | 0.766 | 0.772 | 1.894 |
| Capewell-Dvorak | 71 | -91 | 59 | 92 | 82 | 0.333 | 0.878 | 0.774 | 1.985 |
| Klausler | 74 | -94 | 62 | 93 | 86 | 0.341 | 0.797 | 0.729 | 1.867 |
| Dvorak | 71 | -86 | 62 | 93 | 84 | 0.397 | 0.937 | 0.765 | 2.098 |
| QWERTY | 34 | 85 | 51 | 89 | 68 | 1 | 1 | 1 | 3 |

## Score layouts using the Keyboard Layout Analyzer <a name="KLAscores">

[Keyboard Layout Analyzer](http://patorjk.com/keyboard-layout-analyzer/) (KLA) scores for the same text sources:

> The optimal layout score is based on a weighted calculation that factors in the distance your fingers moved (33%), how often you use particular fingers (33%), and how often you switch fingers and hands while typing (34%).

| Layout | Alice in Wonderland | Romeo Juliet | Bhagavad Gita | Memento screenplay | 100K tweets | 20K tweets | MASC tweets | MASC spoken | COCA blogs | iweb | Monkey | Coder | Software languages |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram    | 69.10 | 61.26 | 61.68 | 56.50 | 63.87 | 58.64 | 60.05 | 63.64 | 69.45 | 68.26 | 67.64 | 47.70 | 48.73 |
| Halmak    | 66.25 | 57.02 | 57.45 | 55.03 | 60.86 | 55.53 | 57.13 | 62.32 | 67.29 | 65.50 | 64.75 | 45.68 | 47.60 |
| Hieamtsrn | 69.43 | 60.94 | 60.87 | 56.75 | 64.40 | 58.95 | 60.47 | 64.33 | 69.93 | 69.15 | 68.30 | 46.01 | 46.48 |
| Colemak Mod-DH | 65.74 | 56.05 | 57.52 | 54.91 | 60.75 | 54.94 | 57.15 | 61.29 | 67.12 | 65.98 | 64.85 | 47.35 | 48.50 |
| Norman    | 62.76 | 53.21 | 53.44 | 52.33 | 57.43 | 53.24 | 53.90 | 59.97 | 62.80 | 60.90 | 59.82 | 43.76 | 46.01 |
| Workman   | 64.78 | 56.67 | 56.97 | 54.29 | 59.98 | 55.81 | 56.25 | 61.34 | 65.27 | 63.76 | 62.90 | 45.33 | 47.76 |
| MTGAP 2.0 | 66.13 | 53.98 | 56.57 | 53.78 | 59.87 | 55.30 | 55.81 | 60.32 | 65.68 | 63.81 | 62.74 | 45.38 | 44.34 |
| QGMLWB    | 65.45 | 55.67 | 55.57 | 54.07 | 60.51 | 56.05 | 56.90 | 62.23 | 66.26 | 64.76 | 63.91 | 46.38 | 45.72 |
| Colemak   | 65.83 | 56.12 | 57.63 | 54.94 | 60.67 | 54.97 | 57.04 | 61.36 | 67.14 | 66.01 | 64.91 | 47.30 | 48.65 |
| Asset     | 64.60 | 54.63 | 56.09 | 53.84 | 58.66 | 54.72 | 55.35 | 60.81 | 64.71 | 63.17 | 62.44 | 45.54 | 47.52 |
| Capewell-Dvorak | 66.94 | 58.31 | 57.39 | 55.66 | 62.14 | 56.85 | 57.99 | 62.83 | 66.95 | 65.23 | 64.70 | 45.30 | 45.62 |
| Klausler  | 68.24 | 59.91 | 59.71 | 55.75 | 62.57 | 56.45 | 58.34 | 64.04 | 68.34 | 66.89 | 66.31 | 46.83 | 45.66 |
| Dvorak    | 65.86 | 58.18 | 57.29 | 55.09 | 60.93 | 55.56 | 56.59 | 62.75 | 66.64 | 64.87 | 64.26 | 45.46 | 45.55 |
| QWERTY    | 53.06 | 43.74 | 44.92 | 44.25 | 48.28 | 44.99 | 44.59 | 51.79 | 52.31 | 50.19 | 49.18 | 38.46 | 39.89 |

## Average the Keyboard Layout Analysis scores

```python
KLA_scores = [
    [69.10, 61.26, 61.68, 56.50, 63.87, 58.64, 60.05, 63.64, 69.45, 68.26, 67.64, 47.70, 48.73],
    [66.25, 57.02, 57.45, 55.03, 60.86, 55.53, 57.13, 62.32, 67.29, 65.50, 64.75, 45.68, 47.60],
    [69.43, 60.94, 60.87, 56.75, 64.40, 58.95, 60.47, 64.33, 69.93, 69.15, 68.30, 46.01, 46.48],
    [65.74, 56.05, 57.52, 54.91, 60.75, 54.94, 57.15, 61.29, 67.12, 65.98, 64.85, 47.35, 48.50],
    [62.76, 53.21, 53.44, 52.33, 57.43, 53.24, 53.90, 59.97, 62.80, 60.90, 59.82, 43.76, 46.01],
    [64.78, 56.67, 56.97, 54.29, 59.98, 55.81, 56.25, 61.34, 65.27, 63.76, 62.90, 45.33, 47.76],
    [66.13, 53.98, 56.57, 53.78, 59.87, 55.30, 55.81, 60.32, 65.68, 63.81, 62.74, 45.38, 44.34],
    [65.45, 55.67, 55.57, 54.07, 60.51, 56.05, 56.90, 62.23, 66.26, 64.76, 63.91, 46.38, 45.72],
    [65.83, 56.12, 57.63, 54.94, 60.67, 54.97, 57.04, 61.36, 67.14, 66.01, 64.91, 47.30, 48.65],
    [64.60, 54.63, 56.09, 53.84, 58.66, 54.72, 55.35, 60.81, 64.71, 63.17, 62.44, 45.54, 47.52],
    [66.94, 58.31, 57.39, 55.66, 62.14, 56.85, 57.99, 62.83, 66.95, 65.23, 64.70, 45.30, 45.62],
    [68.24, 59.91, 59.71, 55.75, 62.57, 56.45, 58.34, 64.04, 68.34, 66.89, 66.31, 46.83, 45.66],
    [65.86, 58.18, 57.29, 55.09, 60.93, 55.56, 56.59, 62.75, 66.64, 64.87, 64.26, 45.46, 45.55],
    [53.06, 43.74, 44.92, 44.25, 48.28, 44.99, 44.59, 51.79, 52.31, 50.19, 49.18, 38.46, 39.89]]

for i, KLA_score in enumerate(KLA_scores):
    print("    {0}: {1:0.2f} ({2:0.2f})".format(layout_names[i], np.mean(KLA_score), np.std(KLA_score)))
```

        Engram: 61.27 (6.81)
        Halmak: 58.65 (6.53)
        Hieamtsrn: 61.23 (7.60)
        Colemak Mod-DH: 58.63 (6.17)
        Norman: 55.35 (5.77)
        Workman: 57.78 (5.95)
        MTGap 2.0: 57.21 (6.66)
        QGMLWB: 57.96 (6.48)
        Colemak: 58.66 (6.17)
        Asset: 57.08 (5.87)
        Capewell-Dvorak: 58.92 (6.84)
        Klausler: 59.93 (7.13)
        Dvorak: 58.39 (6.69)
        QWERTY: 46.59 (4.46)

    Engram: 61.27 (6.81)
    Halmak: 58.65 (6.53)
    Hieamtsrn: 61.23 (7.60)
    Colemak Mod-DH: 58.63 (6.17)
    Norman: 55.35 (5.77)
    Workman: 57.78 (5.95)
    MTGap 2.0: 57.21 (6.66)
    QGMLWB: 57.96 (6.48)
    Colemak: 58.66 (6.17)
    Asset: 57.08 (5.87)
    Capewell-Dvorak: 58.92 (6.84)
    Klausler: 59.93 (7.13)
    Dvorak: 58.39 (6.69)
    QWERTY: 46.59 (4.46)

## Keyboard Layout Analyzer data <a name="KLAdata">

Below we manually construct tables of measures computed by the [Keyboard Layout Analyzer](https://klatest.keyboard-design.com/#/main) (after the original [KLA](http://patorjk.com/keyboard-layout-analyzer/) for the same text sources:

    - Finger distances (cm)
    - Number of taps
    - Number of same-finger taps

Text samples:

    - Alice in Wonderland (Chapter 1)
    - Memento
    - 100K tweets
    - 20K tweets
    - MASC tweets
    - MASC spoken
    - COCA blogs
    - iweb
    - Monkey
    - Coder
    - Rosetta

```python

Alice_distance_Engram2 = [
2385.1
670.2
2585.9
2812.0
3766.1
2113.5
1762.5
2554.2
18649.5
Alice_distance_Engram3 = [
2326.3
1054.6
2585.9
2443.7
4402.5
2113.5
1606.6
2806.4
19339.4
Alice_distance_Exgram = [
2326.3
1054.6
2585.9
2443.7
3543.6
2113.5
2470.3
2806.4
19344.2
Alice_distance_Halmak = [
2991.1
1999.6
2048.7
2038.5
1773.8
1007.9
1996.4
2867.4
16723.3
Alice_distance_Hieamtsrn = [
1216.1
747.9
2568.6
2709.3
4548.2
1440.5
1408.0
3044.2
17682.7
Alice_distance_ColemakModDH = [
1142.2
1019.7
1437.0
3958.6
4917.7
1746.3
919.7
2471.2
17612.3
Alice_distance_Norman = [
1136.5
1019.7
2230.1
3135.1
2707.5
2523.3
1661.8
2359.8
16773.8
Alice_distance_Workman = [
1096.6
1526.2
2372.6
3585.9
3250.6
1746.3
747.0
2461.3
16786.5
Alice_distance_MTGap = [
1863.4
733.0
2894.5
3253.8
3006.2
1439.7
1765.4
2174.2
17130.1
Alice_distance_QGMLWB = [
1324.8
819.4
1295.6
5062.3
4380.8
1746.3
546.7
2254.1
17430.1
Alice_distance_Colemak = [
1142.2
1019.7
1437.0
4070.7
4686.3
1746.3
919.7
2471.2
17493.0
Alice_distance_Asset = [
1142.2
1019.7
1437.0
3474.5
4719.3
1746.3
1661.8
2350.0
17550.7
Alice_distance_CapewellDvorak = [ = [
1541.2
729.1
906.9
2484.0
4200.7
1877.5
2414.7
2475.0
16629.2
Alice_distance_Klausler = [
1413.4
888.9
1439.7
2828.7
4923.7
1429.5
1358.7
2908.6
17191.2
Alice_distance_Dvorak = [
1622.7
724.8
198.7
3752.4
4483.8
1839.4
2129.1
3381.9
18132.8

Alice_taps_Engram2 = [
691
731
1780
1363
1578
1398
944
974
9459
Alice_taps_Engram3 = [
680
820
1780
1274
1578
1398
951
977
9458
Alice_taps_Exgram = [
680
820
1780
1274
1406
1398
1123
977
9458
Alice_taps_Halmak = [
1149
1154
1079
1374
1099
1334
1190
1070
9449
Alice_taps_Hieamtsrn = [
857
749
1776
1333
1948
863
877
1036
9439
Alice_taps_ColemakModDH = [
869
712
863
1796
1814
1505
779
1103
9441
Alice_taps_Norman = [
868
765
1636
1560
1251
1192
1169
989
9430
Alice_taps_Workman = [
861
900
1189
1701
1427
1505
882
967
9432
Alice_taps_MTGap = [
1068
871
1291
1687
1242
1434
950
883
9426
Alice_taps_QGMLWB = [
610
715
1182
1873
1770
1505
819
972
9446
Alice_taps_Colemak = [
869
712
863
1796
1814
1505
779
1103
9441
Alice_taps_Asset = [
869
765
1435
1671
1684
988
1169
849
9430
Alice_taps_CapewellDvorak = [ = [
998
863
1293
1178
1733
1321
1163
894
9443
Alice_taps_Klausler = [
964
900
1434
1284
1756
1213
930
967
9448
Alice_taps_Dvorak = [
1003
880
1128
1207
1652
1301
1090
1186
9447

Alice_samefinger_Engram2 = [
3
12
4
51
0
0
19
1
1
17
108
Alice_samefinger_Engram3 = [
5
28
4
34
0
0
19
1
28
17
136
Alice_samefinger_Exgram = [
5
28
4
34
0
0
11
1
8
17
108
Alice_samefinger_Halmak = [
6
1
12
43
0
0
48
7
59
73
249
Alice_samefinger_Hieamtsrn = [
21
13
4
42
0
0
6
5
3
28
122
Alice_samefinger_ColemakModDH = [
6
3
5
9
0
0
39
35
13
71
181
Alice_samefinger_Norman = [
12
1
170
8
0
0
90
59
44
85
469
Alice_samefinger_Workman = [
5
10
11
16
0
0
98
35
38
62
275
Alice_samefinger_MTGap = [
18
17
0
5
0
0
19
8
6
40
113
Alice_samefinger_QGMLWB = [
3
7
14
78
0
0
186
35
8
75
406
Alice_samefinger_Colemak = [
6
3
5
9
0
0
39
35
13
71
181
Alice_samefinger_Asset = [
12
1
77
4
0
0
52
5
44
65
260
Alice_samefinger_CapewellDvorak = [ = [
49
0
63
60
0
0
58
3
13
32
278
Alice_samefinger_Klausler = [
34
0
8
74
0
0
60
1
0
27
204
Alice_samefinger_Dvorak = [
45
5
9
72
0
0
43
17
12
55
258

Memento_distance_Engram2 = [
117669.4
14714.3
46103.8
45471.4
76514.5
39479.4
20635.9
166039.6
526628.3
Memento_distance_Engram3 = [
118376.9
22176.8
46103.8
38101.2
75991.2
39479.4
20495.3
165485.1
526209.6
Memento_distance_Exgram = [
118376.9
22176.8
46103.8
38101.2
63079.0
39479.4
33486.7
165485.1
526288.9
Memento_distance_Halmak = [
110075.3
36876.7
35540.7
35674.8
38882.9
22425.2
39790.0
187228.3
506494.1
Memento_distance_Hieamtsrn = [
107035.7
16014.0
47105.1
48724.7
73070.9
27444.8
26262.9
166803.7
512461.8
Memento_distance_ColemakModDH = [
89542.2
11946.3
25454.4
65355.9
77791.2
28531.4
33293.2
150661.9
482576.4
Memento_distance_Norman = [
94898.1
11946.3
41705.2
49257.4
55506.0
40735.6
42528.7
157722.4
494299.7
Memento_distance_Workman = [
88241.5
27522.1
44986.1
53199.2
56532.1
28531.4
30073.5
154436.5
483522.4
Memento_distance_MTGap = [
98647.0
11271.0
39742.2
56656.3
52853.7
27673.4
32138.7
156857.9
475840.1
Memento_distance_QGMLWB = [
95535.8
13626.8
29471.0
73752.0
77800.2
28531.4
25052.7
177326.1
521096.0
Memento_distance_Colemak = [
89542.2
11946.3
25454.4
66715.1
75738.6
28531.4
33293.2
150661.9
481883.0
Memento_distance_Asset = [
94491.4
11946.3
25454.4
57802.9
78719.3
28531.4
42528.7
159346.9
498821.2
Memento_distance_CapewellDvorak = [ = [
109664.9
9182.2
30268.1
47610.7
71805.3
25808.3
44566.5
158277.4
497183.2
Memento_distance_Klausler = [
109687.3
22941.7
25209.9
49823.5
70722.5
29317.4
24235.9
165482.3
497420.5
Memento_distance_Dvorak = [
111455.5
8832.3
17558.7
69048.5
76275.1
28439.8
38594.2
166387.9
516592.0

Memento_taps_Engram2 = [
33554
12430
27876
20522
25989
22447
13622
32485
188925
Memento_taps_Engram3 = [
33782
14158
27876
18794
25989
22447
14904
30881
188831
Memento_taps_Exgram = [
33782
14158
27876
18794
24754
22447
16139
30881
188831
Memento_taps_Halmak = [
37200
16826
18918
20266
19443
20678
21231
35000
189562
Memento_taps_Hieamtsrn = [
34717
12806
28116
21485
29681
14923
14355
32737
188820
Memento_taps_ColemakModDH = [
33825
10163
14719
27427
29373
22092
16422
32109
186130
Memento_taps_Norman = [
34753
11392
26165
22602
23781
18623
22107
28449
187872
Memento_taps_Workman = [
33571
15812
18383
24064
24136
22092
18376
29948
186382
Memento_taps_MTGap = [
37515
12823
19804
26340
21477
21894
15358
31570
186781
Memento_taps_QGMLWB = [
31251
11849
19371
28892
28779
22092
17047
30758
190039
Memento_taps_Colemak = [
33825
10163
14719
27427
29373
22092
16422
32109
186130
Memento_taps_Asset = [
34667
11392
21722
25526
28256
15422
22107
28862
187954
Memento_taps_CapewellDvorak = [ = [
39409
12142
22928
20219
26079
17916
20557
30071
189321
Memento_taps_Klausler = [
39559
15443
21690
21740
27395
18983
12498
32108
189416
Memento_taps_Dvorak = [
38261
13607
19970
21104
25309
18812
19228
33442
189733

Memento_samefinger_Engram2 = [
1854
97
1306
595
0
0
715
23
97
1051
5738
Memento_samefinger_Engram3 = [
1918
427
1306
334
0
0
715
23
168
1048
5939
Memento_samefinger_Exgram = [
1918
427
1306
334
0
0
370
23
253
1048
5679
Memento_samefinger_Halmak = [
1456
21
163
495
0
0
1055
560
999
2071
6820
Memento_samefinger_Hieamtsrn = [
2286
84
1332
418
0
0
148
120
110
1550
6048
Memento_samefinger_ColemakModDH = [
2061
116
120
107
0
0
623
604
270
1579
5480
Memento_samefinger_Norman = [
2009
86
2324
90
0
0
1833
756
952
1956
10006
Memento_samefinger_Workman = [
1956
265
276
392
0
0
1109
604
500
1441
6543
Memento_samefinger_MTGap = [
2203
192
104
94
0
0
762
637
216
3067
7275
Memento_samefinger_QGMLWB = [
1326
95
344
974
0
0
2890
604
329
2348
8910
Memento_samefinger_Colemak = [
2061
116
120
107
0
0
623
604
270
1579
5480
Memento_samefinger_Asset = [
1899
86
926
81
0
0
1173
127
952
1542
6786
Memento_samefinger_CapewellDvorak = [ = [
2384
28
1089
1362
0
0
482
38
239
1491
7113
Memento_samefinger_Klausler = [
2446
154
698
1670
0
0
650
23
9
1717
7367
Memento_samefinger_Dvorak = [
2405
21
518
1396
0
0
498
492
163
1492
6985

Tweets_100K_distance_Engram2 = [
2087787.3
756329.8
1924024.8
1521062.0
2506857.0
1672844.0
967345.6
3256289.9
14692540.4
Tweets_100K_distance_Engram3 = [
2092041.1
1076623.4
1924024.8
1203600.1
2506751.0
1672844.0
1013846.9
3219938.7
14709670.1
Tweets_100K_distance_Exgram = [
2092041.1
1076623.4
1924024.8
1203600.1
2113016.1
1672844.0
1413039.5
3219938.7
14715127.8
Tweets_100K_distance_Halmak = [
2154544.8
1930741.0
1331619.2
1310032.1
1567010.5
748343.9
1226652.6
3548660.6
13817604.8
Tweets_100K_distance_Hieamtsrn = [
1348202.4
751091.1
1889407.8
1928067.8
3370945.7
951733.0
890933.9
3360425.1
14490806.7
Tweets_100K_distance_ColemakModDH = [
1328914.1
968799.3
988425.9
2747434.4
3192557.7
820667.2
1046852.1
2801874.1
13895524.8
Tweets_100K_distance_Norman = [
1340538.7
968799.3
1444262.5
2329739.9
2593809.1
1207393.9
1200692.1
2766330.0
13851565.5
Tweets_100K_distance_Workman = [
1267186.7
1227421.5
1885903.2
2598978.5
2393353.8
820667.2
787794.4
2866597.1
13847902.4
Tweets_100K_distance_MTGap = [
1478291.6
778304.2
1530578.3
2338058.6
2647497.9
879359.9
1052964.2
2844426.7
13549481.4
Tweets_100K_distance_QGMLWB = [
1325411.1
1019020.1
1340051.8
3023368.0
3623460.0
820667.2
621040.8
2852080.5
14625099.5
Tweets_100K_distance_Colemak = [
1328914.1
968799.3
988425.9
2862301.8
3150386.7
820667.2
1046852.1
2801874.1
13968221.1
Tweets_100K_distance_Asset = [
1328975.8
968799.3
988425.9
2459632.8
3578033.7
820667.2
1200692.1
2774004.4
14119231.1
Tweets_100K_distance_CapewellDvorak = [ = [
1487143.7
535116.9
969711.4
2147031.1
2860823.2
1244980.1
1508290.1
3038947.3
13792043.8
Tweets_100K_distance_Klausler = [
1622397.8
858035.7
901022.9
2040177.9
3004076.7
1411339.3
824825.7
3259494.1
13921370.0
Tweets_100K_distance_Dvorak = [
1517448.5
508247.2
485654.9
3213344.6
3241556.3
1157656.6
1337003.0
3396762.5
14857673.6

Tweets_100K_taps_Engram2 = [
570093
608440
1090451
803929
1004159
905985
586816
860756
6430629
Tweets_100K_taps_Engram3 = [
575321
681775
1090451
730594
1004159
905985
623064
819297
6430646
Tweets_100K_taps_Exgram = [
575321
681775
1090451
730594
962641
905985
664582
819297
6430646
Tweets_100K_taps_Halmak = [
796589
742757
714394
806595
876199
758796
795697
973213
6464240
Tweets_100K_taps_Hieamtsrn = [
541051
606892
1083678
947406
1294889
578527
540302
875122
6467867
Tweets_100K_taps_ColemakModDH = [
682856
480572
581189
1129823
1192142
774214
731751
884398
6456945
Tweets_100K_taps_Norman = [
684852
544418
923323
1003298
1027305
734479
879511
657566
6454752
Tweets_100K_taps_Workman = [
671997
611345
741958
1094201
997347
774214
740842
822809
6454713
Tweets_100K_taps_MTGap = [
762882
603446
754559
1073266
999274
787675
575978
898919
6455999
Tweets_100K_taps_QGMLWB = [
447639
556261
826788
1165694
1332105
774214
691857
668123
6462681
Tweets_100K_taps_Colemak = [
682856
480572
581189
1129823
1192142
774214
731751
884398
6456945
Tweets_100K_taps_Asset = [
682846
544418
811575
1047633
1196788
625141
879511
666454
6454366
Tweets_100K_taps_CapewellDvorak = [ = [
769495
533695
853691
937348
1024760
803870
759140
785993
6467992
Tweets_100K_taps_Klausler = [
807522
660980
790337
931317
1116608
846542
474531
840996
6468833
Tweets_100K_taps_Dvorak = [
727928
573674
740196
968265
1036441
781429
716998
924947
6469878

Tweets_100K_samefinger_Engram2 = [
5271
6447
12321
24434
0
0
24906
2827
4259
79738
160203
Tweets_100K_samefinger_Engram3 = [
9391
23756
12321
12712
0
0
24906
2827
4598
75167
165678
Tweets_100K_samefinger_Exgram = [
9391
23756
12321
12712
0
0
14207
2827
10787
75167
161168
Tweets_100K_samefinger_Halmak = [
11789
6055
9071
18985
0
0
42034
10460
43913
100044
242351
Tweets_100K_samefinger_Hieamtsrn = [
13716
5066
7399
15381
0
0
14567
7525
7280
84566
155500
Tweets_100K_samefinger_ColemakModDH = [
19454
3602
7614
14277
0
0
27363
8450
13305
82224
176289
Tweets_100K_samefinger_Norman = [
20294
5138
70764
10426
0
0
97096
32818
46124
78141
360801
Tweets_100K_samefinger_Workman = [
15554
8636
7150
21161
0
0
59606
8450
21572
83511
225640
Tweets_100K_samefinger_MTGap = [
19532
12512
2352
12273
0
0
51182
7937
8764
84293
198845
Tweets_100K_samefinger_QGMLWB = [
6139
4858
12022
42462
0
0
151585
8450
13061
80317
318894
Tweets_100K_samefinger_Colemak = [
19454
3602
7614
14277
0
0
27363
8450
13305
82224
176289
Tweets_100K_samefinger_Asset = [
20004
5138
34215
7864
0
0
68682
3324
46124
74158
259509
Tweets_100K_samefinger_CapewellDvorak = [ = [
27189
3502
34848
59191
0
0
23231
7150
13578
81900
250589
Tweets_100K_samefinger_Klausler = [
38074
4069
7959
58716
0
0
28454
3437
1136
85984
227829
Tweets_100K_samefinger_Dvorak = [
26129
1600
13601
61445
0
0
28743
15962
9006
89816
246302

Tweets_20K_distance_Engram2 = [
827967.4
190513.8
489342.1
432633.0
748985.7
414539.9
274383.8
1350474.0
4728839.8
Tweets_20K_distance_Engram3 = [
877386.1
252786.2
489342.1
371158.5
753248.1
414539.9
262816.5
1313689.9
4734967.3
Tweets_20K_distance_Exgram = [
877386.1
252786.2
489342.1
371158.5
647684.7
414539.9
370989.1
1313689.9
4737576.5
Tweets_20K_distance_Halmak = [
804427.9
481673.9
462393.2
545563.6
532615.6
213225.5
332700.2
1302592.0
4675191.9
Tweets_20K_distance_Hieamtsrn = [
669355.1
199784.7
602938.4
522540.0
814662.6
328413.5
260001.1
1340124.4
4737819.7
Tweets_20K_distance_ColemakModDH = [
566778.0
253396.8
400494.2
812638.0
863733.2
216427.9
256859.2
1277370.9
4647698.2
Tweets_20K_distance_Norman = [
576596.0
253396.8
506668.1
645251.3
701641.3
349630.0
326855.8
1255515.7
4615554.8
Tweets_20K_distance_Workman = [
556632.6
343406.7
560144.0
758660.9
638035.4
216427.9
264735.3
1281595.5
4619638.4
Tweets_20K_distance_MTGap = [
642229.0
238311.9
500314.0
692751.7
702656.4
229476.5
310416.3
1188922.6
4505078.5
Tweets_20K_distance_QGMLWB = [
585695.7
258078.5
444177.8
876596.1
911314.9
216427.9
186826.9
1265809.6
4744927.5
Tweets_20K_distance_Colemak = [
566778.0
253396.8
400494.2
824699.3
844468.9
216427.9
256859.2
1277370.9
4640495.2
Tweets_20K_distance_Asset = [
574281.6
253396.8
400494.2
687049.9
948654.2
216427.9
326855.8
1256734.5
4663894.8
Tweets_20K_distance_CapewellDvorak = [ = [
708612.8
151349.5
371843.7
647945.9
776762.6
292143.1
440776.1
1165591.3
4555025.0
Tweets_20K_distance_Klausler = [
691510.2
218659.5
295114.9
676267.9
834534.2
321868.7
250193.0
1317054.7
4605203.0
Tweets_20K_distance_Dvorak = [
713303.8
143896.6
198760.0
851698.8
832010.7
351565.5
423853.1
1274209.6
4789298.0

Tweets_20K_taps_Engram2 = [
208894
138064
286632
216176
273104
246031
159822
301108
1829831
Tweets_20K_taps_Engram3 = [
222632
152405
286632
201835
273104
246031
157309
289951
1829899
Tweets_20K_taps_Exgram = [
222632
152405
286632
201835
254276
246031
176137
289951
1829899
Tweets_20K_taps_Halmak = [
252716
193598
202587
267502
241721
213050
194793
277057
1843024
Tweets_20K_taps_Hieamtsrn = [
204214
143654
315200
240044
335537
174442
150421
286713
1850225
Tweets_20K_taps_ColemakModDH = [
218053
129810
182525
327229
309243
213601
158358
301448
1840267
Tweets_20K_taps_Norman = [
219755
145126
276006
282317
266611
180906
206309
262740
1839770
Tweets_20K_taps_Workman = [
216262
168764
208353
312469
255657
213601
183330
280827
1839263
Tweets_20K_taps_MTGap = [
228274
166708
210617
308994
262830
216636
161497
283368
1838924
Tweets_20K_taps_QGMLWB = [
159607
146854
245087
314831
336795
213601
161875
263738
1842388
Tweets_20K_taps_Colemak = [
218053
129810
182525
327229
309243
213601
158358
301448
1840267
Tweets_20K_taps_Asset = [
219358
145126
249882
295477
314452
145656
206309
263318
1839578
Tweets_20K_taps_CapewellDvorak = [ = [
241447
142782
245755
243926
276562
215635
203980
274318
1844405
Tweets_20K_taps_Klausler = [
241644
163132
224719
252350
297519
223688
137896
304128
1845076
Tweets_20K_taps_Dvorak = [
247560
137681
205125
247540
271305
230024
198723
307947
1845905

Tweets_20K_samefinger_Engram2 = [
4572
1807
3433
7217
0
0
6532
1117
1613
33852
60143
Tweets_20K_samefinger_Engram3 = [
4949
5203
3433
4397
0
0
6532
1117
1497
31540
58668
Tweets_20K_samefinger_Exgram = [
4949
5203
3433
4397
0
0
3409
1117
2587
31540
56635
Tweets_20K_samefinger_Halmak = [
16292
2047
2755
15230
0
0
9918
3391
7842
27557
85032
Tweets_20K_samefinger_Hieamtsrn = [
13032
1339
2776
4554
0
0
4998
2281
1827
28938
59745
Tweets_20K_samefinger_ColemakModDH = [
7872
1260
2939
14496
0
0
7618
2687
1980
37016
75868
Tweets_20K_samefinger_Norman = [
8470
1884
20278
4474
0
0
19321
9515
11622
31381
106945
Tweets_20K_samefinger_Workman = [
6722
3036
3019
7946
0
0
13495
2687
5298
26143
68346
Tweets_20K_samefinger_MTGap = [
8486
3601
1668
13798
0
0
10673
2794
2491
26054
69565
Tweets_20K_samefinger_QGMLWB = [
3482
1856
5077
12339
0
0
34669
2687
3728
31012
94850
Tweets_20K_samefinger_Colemak = [
7872
1260
2939
14496
0
0
7618
2687
1980
37016
75868
Tweets_20K_samefinger_Asset = [
8350
1884
10968
3906
0
0
13599
1359
11622
25935
77623
Tweets_20K_samefinger_CapewellDvorak = [ = [
11182
1064
17648
15759
0
0
7320
1732
3307
23927
81939
Tweets_20K_samefinger_Klausler = [
14186
944
2964
15999
0
0
8023
1248
659
43476
87499
Tweets_20K_samefinger_Dvorak = [
10859
511
2280
15715
0
0
7166
4823
2428
41962
85744

Tweets_MASC_distance_Engram2 = [
58340.2
13952.4
36877.7
30025.4
62970.4
29576.8
19716.5
80550.0
332009.4
Tweets_MASC_distance_Engram3 = [
60842.8
19233.8
36877.7
24825.4
54558.6
29576.8
19445.6
77646.6
323007.3
Tweets_MASC_distance_Exgram = [
60842.8
19233.8
36877.7
24825.4
46698.8
29576.8
27851.4
77646.6
323553.3
Tweets_MASC_distance_Halmak = [
51012.9
33352.8
33008.1
36960.4
42543.8
15094.3
22686.9
85809.9
320469.1
Tweets_MASC_distance_Hieamtsrn = [
40935.7
14518.6
41371.2
38760.1
62043.0
23979.4
19107.8
83846.6
324562.5
Tweets_MASC_distance_ColemakModDH = [
34478.5
14046.3
25911.0
56905.8
59835.8
16485.0
21793.4
81824.1
311279.8
Tweets_MASC_distance_Norman = [
36238.7
14046.3
31804.1
48378.0
51303.3
29896.4
27498.6
80146.8
319312.2
Tweets_MASC_distance_Workman = [
33817.1
18671.6
42434.2
55716.4
47265.4
16485.0
21599.6
82426.1
318415.4
Tweets_MASC_distance_MTGap = [
41531.6
12793.6
29452.1
48724.0
52002.7
16951.1
22620.9
79374.6
303450.7
Tweets_MASC_distance_QGMLWB = [
35498.4
17116.8
30257.3
66240.1
72583.3
16485.0
15303.1
80737.1
334221.2
Tweets_MASC_distance_Colemak = [
34478.5
14046.3
25911.0
59702.1
59136.2
16485.0
21793.4
81824.1
313376.5
Tweets_MASC_distance_Asset = [
36030.4
14046.3
25911.0
48861.5
66526.2
16485.0
27498.6
80322.2
315681.2
Tweets_MASC_distance_CapewellDvorak = [ = [
44519.8
7037.5
26145.1
43672.0
56117.4
24254.4
36454.4
74121.5
312322.1
Tweets_MASC_distance_Klausler = [
43413.7
15057.2
18341.8
44713.5
63606.6
27700.2
18754.6
85478.6
317066.2
Tweets_MASC_distance_Dvorak = [
45104.4
6394.2
12883.6
65337.4
63457.7
25924.7
33471.8
83117.3
335691.0

Tweets_MASC_taps_Engram2 = [
15178
11625
20760
15106
21492
17594
11552
19517
132824
Tweets_MASC_taps_Engram3 = [
15986
12847
20760
13884
21492
17594
12197
18046
132806
Tweets_MASC_taps_Exgram = [
15986
12847
20760
13884
19582
17594
14107
18046
132806
Tweets_MASC_taps_Halmak = [
16991
13076
15626
19039
18765
14874
14329
20701
133401
Tweets_MASC_taps_Hieamtsrn = [
12460
11801
22195
17872
25010
12581
12005
19554
133478
Tweets_MASC_taps_ColemakModDH = [
14299
9935
12765
23542
22454
15198
14179
20964
133336
Tweets_MASC_taps_Norman = [
14604
9864
18729
20903
20183
15888
16766
16410
133347
Tweets_MASC_taps_Workman = [
14181
11010
15005
23151
19439
15198
14800
20521
133305
Tweets_MASC_taps_MTGap = [
16282
11217
14535
22278
19369
15301
12732
21664
133378
Tweets_MASC_taps_QGMLWB = [
9867
10630
17614
24503
25934
15198
13064
16610
133420
Tweets_MASC_taps_Colemak = [
14299
9935
12765
23542
22454
15198
14179
20964
133336
Tweets_MASC_taps_Asset = [
14567
9864
17329
21187
22752
12359
16766
18537
133361
Tweets_MASC_taps_CapewellDvorak = [ = [
16896
9598
17961
18810
19041
16387
16514
18176
133383
Tweets_MASC_taps_Klausler = [
16899
12173
15485
19196
23137
17177
9157
20230
133454
Tweets_MASC_taps_Dvorak = [
16566
10099
14851
19319
19480
16727
15758
20678
133478

Tweets_MASC_samefinger_Engram2 = [
189
153
283
491
0
0
1217
92
142
1297
3864
Tweets_MASC_samefinger_Engram3 = [
692
477
283
279
0
0
1217
92
94
1259
4393
Tweets_MASC_samefinger_Exgram = [
692
477
283
279
0
0
388
92
458
1259
3928
Tweets_MASC_samefinger_Halmak = [
455
97
208
1013
0
0
886
247
658
2164
5728
Tweets_MASC_samefinger_Hieamtsrn = [
465
125
180
312
0
0
467
161
403
2045
4158
Tweets_MASC_samefinger_ColemakModDH = [
407
59
174
850
0
0
536
201
273
2149
4649
Tweets_MASC_samefinger_Norman = [
464
129
1658
297
0
0
1803
774
1144
1738
8007
Tweets_MASC_samefinger_Workman = [
333
166
207
720
0
0
1276
201
510
1936
5349
Tweets_MASC_samefinger_MTGap = [
613
228
77
751
0
0
818
182
444
2080
5193
Tweets_MASC_samefinger_QGMLWB = [
137
102
409
1139
0
0
3030
201
253
1911
7182
Tweets_MASC_samefinger_Colemak = [
407
59
174
850
0
0
536
201
273
2149
4649
Tweets_MASC_samefinger_Asset = [
450
129
898
282
0
0
1178
109
1144
1711
5901
Tweets_MASC_samefinger_CapewellDvorak = [ = [
875
66
1199
1418
0
0
467
207
276
1599
6107
Tweets_MASC_samefinger_Klausler = [
1040
75
179
1247
0
0
860
72
56
2176
5705
Tweets_MASC_samefinger_Dvorak = [
748
30
261
1521
0
0
575
532
205
2232
6104

Spoken_MASC_distance_Engram2 = [
31904.6
11878.6
33032.9
40302.3
38954.3
23273.3
17592.4
117978.6
314916.9
Spoken_MASC_distance_Engram3 = [
31747.7
16534.1
33032.9
36052.7
47698.2
23273.3
17809.8
117928.9
324077.6
Spoken_MASC_distance_Exgram = [
31747.7
16534.1
33032.9
36052.7
41759.4
23273.3
23796.4
117928.9
324125.4
Spoken_MASC_distance_Halmak = [
40088.6
21597.8
22139.2
22285.1
19659.9
15525.0
18704.4
129009.3
289009.2
Spoken_MASC_distance_Hieamtsrn = [
25101.8
17384.0
32442.0
33915.3
50307.9
13885.9
12789.3
116438.2
302264.3
Spoken_MASC_distance_ColemakModDH = [
24259.4
11933.5
14047.5
40565.0
55864.5
21441.7
17457.7
116774.0
302343.3
Spoken_MASC_distance_Norman = [
24542.2
11933.5
21428.9
33593.5
41289.2
24609.1
17953.4
116832.0
292181.9
Spoken_MASC_distance_Workman = [
23822.5
14073.4
27924.7
40451.4
35982.5
21441.7
11231.4
117633.8
292561.3
Spoken_MASC_distance_MTGap = [
31946.7
6691.9
32081.5
32957.1
41715.2
19630.5
15786.0
114542.4
295351.3
Spoken_MASC_distance_QGMLWB = [
25543.2
8717.9
17267.1
50345.8
54239.2
21441.7
10231.3
114939.0
302725.1
Spoken_MASC_distance_Colemak = [
24259.4
11933.5
14047.5
41263.1
53640.0
21441.7
17457.7
116774.0
300817.0
Spoken_MASC_distance_Asset = [
24393.9
11933.5
14047.5
36169.1
62183.4
21441.7
17953.4
116169.0
304291.5
Spoken_MASC_distance_CapewellDvorak = [ = [
25897.0
6903.8
13976.7
37651.8
40836.8
20142.1
24039.1
116155.9
285603.1
Spoken_MASC_distance_Klausler = [
26490.4
12509.5
19638.6
30463.4
50926.1
17798.5
12013.9
119846.1
289686.6
Spoken_MASC_distance_Dvorak = [
25793.9
6459.1
7045.4
49013.6
45652.8
19649.8
22175.3
123090.8
298880.6

Spoken_MASC_taps_Engram2 = [
8719
9606
20577
16531
16794
16077
10281
19851
118436
Spoken_MASC_taps_Engram3 = [
8672
10684
20577
15453
16794
16077
10793
19372
118422
Spoken_MASC_taps_Exgram = [
8672
10684
20577
15453
16526
16077
11061
19372
118422
Spoken_MASC_taps_Halmak = [
14526
12671
12126
15531
12392
15877
13005
22708
118836
Spoken_MASC_taps_Hieamtsrn = [
11782
10883
20440
15626
22192
9345
8512
19771
118551
Spoken_MASC_taps_ColemakModDH = [
12088
7626
9346
19345
20747
17247
10901
21492
118792
Spoken_MASC_taps_Norman = [
12138
8873
17239
17512
17117
12768
13445
19768
118860
Spoken_MASC_taps_Workman = [
12011
9440
13663
19389
16105
17247
11111
19839
118805
Spoken_MASC_taps_MTGap = [
14713
9290
14570
18319
16129
16828
9206
19882
118937
Spoken_MASC_taps_QGMLWB = [
8195
8066
14575
19473
20908
17247
10803
19570
118837
Spoken_MASC_taps_Colemak = [
12088
7626
9346
19345
20747
17247
10901
21492
118792
Spoken_MASC_taps_Asset = [
12112
8873
15432
18343
20948
11908
13445
17688
118749
Spoken_MASC_taps_CapewellDvorak = [ = [
13544
9249
15319
15719
17736
15091
12574
19671
118903
Spoken_MASC_taps_Klausler = [
13678
10547
16829
14235
18756
14703
9623
20603
118974
Spoken_MASC_taps_Dvorak = [
12661
9979
13706
15903
17489
14962
12131
22153
118984

Spoken_MASC_samefinger_Engram2 = [
27
99
173
563
0
0
502
26
42
325
1757
Spoken_MASC_samefinger_Engram3 = [
19
351
173
363
0
0
502
26
45
193
1672
Spoken_MASC_samefinger_Exgram = [
19
351
173
363
0
0
356
26
117
193
1598
Spoken_MASC_samefinger_Halmak = [
189
52
65
361
0
0
375
244
698
887
2871
Spoken_MASC_samefinger_Hieamtsrn = [
338
112
151
293
0
0
187
113
59
343
1596
Spoken_MASC_samefinger_ColemakModDH = [
134
22
113
99
0
0
584
368
113
889
2322
Spoken_MASC_samefinger_Norman = [
140
35
1161
75
0
0
1299
473
449
879
4511
Spoken_MASC_samefinger_Workman = [
116
61
211
350
0
0
1069
368
397
506
3078
Spoken_MASC_samefinger_MTGap = [
492
105
15
84
0
0
506
330
87
1507
3126
Spoken_MASC_samefinger_QGMLWB = [
28
61
220
391
0
0
1794
368
190
867
3919
Spoken_MASC_samefinger_Colemak = [
134
22
113
99
0
0
584
368
113
889
2322
Spoken_MASC_samefinger_Asset = [
135
35
662
48
0
0
902
38
449
563
2832
Spoken_MASC_samefinger_CapewellDvorak = [ = [
479
36
678
775
0
0
460
123
74
783
3408
Spoken_MASC_samefinger_Klausler = [
569
22
330
676
0
0
283
25
4
697
2606
Spoken_MASC_samefinger_Dvorak = [
200
100
207
775
0
0
511
326
65
772
2956

COCA_blogs_distance_Engram2 = [
1638526.8
595437.8
1845339.7
1426202.3
2730231.3
1452126.0
975102.0
1938587.2
12601553.0
COCA_blogs_distance_Engram3 = [
1714074.9
763441.1
1845339.7
1258703.1
2540946.5
1452126.0
897608.7
1927496.9
12399736.9
COCA_blogs_distance_Exgram = [
1714074.9
763441.1
1845339.7
1258703.1
2102901.6
1452126.0
1335539.0
1927496.9
12399622.3
COCA_blogs_distance_Halmak = [
1774467.9
1493613.7
1606552.5
1470536.8
1365957.4
738440.5
1085214.6
2087906.2
11622689.6
COCA_blogs_distance_Hieamtsrn = [
1143152.5
605485.2
1875206.9
1482673.1
2708925.6
1175707.0
885627.1
1874879.4
11751656.6
COCA_blogs_distance_ColemakModDH = [
856756.7
556542.6
1199294.7
2748002.5
2922862.0
942954.0
841506.9
1570334.3
11638253.7
COCA_blogs_distance_Norman = [
889469.7
556542.6
1553040.7
2161300.5
2286825.0
1581318.4
1171401.4
1516192.9
11716091.2
COCA_blogs_distance_Workman = [
834311.0
913014.9
1953894.9
2595441.0
2116650.8
942954.0
797336.1
1602646.2
11756248.8
COCA_blogs_distance_MTGap = [
1158226.0
559121.3
1572850.4
2095892.9
2308046.9
875959.3
1150340.0
1502833.6
11223270.4
COCA_blogs_distance_QGMLWB = [
916752.5
590454.3
1312010.0
3228188.4
3335246.1
942954.0
607511.8
1504761.8
12437878.8
Colemak = [
856756.7
556542.6
1199294.7
2801553.6
2849065.3
942954.0
841506.9
1570334.3
11618008.1
Asset = [
880669.5
556542.6
1199294.7
2320115.4
3141198.9
942954.0
1171401.4
1528977.0
11741153.4
CapewellDvorak = [
1035248.9
335872.4
1014558.1
2053965.3
2761217.4
1003422.5
1779571.0
1536770.4
11520625.9
Klausler = [
1067390.6
583212.7
879527.3
1927064.3
3116710.7
1122159.2
928160.0
2000212.0
11624436.8
Dvorak = [
1064382.0
310172.7
346465.4
2963689.8
3020449.6
1206828.2
1676315.5
2007717.5
12596020.5

COCA_blogs_taps_Engram2 = [
515844
566272
1173819
810064
981485
907329
613793
716835
6285441
COCA_blogs_taps_Engram3 = [
540041
605206
1173819
771130
981485
907329
615469
691187
6285666
COCA_blogs_taps_Exgram = [
540041
605206
1173819
771130
900937
907329
696017
691187
6285666
COCA_blogs_taps_Halmak = [
751878
683820
805445
896346
806432
879869
728358
751894
6304042
COCA_blogs_taps_Hieamtsrn = [
518333
574011
1180674
827825
1198472
668358
592211
715613
6275497
COCA_blogs_taps_ColemakModDH = [
618213
470079
668166
1168023
1144067
927186
630770
672103
6298607
COCA_blogs_taps_Norman = [
623935
506936
1075735
1014044
975752
823564
787298
491559
6298823
COCA_blogs_taps_Workman = [
614280
599763
776600
1126179
952706
927186
664690
636528
6297932
COCA_blogs_taps_MTGap = [
680903
609598
788978
1064077
944652
911673
649097
648812
6297790
COCA_blogs_taps_QGMLWB = [
366389
517100
869547
1236032
1285795
927186
610025
490400
6302474
Colemak = [
618213
470079
668166
1168023
1144067
927186
630770
672103
6298607
Asset = [
622393
506936
989890
1061480
1132915
655738
787298
541923
6298573
CapewellDvorak = [
654705
546320
943933
918787
1015277
792328
842405
588086
6301841
Klausler = [
662356
610958
911481
895921
1172946
825465
513549
709747
6302423
Dvorak = [
667318
533762
786407
907194
992132
840765
817169
757899
6302646

COCA_blogs_samefinger_Engram2 = [
2129
4141
12555
21196
0
0
10248
1913
3824
12639
68645
COCA_blogs_samefinger_Engram3 = [
2675
14452
12555
14891
0
0
10248
1913
4360
8803
69897
COCA_blogs_samefinger_Exgram = [
2675
14452
12555
14891
0
0
2597
1913
8381
8803
66267
COCA_blogs_samefinger_Halmak = [
9599
2336
10825
20029
0
0
34886
15212
27097
14139
134123
COCA_blogs_samefinger_Hieamtsrn = [
19390
3732
9169
12041
0
0
9271
7210
4309
12715
77837
COCA_blogs_samefinger_ColemakModDH = [
8591
2838
7214
9689
0
0
21354
6702
2599
18005
76992
COCA_blogs_samefinger_Norman = [
9657
3037
111893
7325
0
0
70841
39801
32348
22682
297584
COCA_blogs_samefinger_Workman = [
7151
5987
9949
23597
0
0
52774
6702
26980
10671
143811
COCA_blogs_samefinger_MTGap = [
12945
12017
1839
7621
0
0
30257
6687
7724
9272
88362
COCA_blogs_samefinger_QGMLWB = [
1071
3333
18765
39522
0
0
123835
6702
12417
22576
228221
Colemak = [
8591
2838
7214
9689
0
0
21354
6702
2599
18005
76992
Asset = [
9263
3037
59245
5832
0
0
42552
3752
32348
10401
166430
CapewellDvorak = [
17423
2033
43124
54903
0
0
23660
3512
10896
11977
167528
Klausler = [
23915
371
6686
52822
0
0
28103
3041
610
13391
128939
Dvorak = [
14291
113
1667
46534
0
0
20913
20515
10773
16703
131509

iweb_distance_Engram2 = [
9164499.4
3347614.1
10543924.9
7969894.1
16059053.6
8360759.0
5522514.1
11371913.3
72340172.3
iweb_distance_Engram3 = [
9909496.4
4233648.5
10543924.9
7096781.1
13792131.4
8360759.0
4788694.1
11300359.2
70025794.5
iweb_distance_Exgram = [
9909496.4
4233648.5
10543924.9
7096781.1
10975821.0
8360759.0
7621632.5
11300359.2
70042422.6
iweb_distance_Halmak = [
9419294.9
8623276.0
9760442.6
8419191.0
7955907.1
4517922.3
6344752.6
11947563.0
66988349.5
iweb_distance_Hieamtsrn = [
6473195.8
3402052.2
10614165.3
8054091.7
15356999.1
7194833.3
5180113.0
11017005.4
67292455.7
iweb_distance_ColemakModDH = [
4112869.3
3071102.1
7401898.6
15856176.9
16180927.0
5567947.9
4733226.1
9308979.8
66233127.6
iweb_distance_Norman = [
4308336.0
3071102.1
9458047.0
12104303.1
13431893.2
9497545.9
6857490.2
8997485.0
67726202.4
iweb_distance_Workman = [
4128791.3
5401296.0
11663713.6
14862366.5
12296027.8
5567947.9
4796386.1
9282232.1
67998761.3
iweb_distance_MTGap = [
5958510.6
3344120.7
8308022.6
12308538.7
13258772.2
4800710.3
6775884.9
9026980.6
63781540.6
iweb_distance_QGMLWB = [
4445888.9
3364197.0
7864755.8
18999710.5
19096155.4
5567947.9
3464405.9
8959190.8
71762252.3
iweb_distance_Colemak = [
4112869.3
3071102.1
7401898.6
16046231.3
15818671.4
5567947.9
4733226.1
9308979.8
66060926.5
iweb_distance_Asset = [
4276589.8
3071102.1
7401898.6
13003768.5
17519950.7
5567947.9
6857490.2
9039908.3
66738656.1
iweb_distance_CapewellDvorak = [ = [
5272106.9
1890549.3
6197933.3
12096009.7
16228202.0
5500792.8
10576987.0
8639509.4
66402090.3
iweb_distance_Klausler = [
5869886.2
3220975.3
4866524.8
11288418.0
18403949.2
6266196.6
5266048.1
11651345.8
66833344.1
iweb_distance_Dvorak = [
5436616.3
1709925.9
1915032.9
17145406.8
17275358.1
7132350.2
10149547.9
11456547.1
72220785.1

iweb_taps_Engram2 = [
3001132
3233904
6767298
4578171
5576490
5157643
3596919
4202863
36114420
iweb_taps_Engram3 = [
3232215
3438878
6767298
4373197
5576490
5157643
3422812
4143635
36112168
iweb_taps_Exgram = [
3232215
3438878
6767298
4373197
4870810
5157643
4128492
4143635
36112168
iweb_taps_Halmak = [
4269573
3810031
4727117
5088908
4614959
5151304
4230331
4287205
36179428
iweb_taps_Hieamtsrn = [
2812034
3248804
6782925
4628359
6774116
4043335
3563631
4211819
36065023
iweb_taps_ColemakModDH = [
3400043
2800625
4051343
6682276
6411562
5394214
3550571
3876090
36166724
iweb_taps_Norman = [
3434069
2965052
6344684
5714886
5665905
4827975
4527855
2685285
36165711
iweb_taps_Workman = [
3402786
3577751
4431620
6392123
5485815
5394214
3848410
3634296
36167015
iweb_taps_MTGap = [
3800079
3528888
4320964
6120170
5523374
5216625
3905164
3752295
36167559
iweb_taps_QGMLWB = [
2007468
3047903
5001602
7217666
7369018
5394214
3466797
2676162
36180830
iweb_taps_Colemak = [
3400043
2800625
4051343
6682276
6411562
5394214
3550571
3876090
36166724
iweb_taps_Asset = [
3428505
2965052
5842870
5991862
6364034
3802234
4527855
3242477
36164889
iweb_taps_CapewellDvorak = [ = [
3624191
3117803
5497187
5371258
5795761
4414598
4899821
3458332
36178951
iweb_taps_Klausler = [
3770373
3426115
5224633
5210869
6855978
4626459
2803011
4261489
36178927
iweb_taps_Dvorak = [
3666780
3061601
4484227
5321116
5549228
4816148
4793138
4482995
36175233

iweb_samefinger_Engram2 = [
17264
24882
55657
150715
0
0
105326
14224
27769
136483
532320
iweb_samefinger_Engram3 = [
24861
73939
55657
105902
0
0
105326
14224
25184
120383
525476
iweb_samefinger_Exgram = [
24861
73939
55657
105902
0
0
60636
14224
40913
120383
496515
iweb_samefinger_Halmak = [
89406
13664
70593
160557
0
0
246563
93821
149535
190678
1014817
iweb_samefinger_Hieamtsrn = [
114896
20069
37927
97619
0
0
56817
44696
20779
157255
550058
iweb_samefinger_ColemakModDH = [
58990
12839
44736
71524
0
0
99312
85581
36729
207174
616885
iweb_samefinger_Norman = [
63743
22327
689084
46173
0
0
415876
259702
225030
220706
1942641
iweb_samefinger_Workman = [
48193
39735
66938
154850
0
0
278054
85581
150752
163679
987782
iweb_samefinger_MTGap = [
104965
67130
10315
53542
0
0
179031
55268
46848
249323
766422
iweb_samefinger_QGMLWB = [
20868
18367
125025
238335
0
0
736352
85581
74674
214563
1513765
iweb_samefinger_Colemak = [
58990
12839
44736
71524
0
0
99312
85581
36729
207174
616885
iweb_samefinger_Asset = [
61341
22327
362102
41713
0
0
227843
36295
225030
158020
1134671
iweb_samefinger_CapewellDvorak = [ = [
102617
18561
334304
356228
0
0
126433
24080
74270
159215
1195708
iweb_samefinger_Klausler = [
144673
17708
55265
320043
0
0
164410
12835
3069
179299
897302
iweb_samefinger_Dvorak = [
84777
7861
70921
305848
0
0
115425
139027
70446
202368
996673

Monkey_distance_Engram2 = [
287881.2
87005.4
307909.6
244385.9
492518.1
271660.1
181082.0
404573.4
2277015.8
Monkey_distance_Engram3 = [
306036.7
108255.3
307909.6
223643.6
448805.7
271660.1
155536.8
412624.5
2234472.3
Monkey_distance_Exgram = [
306036.7
108255.3
307909.6
223643.6
363830.2
271660.1
240954.8
412624.5
2234914.8
Monkey_distance_Halmak = [
295533.3
264632.4
302685.6
266868.2
232101.5
124933.7
202761.5
420817.8
2110334.0
Monkey_distance_Hieamtsrn = [
215675.6
90765.0
309675.2
243381.4
473579.3
228190.8
163914.8
385247.7
2110429.8
Monkey_distance_ColemakModDH = [
126843.9
92966.8
231423.8
490053.3
524390.2
170629.6
130356.3
345686.9
2112350.7
Monkey_distance_Norman = [
132110.3
92966.8
301566.9
366496.9
383234.5
311394.7
208883.8
338028.1
2134682.0
Monkey_distance_Workman = [
121983.0
174634.7
364188.8
453196.3
365002.2
170629.6
139750.5
352283.9
2141668.9
Monkey_distance_MTGap = [
192713.9
104486.4
285710.8
370830.8
397898.9
144548.0
209947.8
328634.9
2034771.4
Monkey_distance_QGMLWB = [
136813.8
96492.7
241996.1
595571.1
570040.8
170629.6
102578.4
340702.4
2254824.8
Monkey_distance_Colemak = [
126843.9
92966.8
231423.8
495958.1
509719.4
170629.6
130356.3
345686.9
2103584.8
Monkey_distance_Asset = [
130692.4
92966.8
231423.8
408567.9
536933.5
170629.6
208883.8
340087.6
2120185.3
Monkey_distance_CapewellDvorak = [ = [
179817.5
66233.2
184813.1
335112.6
517078.3
169126.6
335367.4
308874.5
2096423.1
Monkey_distance_Klausler = [
189634.1
102772.3
143944.4
337816.2
571359.5
191574.9
171921.3
399757.3
2108780.0
Monkey_distance_Dvorak = [
189702.0
61829.1
53399.5
504031.6
551454.7
223571.7
312411.7
400559.7
2296960.1

Monkey_taps_Engram2 = [
92936
97071
207397
143198
177747
161463
112149
144428
1136389
Monkey_taps_Engram3 = [
98494
101990
207397
138279
177747
161463
110349
140837
1136556
Monkey_taps_Exgram = [
98494
101990
207397
138279
159441
161463
128655
140837
1136556
Monkey_taps_Halmak = [
131929
123673
149956
158700
140841
158621
126972
147301
1137993
Monkey_taps_Hieamtsrn = [
96598
98296
207799
144129
208856
125085
110860
143658
1135281
Monkey_taps_ColemakModDH = [
106686
87550
124984
205346
206013
169195
106687
130663
1137124
Monkey_taps_Norman = [
107615
90549
201678
173877
169588
154507
133197
106161
1137172
Monkey_taps_Workman = [
105841
111732
145276
195510
167830
169195
111572
130250
1137206
Monkey_taps_MTGap = [
114730
111335
144194
186110
166760
163172
120800
129682
1136783
Monkey_taps_QGMLWB = [
64379
91689
153520
227633
224475
169195
100949
105961
1137801
Monkey_taps_Colemak = [
106686
87550
124984
205346
206013
169195
106687
130663
1137124
Monkey_taps_Asset = [
107367
90549
184614
185623
200566
117621
133197
117621
1137158
Monkey_taps_CapewellDvorak = [ = [
110641
100465
171873
157410
189032
135015
156700
116652
1137788
Monkey_taps_Klausler = [
112316
109168
163071
159357
215020
141415
95533
141946
1137826
Monkey_taps_Dvorak = [
119715
92166
140803
154518
181957
148400
151735
148586
1137880

Monkey_samefinger_Engram2 = [
624
713
1552
4592
0
0
3664
419
706
6497
18767
Monkey_samefinger_Engram3 = [
581
1734
1552
3558
0
0
3664
419
934
5530
17972
Monkey_samefinger_Exgram = [
581
1734
1552
3558
0
0
2087
419
1561
5530
17022
Monkey_samefinger_Halmak = [
2098
500
2403
4955
0
0
7589
2901
3720
10263
34429
Monkey_samefinger_Hieamtsrn = [
3873
610
982
3709
0
0
1933
1409
943
6982
20441
Monkey_samefinger_ColemakModDH = [
2312
382
1412
2068
0
0
3147
3075
1100
10223
23719
Monkey_samefinger_Norman = [
2601
519
24162
1540
0
0
12303
9474
6335
10988
67922
Monkey_samefinger_Workman = [
1904
1104
2266
4780
0
0
8396
3075
4767
9283
35575
Monkey_samefinger_MTGap = [
3347
2238
430
1475
0
0
5282
1721
1778
12801
29072
Monkey_samefinger_QGMLWB = [
556
507
3638
7845
0
0
22051
3075
2306
10397
50375
Monkey_samefinger_Colemak = [
2312
382
1412
2068
0
0
3147
3075
1100
10223
23719
Monkey_samefinger_Asset = [
2475
519
11403
1252
0
0
6595
1094
6335
9030
38703
Monkey_samefinger_CapewellDvorak = [ = [
3993
645
9990
10055
0
0
4469
879
2517
6528
39076
Monkey_samefinger_Klausler = [
4564
572
1716
9511
0
0
5754
405
112
7149
29783
Monkey_samefinger_Dvorak = [
4101
272
1839
7967
0
0
3971
4193
2400
7754
32497

Coder_distance_Engram2 = [
877832.2
251277.1
209134.1
564336.6
718232.8
220925.3
150502.2
1653685.6
4645926.0
Coder_distance_Engram3 = [
907818.0
233267.7
209134.1
580416.4
572756.0
220925.3
121442.3
1649320.3
4495080.3
Coder_distance_Exgram = [
907818.0
233267.7
209134.1
580416.4
501075.9
220925.3
193476.4
1649320.3
4495434.3
Coder_distance_Halmak = [
927452.3
281483.4
281032.7
390764.7
393970.7
168575.6
345586.7
1637800.1
4426666.2
Coder_distance_Hieamtsrn = [
674378.8
208444.8
294746.8
442708.3
362376.9
228107.8
170562.0
1806099.6
4187425.0
Coder_distance_ColemakModDH = [
834091.9
143427.5
240757.1
469448.8
353593.1
231058.2
335037.9
1623384.2
4230798.6
Coder_distance_Norman = [
842628.0
143427.5
272138.6
375148.1
358551.8
339183.6
418113.1
1592984.8
4342175.5
Coder_distance_Workman = [
844128.7
215481.3
336872.0
413584.9
330419.7
231058.2
381234.9
1598126.5
4350906.2
Coder_distance_MTGap = [
924674.9
184330.1
171241.2
390563.8
320175.3
215502.6
375146.3
1591054.9
4172689.0
Coder_distance_QGMLWB = [
849510.1
164435.3
246231.4
547042.6
474932.2
231058.2
329271.0
1632956.3
4475437.2
Coder_distance_Colemak = [
834091.9
143427.5
240757.1
476640.4
356360.6
231058.2
335037.9
1623384.2
4240757.7
Coder_distance_Asset = [
842914.8
143427.5
240757.1
391631.5
359240.9
231058.2
418113.1
1592778.0
4219921.0
Coder_distance_CapewellDvorak = [ = [
874378.6
196699.9
233251.5
357968.5
460749.1
136512.9
467951.0
1637842.1
4365353.6
Coder_distance_Klausler = [
790705.3
233686.9
225598.9
435935.6
482220.0
184979.3
350164.5
1722681.0
4425971.6
Coder_distance_Dvorak = [
914749.7
168161.3
131040.4
530219.8
478086.8
345318.3
468779.3
1505054.4
4541410.0

Coder_taps_Engram2 = [
179443
95161
126847
172429
178254
115531
77841
280194
1225700
Coder_taps_Engram3 = [
188293
90868
126847
176722
178254
115531
81218
268297
1226030
Coder_taps_Exgram = [
188293
90868
126847
176722
161204
115531
98268
268297
1226030
Coder_taps_Halmak = [
215122
78979
120918
148327
131794
114210
104058
297191
1210599
Coder_taps_Hieamtsrn = [
137133
97595
146721
147243
146296
97339
92392
319326
1184045
Coder_taps_ColemakModDH = [
192799
78175
97939
162075
138163
129042
110601
298254
1207048
Coder_taps_Norman = [
194318
71224
138055
136504
137838
135344
124049
268098
1205430
Coder_taps_Workman = [
194582
90262
95403
146994
130734
129042
113013
305939
1205969
Coder_taps_MTGap = [
213957
84722
90769
148421
118503
125712
120785
303411
1206280
Coder_taps_QGMLWB = [
176627
76435
117817
184267
156070
129042
98268
272159
1210685
Coder_taps_Colemak = [
192799
78175
97939
162075
138163
129042
110601
298254
1207048
Coder_taps_Asset = [
194369
71224
130014
141947
134296
105958
124049
303583
1205440
Coder_taps_CapewellDvorak = [ = [
203270
88757
129480
130704
126723
92977
147416
293510
1212837
Coder_taps_Klausler = [
181773
99020
126312
149403
171308
105034
77160
303347
1213357
Coder_taps_Dvorak = [
221149
77968
105395
137824
121862
126881
153238
269361
1213678

Coder_samefinger_Engram2 = [
9272
1324
857
6315
0
0
5654
1688
915
36874
62899
Coder_samefinger_Engram3 = [
9676
603
857
7089
0
0
5654
1688
510
34995
61072
Coder_samefinger_Exgram = [
9676
603
857
7089
0
0
5019
1688
1212
34995
61139
Coder_samefinger_Halmak = [
16951
544
2588
7636
0
0
7621
5215
4463
27377
72395
Coder_samefinger_Hieamtsrn = [
5166
1065
1120
5888
0
0
3723
1326
510
60551
79349
Coder_samefinger_ColemakModDH = [
10196
955
1411
4751
0
0
2614
3365
1401
34228
58921
Coder_samefinger_Norman = [
10801
1233
12799
3018
0
0
14799
9320
6465
31441
89876
Coder_samefinger_Workman = [
9964
1662
1457
6050
0
0
4241
3365
4832
34692
66263
Coder_samefinger_MTGap = [
17801
2099
370
4142
0
0
4224
2776
1339
36491
69242
Coder_samefinger_QGMLWB = [
10519
1196
4451
7350
0
0
14369
3365
1870
31563
74683
Coder_samefinger_Colemak = [
10196
955
1411
4751
0
0
2614
3365
1401
34228
58921
Coder_samefinger_Asset = [
10785
1233
7555
3442
0
0
5637
1528
6465
33798
70443
Coder_samefinger_CapewellDvorak = [ = [
12411
3269
6936
7032
0
0
3443
1019
3339
38148
75597
Coder_samefinger_Klausler = [
11460
3283
2859
8854
0
0
5681
1524
552
33678
67891
Coder_samefinger_Dvorak = [
18188
1430
1783
8092
0
0
3902
4404
2784
30459
71042

Rosetta_distance_Engram2 = [
44991.5
7132.2
14832.8
28019.2
30817.0
12268.0
7927.5
79880.8
225869.1
Rosetta_distance_Engram3 = [
46518.5
8103.9
14832.8
26983.5
25039.1
12268.0
4741.4
82114.3
220601.4
Rosetta_distance_Exgram = [
46518.5
8103.9
14832.8
26983.5
23004.2
12268.0
6747.5
82114.3
220572.7
Rosetta_distance_Halmak = [
46752.7
13288.8
15996.4
18794.0
16593.5
4236.1
15405.1
83326.0
214392.6
Rosetta_distance_Hieamtsrn = [
33992.7
8080.7
19808.7
20310.5
18772.1
9620.5
5991.4
89583.0
206159.5
Rosetta_distance_ColemakModDH = [
40632.6
4928.6
11772.3
26243.1
16451.7
11539.1
12760.5
81756.0
206084.0
Rosetta_distance_Norman = [
41775.5
4928.6
11968.5
21363.2
15789.5
17462.6
15850.0
77820.3
206958.3
Rosetta_distance_Workman = [
41398.3
8399.6
18310.4
21963.3
12561.3
11539.1
16400.0
81426.2
211998.3
Rosetta_distance_MTGap = [
46607.6
8211.0
8230.9
19082.8
13281.8
7549.0
17171.2
80587.3
200721.5
Rosetta_distance_QGMLWB = [
41985.1
6200.8
13339.0
22606.8
20494.3
11539.1
16180.3
82675.6
215021.0
Rosetta_distance_Colemak = [
40632.6
4928.6
11772.3
24460.1
16853.3
11539.1
12760.5
81756.0
204702.6
Rosetta_distance_Asset = [
41889.6
4928.6
11772.3
19769.7
18199.7
11539.1
15850.0
77993.2
201942.3
Rosetta_distance_CapewellDvorak = [ = [
41987.1
10627.3
10004.7
17120.2
21158.8
4871.5
19273.5
84602.6
209645.7
Rosetta_distance_Klausler = [
39063.6
12924.4
9792.2
19038.5
20370.3
9859.8
15293.3
87501.5
213843.5
Rosetta_distance_Dvorak = [
44489.8
9803.6
6079.9
22878.6
24383.9
13549.0
22804.3
77781.2
221770.3

Rosetta_taps_Engram2 = [
8696
3632
6968
8525
7521
5544
3818
13257
57961
Rosetta_taps_Engram3 = [
9215
3846
6968
8311
7521
5544
3467
13137
58009
Rosetta_taps_Exgram = [
9215
3846
6968
8311
7224
5544
3764
13137
58009
Rosetta_taps_Halmak = [
10669
3810
6091
7124
5783
4247
6091
14093
57908
Rosetta_taps_Hieamtsrn = [
6845
4134
7893
6467
7039
4355
3862
15743
56338
Rosetta_taps_ColemakModDH = [
8944
3088
4639
7801
6553
6256
4857
15300
57438
Rosetta_taps_Norman = [
9149
2997
5880
7014
6228
7010
6518
12452
57248
Rosetta_taps_Workman = [
9076
3916
4992
6692
5503
6256
6624
14505
57564
Rosetta_taps_MTGap = [
12570
3647
4150
6784
5341
5015
5386
14583
57476
Rosetta_taps_QGMLWB = [
8555
3322
5558
7893
6731
6256
6514
12964
57793
Rosetta_taps_Colemak = [
8944
3088
4639
7801
6553
6256
4857
15300
57438
Rosetta_taps_Asset = [
9169
2997
5811
6694
6788
5485
6518
13830
57292
Rosetta_taps_CapewellDvorak = [ = [
10942
4685
5695
6174
6066
3728
6225
14329
57844
Rosetta_taps_Klausler = [
10185
5540
5299
6589
7440
4978
3590
14426
58047
Rosetta_taps_Dvorak = [
10282
5868
4778
5783
6186
5029
7104
13026
58056

Rosetta_samefinger_Engram2 = [
542
26
11
330
0
0
155
35
30
1782
2911
Rosetta_samefinger_Engram3 = [
546
14
11
370
0
0
155
35
14
1497
2642
Rosetta_samefinger_Exgram = [
546
14
11
370
0
0
137
35
47
1497
2657
Rosetta_samefinger_Halmak = [
625
9
55
319
0
0
145
106
121
1316
2696
Rosetta_samefinger_Hieamtsrn = [
224
24
31
293
0
0
75
113
32
2870
3662
Rosetta_samefinger_ColemakModDH = [
541
20
116
155
0
0
74
54
38
1666
2664
Rosetta_samefinger_Norman = [
583
63
405
119
0
0
463
286
314
1468
3701
Rosetta_samefinger_Workman = [
474
86
38
128
0
0
101
54
286
1608
2775
Rosetta_samefinger_MTGap = [
1419
21
5
144
0
0
166
16
79
1786
3636
Rosetta_samefinger_QGMLWB = [
444
62
75
671
0
0
605
54
612
1508
4031
Rosetta_samefinger_Colemak = [
541
20
116
155
0
0
74
54
38
1666
2664
Rosetta_samefinger_Asset = [
583
63
310
76
0
0
130
25
314
1509
3010
Rosetta_samefinger_CapewellDvorak = [ = [
848
238
223
458
0
0
88
29
131
2489
4504
Rosetta_samefinger_Klausler = [
767
253
21
573
0
0
180
36
34
1858
3722
Rosetta_samefinger_Dvorak = [
869
189
50
202
0
0
139
83
65
1645
3242

```

## Keyboard Layout Analyzer analysis of individual measures <a name="KLAmeasures">

### Construct tables

```python
layout_names2 = ['Engram v2','Engram v2.5','Engram v3','Halmak','Hieamtsrn','Colemak Mod-DH',
                'Norman','Workman','MTGap 2.0','QGMLWB','Colemak',
                'Asset','Capewell-Dvorak','Klausler','Dvorak','QWERTY']
layout_abbrs2 = ['Engram2','Engram25','Engram3','Halmak','Hieamtsrn','ColemakModDH',
                'Norman','Workman','MTGap','QGMLWB','Colemak',
                'Asset','CapewellDvorak','Klausler','Dvorak','QWERTY']
finger_names = ["left little", "left ring", "left middle", "left index",
                "right index", "right middle", "right ring", "right little", "total"]
measure_abbrs = ["distance", "taps", "samefinger"]
empty_matrix = np.zeros((len(layout_names2), len(text_names)))

# Finger distances (cm)
total_finger_distances = empty_matrix.copy()
left_little_finger_distances = empty_matrix.copy()
right_little_finger_distances = empty_matrix.copy()
left_index_finger_distances = empty_matrix.copy()
right_index_finger_distances = empty_matrix.copy()
# Finger taps
left_little_finger_taps = empty_matrix.copy()
right_little_finger_taps = empty_matrix.copy()
# Same-finger, different key bigram taps
same_finger_different_key_taps = empty_matrix.copy()
# Balance between left and right hands (percent, left side negative)
hand_balances = empty_matrix.copy()

for ilayout, layout_abbr in enumerate(layout_abbrs2):
    for itext, text_abbr in enumerate(text_abbrs):
        exec('distances = {0}_{1}_{2}'.format(text_abbr, measure_abbrs[0], layout_abbr))
        exec('taps = {0}_{1}_{2}'.format(text_abbr, measure_abbrs[1], layout_abbr))
        exec('samefingers = {0}_{1}_{2}'.format(text_abbr, measure_abbrs[2], layout_abbr))
        total_finger_distances[ilayout, itext] = np.sum(distances)
        left_little_finger_distances[ilayout, itext] = distances[0]
        right_little_finger_distances[ilayout, itext] = distances[7]
        left_index_finger_distances[ilayout, itext] = distances[3]
        right_index_finger_distances[ilayout, itext] = distances[4]
        left_little_finger_taps[ilayout, itext] = taps[0]
        right_little_finger_taps[ilayout, itext] = taps[7]
        same_finger_different_key_taps[ilayout, itext] = np.sum(samefingers)
        hand_balances[ilayout, itext] = 100 * (np.sum(taps[4:8]) - np.sum(taps[0:4])) / np.sum(taps[0:8])

```

```python
score_matrices = [
    total_finger_distances,
    left_little_finger_distances,
    right_little_finger_distances,
    left_index_finger_distances,
    right_index_finger_distances,
    left_little_finger_taps,
    right_little_finger_taps,
    same_finger_different_key_taps,
    hand_balances]
matrix_labels = [
    "Total finger distances",
    "Left little finger distances",
    "Right little finger distances",
    "Left index finger distances",
    "Right index finger distances",
    "Left little finger taps",
    "Right little finger taps",
    "Same finger different key taps",
    "Hand balances"]

divide_bys = [100,100,100,100,100,1,1,1,1]
display_ints = [True,True,True,True,True,True,True,True,False]

for imatrix, score_matrix in enumerate(score_matrices):
    matrix_label = matrix_labels[imatrix]
    divide_by = divide_bys[imatrix]
    display_int = display_ints[imatrix]
    print('\n\n{0}\n'.format(matrix_label))
    print("| Layout |", end='')
    for itext in range(len(text_names)):
        print(" {0} |".format(text_abbrs[itext]), end='')
    print("")
    print("| --- |", end='')
    for itext in range(len(text_names)):
        print(" --- |", end='')
    for ilayout in range(len(layout_names2)):
        print("")
        for itext in range(len(text_names)):
            score = score_matrix[ilayout, itext]
            if divide_by > 1:
                if display_int:
                    score = '{0:0.0f}'.format(np.int(score_matrix[ilayout, itext])/100)
                else:
                    score = '{0:0.2f}'.format(np.int(score_matrix[ilayout, itext])/100)
            else:
                if display_int:
                    score = '{0:0.0f}'.format(np.float(score_matrix[ilayout, itext]))
                else:
                    score = '{0:0.2f}'.format(np.float(score_matrix[ilayout, itext]))
            if itext == 0:
                print("| {0} | {1} |".format(layout_names2[ilayout], score), end='')
            else:
                print(" {0} |".format(score), end='')

```

    Total finger distances

    | Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
    | Engram v2 | 566 | 14692 | 419215 | 132526 | 9338 | 8675 | 369688 | 2122428 | 66897 | 121992 | 5922 |
    | Engram v2.5 | 581 | 14664 | 418898 | 132430 | 9110 | 8881 | 364615 | 2066500 | 65774 | 118645 | 5816 |
    | Engram v3 | 581 | 14647 | 417532 | 132294 | 9102 | 8866 | 364165 | 2064657 | 65734 | 118636 | 5800 |
    | Halmak | 527 | 14340 | 403026 | 131920 | 9122 | 8158 | 349569 | 2010306 | 63353 | 116433 | 5653 |
    | Hieamtsrn | 544 | 14340 | 415403 | 133322 | 9188 | 8399 | 349726 | 2002603 | 62990 | 110227 | 5426 |
    | Colemak Mod-DH | 549 | 13753 | 405828 | 131877 | 8957 | 8467 | 352487 | 2009008 | 63903 | 112411 | 5489 |
    | Norman | 526 | 13998 | 403559 | 130814 | 8507 | 8225 | 352517 | 2031254 | 64017 | 114581 | 5490 |
    | Workman | 528 | 13742 | 403910 | 130907 | 9088 | 8236 | 353539 | 2038019 | 64193 | 114758 | 5606 |
    | MTGap 2.0 | 515 | 13527 | 396029 | 128049 | 8747 | 8265 | 340496 | 1939308 | 61611 | 110778 | 5352 |
    | QGMLWB | 528 | 14684 | 420989 | 133989 | 9452 | 8466 | 369723 | 2128855 | 67002 | 117893 | 5687 |
    | Colemak | 546 | 13734 | 407104 | 131671 | 8996 | 8430 | 351881 | 2004168 | 63686 | 112626 | 5458 |
    | Asset | 547 | 14154 | 410554 | 132213 | 9050 | 8510 | 354715 | 2019875 | 64064 | 112119 | 5392 |
    | Capewell-Dvorak | 527 | 14131 | 403672 | 129908 | 8964 | 8113 | 349514 | 2010879 | 63461 | 115380 | 5558 |
    | Klausler | 538 | 14122 | 405001 | 130629 | 9055 | 8181 | 350589 | 2012388 | 63525 | 116691 | 5656 |
    | Dvorak | 541 | 14528 | 425749 | 134617 | 9445 | 8391 | 371416 | 2127700 | 67529 | 118796 | 5814 |
    | QWERTY | 789 | 17968 | 572030 | 173370 | 12263 | 11738 | 542839 | 3095912 | 97366 | 132669 | 6398 |

    Left little finger distances

    | Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
    | Engram v2 | 33 | 1661 | 28603 | 11444 | 805 | 424 | 22658 | 128098 | 4009 | 11680 | 598 |
    | Engram v2.5 | 32 | 1671 | 28740 | 12059 | 838 | 423 | 23637 | 137365 | 4240 | 12044 | 615 |
    | Engram v3 | 32 | 1671 | 28740 | 12059 | 838 | 423 | 23637 | 137365 | 4240 | 12044 | 615 |
    | Halmak | 32 | 1583 | 31042 | 11232 | 706 | 534 | 24614 | 128539 | 4013 | 12465 | 658 |
    | Hieamtsrn | 21 | 1554 | 19967 | 9605 | 584 | 375 | 17196 | 96839 | 3249 | 8928 | 456 |
    | Colemak Mod-DH | 21 | 1357 | 21199 | 8607 | 529 | 381 | 15254 | 76511 | 2374 | 11650 | 566 |
    | Norman | 20 | 1423 | 21352 | 8738 | 553 | 384 | 15704 | 79222 | 2447 | 11771 | 582 |
    | Workman | 20 | 1336 | 20341 | 8465 | 520 | 374 | 14944 | 76750 | 2307 | 11794 | 576 |
    | MTGap 2.0 | 30 | 1478 | 23490 | 9610 | 628 | 483 | 18993 | 100039 | 3150 | 12772 | 654 |
    | QGMLWB | 21 | 1396 | 19278 | 8379 | 507 | 365 | 13986 | 69598 | 2163 | 11703 | 579 |
    | Colemak | 21 | 1357 | 21199 | 8607 | 529 | 381 | 15254 | 76511 | 2374 | 11650 | 566 |
    | Asset | 21 | 1417 | 21197 | 8708 | 550 | 383 | 15584 | 78791 | 2427 | 11776 | 584 |
    | Capewell-Dvorak | 26 | 1629 | 23483 | 10495 | 669 | 402 | 17392 | 91700 | 3012 | 12059 | 586 |
    | Klausler | 24 | 1622 | 25094 | 10195 | 648 | 409 | 17789 | 98962 | 3139 | 10961 | 548 |
    | Dvorak | 27 | 1641 | 23502 | 10542 | 669 | 394 | 17851 | 94145 | 3206 | 12610 | 608 |
    | QWERTY | 20 | 1360 | 21156 | 8604 | 532 | 380 | 15385 | 77757 | 2391 | 11612 | 574 |

    Right little finger distances

    | Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
    | Engram v2 | 37 | 2169 | 43562 | 17637 | 1059 | 1471 | 27599 | 161115 | 5695 | 20997 | 1011 |
    | Engram v2.5 | 47 | 2223 | 47738 | 17735 | 1078 | 1567 | 29014 | 163358 | 5880 | 20727 | 973 |
    | Engram v3 | 47 | 2213 | 47471 | 17724 | 1072 | 1562 | 28808 | 163058 | 5839 | 20646 | 970 |
    | Halmak | 33 | 2293 | 39746 | 15532 | 1010 | 1445 | 22984 | 134783 | 5013 | 20261 | 1066 |
    | Hieamtsrn | 43 | 2167 | 45368 | 17748 | 1112 | 1452 | 26600 | 155279 | 5411 | 22540 | 1120 |
    | Colemak Mod-DH | 37 | 1990 | 39289 | 17159 | 1103 | 1459 | 23332 | 137552 | 4984 | 20236 | 1028 |
    | Norman | 35 | 2046 | 37071 | 16596 | 1046 | 1447 | 21247 | 124299 | 4696 | 19640 | 959 |
    | Workman | 36 | 2020 | 39605 | 17057 | 1108 | 1456 | 23439 | 135326 | 5061 | 20000 | 1018 |
    | MTGap 2.0 | 32 | 2052 | 39523 | 15885 | 1070 | 1417 | 22061 | 131371 | 4737 | 19880 | 1011 |
    | QGMLWB | 33 | 2295 | 38163 | 16712 | 1056 | 1422 | 21100 | 123679 | 4720 | 20139 | 1020 |
    | Colemak | 37 | 1990 | 39289 | 17159 | 1103 | 1459 | 23332 | 137552 | 4984 | 20236 | 1028 |
    | Asset | 34 | 2068 | 37241 | 16619 | 1065 | 1422 | 21809 | 129307 | 4813 | 19920 | 972 |
    | Capewell-Dvorak | 35 | 2058 | 40927 | 15508 | 981 | 1447 | 22210 | 125580 | 4426 | 20535 | 1065 |
    | Klausler | 41 | 2154 | 43650 | 17396 | 1122 | 1493 | 27840 | 162221 | 5527 | 21518 | 1098 |
    | Dvorak | 47 | 2166 | 45609 | 16955 | 1099 | 1537 | 28238 | 161514 | 5578 | 18990 | 985 |
    | QWERTY | 35 | 2039 | 39034 | 17264 | 1104 | 1449 | 24320 | 145897 | 5241 | 20353 | 1002 |

    Left index finger distances

    | Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
    | Engram v2 | 41 | 640 | 22344 | 6247 | 435 | 559 | 21386 | 119845 | 3706 | 7327 | 366 |
    | Engram v2.5 | 36 | 546 | 18271 | 5457 | 368 | 503 | 19232 | 108615 | 3439 | 7538 | 353 |
    | Engram v3 | 36 | 546 | 18271 | 5457 | 368 | 503 | 19232 | 108615 | 3439 | 7538 | 353 |
    | Halmak | 30 | 579 | 23946 | 8481 | 604 | 403 | 21375 | 119770 | 3522 | 4539 | 202 |
    | Hieamtsrn | 39 | 687 | 27872 | 7406 | 553 | 481 | 22158 | 121270 | 3704 | 5860 | 268 |
    | Colemak Mod-DH | 57 | 921 | 38538 | 11285 | 796 | 592 | 38793 | 223369 | 6899 | 6251 | 342 |
    | Norman | 46 | 706 | 32988 | 9131 | 85 | 500 | 31236 | 175133 | 5309 | 5042 | 282 |
    | Workman | 52 | 760 | 36446 | 10584 | 780 | 585 | 36741 | 210242 | 6412 | 5557 | 288 |
    | MTGap 2.0 | 48 | 802 | 33204 | 9764 | 694 | 492 | 30576 | 178619 | 5386 | 5276 | 254 |
    | QGMLWB | 69 | 1013 | 41348 | 11806 | 899 | 690 | 44207 | 259903 | 8162 | 7259 | 302 |
    | Colemak | 58 | 934 | 39640 | 11393 | 823 | 598 | 39300 | 224921 | 6952 | 6329 | 322 |
    | Asset | 51 | 826 | 34739 | 9715 | 691 | 536 | 33441 | 187843 | 5887 | 5293 | 265 |
    | Capewell-Dvorak | 36 | 666 | 30220 | 8779 | 611 | 526 | 29085 | 171000 | 4807 | 4790 | 229 |
    | Klausler | 40 | 702 | 28978 | 9170 | 626 | 435 | 27515 | 160939 | 4856 | 5804 | 254 |
    | Dvorak | 50 | 908 | 42181 | 11038 | 853 | 653 | 38995 | 226118 | 6641 | 6728 | 289 |
    | QWERTY | 95 | 1429 | 60189 | 16971 | 1285 | 1070 | 65288 | 372241 | 11440 | 9211 | 435 |

    Right index finger distances

    | Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
    | Engram v2 | 53 | 1024 | 34818 | 10192 | 846 | 551 | 37026 | 216262 | 6684 | 9078 | 389 |
    | Engram v2.5 | 60 | 1019 | 34821 | 10240 | 754 | 647 | 34944 | 191336 | 6204 | 7479 | 326 |
    | Engram v3 | 49 | 907 | 33651 | 9576 | 711 | 612 | 31704 | 169835 | 5559 | 6962 | 350 |
    | Halmak | 40 | 617 | 27940 | 7471 | 587 | 456 | 23076 | 128477 | 3811 | 4942 | 248 |
    | Hieamtsrn | 64 | 1011 | 46382 | 11360 | 864 | 715 | 38464 | 217742 | 6707 | 5007 | 256 |
    | Colemak Mod-DH | 67 | 1067 | 43775 | 11728 | 819 | 768 | 40459 | 224314 | 7263 | 4838 | 229 |
    | Norman | 39 | 783 | 36039 | 9653 | 712 | 578 | 32304 | 189116 | 5464 | 4930 | 220 |
    | Workman | 46 | 803 | 33802 | 8901 | 664 | 517 | 30376 | 176078 | 5258 | 4566 | 177 |
    | MTGap 2.0 | 42 | 737 | 36478 | 9604 | 711 | 580 | 32249 | 185720 | 5578 | 4331 | 184 |
    | QGMLWB | 61 | 1067 | 49600 | 12495 | 989 | 750 | 46246 | 264943 | 7953 | 6371 | 277 |
    | Colemak | 65 | 1044 | 43311 | 11516 | 812 | 744 | 39648 | 220342 | 7102 | 4868 | 233 |
    | Asset | 65 | 1073 | 48065 | 12691 | 895 | 839 | 42844 | 239079 | 7382 | 4886 | 249 |
    | Capewell-Dvorak | 59 | 987 | 39221 | 10602 | 759 | 584 | 37987 | 221884 | 7102 | 5968 | 276 |
    | Klausler | 66 | 970 | 40842 | 11258 | 862 | 693 | 42605 | 251133 | 7814 | 6504 | 279 |
    | Dvorak | 61 | 1020 | 43094 | 11097 | 835 | 632 | 40406 | 230108 | 7388 | 6078 | 311 |
    | QWERTY | 91 | 1523 | 63615 | 16201 | 1173 | 1182 | 61077 | 343059 | 10706 | 7162 | 318 |

    Left little finger taps

    | Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
    | Engram v2 | 702 | 36656 | 601505 | 220582 | 15909 | 8730 | 522938 | 3059178 | 94115 | 197655 | 9723 |
    | Engram v2.5 | 690 | 36943 | 606711 | 234165 | 16744 | 8684 | 546593 | 3285822 | 99588 | 205947 | 10153 |
    | Engram v3 | 690 | 36943 | 606711 | 234165 | 16744 | 8684 | 546593 | 3285822 | 99588 | 205947 | 10153 |
    | Halmak | 1026 | 40010 | 744317 | 249220 | 15111 | 14724 | 649523 | 3444960 | 113279 | 213638 | 11624 |
    | Hieamtsrn | 871 | 38038 | 558249 | 217201 | 13063 | 11808 | 528656 | 2879031 | 97916 | 150500 | 8512 |
    | Colemak Mod-DH | 888 | 40313 | 710680 | 235125 | 14916 | 12481 | 628201 | 3447309 | 108553 | 225473 | 11097 |
    | Norman | 890 | 39190 | 711129 | 236003 | 15228 | 12463 | 634103 | 3487747 | 109496 | 227863 | 11454 |
    | Workman | 880 | 39389 | 696710 | 232550 | 14746 | 12391 | 623934 | 3451809 | 107612 | 228367 | 11166 |
    | MTGap 2.0 | 1097 | 41900 | 787727 | 246806 | 16963 | 14984 | 689492 | 3868187 | 117057 | 246974 | 14475 |
    | QGMLWB | 633 | 34584 | 471124 | 176349 | 10488 | 8555 | 373626 | 2059911 | 66281 | 206392 | 10503 |
    | Colemak | 888 | 40313 | 710680 | 235125 | 14916 | 12481 | 628201 | 3447309 | 108553 | 225473 | 11097 |
    | Asset | 893 | 39194 | 710005 | 235948 | 15207 | 12548 | 632891 | 3483248 | 109300 | 228074 | 11467 |
    | Capewell-Dvorak | 1015 | 42979 | 792134 | 257611 | 17702 | 13822 | 663564 | 3679810 | 112125 | 228832 | 12033 |
    | Klausler | 981 | 42318 | 829682 | 258500 | 17654 | 13899 | 671647 | 3831110 | 113958 | 205790 | 11228 |
    | Dvorak | 1023 | 42052 | 751676 | 265209 | 17353 | 12872 | 677492 | 3739024 | 121505 | 246022 | 11379 |
    | QWERTY | 876 | 37950 | 706895 | 233338 | 14886 | 12482 | 629320 | 3463858 | 108544 | 223338 | 11132 |

    Right little finger taps

    | Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
    | Engram v2 | 992 | 36036 | 878246 | 315596 | 19925 | 20185 | 723222 | 4239597 | 145817 | 294655 | 14543 |
    | Engram v2.5 | 1188 | 37086 | 963903 | 317302 | 20562 | 22086 | 750777 | 4267126 | 148968 | 287671 | 13412 |
    | Engram v3 | 1136 | 35621 | 929046 | 315415 | 19684 | 21408 | 723514 | 4222472 | 143489 | 277366 | 13027 |
    | Halmak | 927 | 34370 | 854440 | 261398 | 18915 | 19900 | 638369 | 3689730 | 131312 | 302120 | 15207 |
    | Hieamtsrn | 1047 | 35508 | 914629 | 320577 | 20935 | 19975 | 720370 | 4234858 | 144503 | 332278 | 16310 |
    | Colemak Mod-DH | 1123 | 35858 | 924246 | 319835 | 21696 | 21528 | 680622 | 3943707 | 132401 | 308409 | 16009 |
    | Norman | 1017 | 32507 | 701154 | 282448 | 17124 | 19804 | 499682 | 2747503 | 107837 | 279000 | 13199 |
    | Workman | 996 | 34115 | 868000 | 301002 | 21336 | 19875 | 646056 | 3699865 | 132002 | 316062 | 15151 |
    | MTGap 2.0 | 908 | 36771 | 942692 | 301638 | 22290 | 19895 | 659547 | 3798235 | 131301 | 313991 | 15502 |
    | QGMLWB | 983 | 33753 | 706574 | 280334 | 17254 | 19594 | 497803 | 2724496 | 106987 | 281586 | 13523 |
    | Colemak | 1123 | 35858 | 924246 | 319835 | 21696 | 21528 | 680622 | 3943707 | 132401 | 308409 | 16009 |
    | Asset | 875 | 32748 | 709546 | 282876 | 19221 | 7724 | 549966 | 3304452 | 119259 | 314315 | 14540 |
    | Capewell-Dvorak | 914 | 33547 | 819979 | 289475 | 18672 | 19711 | 594500 | 3505369 | 118109 | 304988 | 15694 |
    | Klausler | 982 | 36300 | 874620 | 317922 | 20706 | 20629 | 715147 | 4303432 | 143207 | 315850 | 15636 |
    | Dvorak | 1199 | 36285 | 955938 | 320119 | 21098 | 22179 | 762193 | 4517125 | 149645 | 280687 | 14173 |
    | QWERTY | 570 | 28887 | 536961 | 245630 | 15586 | 14462 | 334346 | 2005118 | 76432 | 290115 | 13849 |

    Same finger different key taps

    | Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
    | Engram v2 | 216 | 9807 | 320406 | 120286 | 7728 | 3514 | 137290 | 1064640 | 37534 | 125798 | 5822 |
    | Engram v2.5 | 270 | 11742 | 339358 | 118954 | 9080 | 3538 | 145178 | 1055230 | 36990 | 121912 | 5766 |
    | Engram v3 | 252 | 12272 | 343824 | 117568 | 8270 | 3744 | 156244 | 1168198 | 39530 | 123242 | 5414 |
    | Halmak | 666 | 14962 | 633920 | 205600 | 14044 | 7826 | 362786 | 2487382 | 83702 | 141290 | 6200 |
    | Hieamtsrn | 244 | 12096 | 311000 | 119490 | 8316 | 3192 | 155674 | 1100116 | 40882 | 158698 | 7324 |
    | Colemak Mod-DH | 362 | 10960 | 352578 | 151736 | 9298 | 4644 | 153984 | 1233770 | 47438 | 117842 | 5328 |
    | Norman | 938 | 20012 | 721602 | 213890 | 16014 | 9022 | 595168 | 3885282 | 135844 | 179752 | 7402 |
    | Workman | 550 | 13086 | 451280 | 136692 | 10698 | 6156 | 287622 | 1975564 | 71150 | 132526 | 5550 |
    | MTGap 2.0 | 226 | 14550 | 397690 | 139130 | 10386 | 6252 | 176724 | 1532844 | 58144 | 138484 | 7272 |
    | QGMLWB | 812 | 17820 | 637788 | 189700 | 14364 | 7838 | 456442 | 3027530 | 100750 | 149366 | 8062 |
    | Colemak | 362 | 10960 | 352578 | 151736 | 9298 | 4644 | 153984 | 1233770 | 47438 | 117842 | 5328 |
    | Asset | 520 | 13572 | 519018 | 155246 | 11802 | 5664 | 332860 | 2269342 | 77406 | 140886 | 6020 |
    | Capewell-Dvorak | 556 | 14226 | 501178 | 163878 | 12214 | 6816 | 335056 | 2391416 | 78152 | 151194 | 9008 |
    | Klausler | 408 | 14734 | 455658 | 174998 | 11410 | 5212 | 257878 | 1794604 | 59566 | 135782 | 7444 |
    | Dvorak | 516 | 13970 | 492604 | 171488 | 12208 | 5912 | 263018 | 1993346 | 64994 | 142084 | 6484 |
    | QWERTY | 880 | 19580 | 736894 | 204712 | 16632 | 9264 | 581944 | 3765246 | 130184 | 173598 | 8052 |

    Hand balances

    | Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
    | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
    | Engram v2 | 3.54 | 0.31 | 4.18 | 7.17 | 5.35 | 6.65 | 2.42 | 2.57 | 4.86 | 5.90 | 4.28 |
    | Engram v2.5 | 3.79 | 0.02 | 4.02 | 5.71 | 4.10 | 6.72 | 1.67 | 1.32 | 3.90 | 4.58 | 2.85 |
    | Engram v3 | 3.79 | 0.02 | 4.02 | 5.71 | 4.10 | 6.72 | 1.67 | 1.32 | 3.90 | 4.58 | 2.85 |
    | Halmak | 2.34 | -1.67 | 2.03 | -3.02 | -1.40 | 7.58 | -0.85 | -0.56 | 0.16 | 4.71 | 5.96 |
    | Hieamtsrn | 0.06 | -3.07 | 2.02 | 3.42 | 4.13 | 1.07 | 1.08 | 2.98 | 3.62 | 10.43 | 7.79 |
    | Colemak Mod-DH | 10.15 | 5.66 | 11.04 | 6.74 | 9.18 | 18.14 | 7.09 | 6.39 | 7.70 | 9.81 | 11.69 |
    | Norman | -2.34 | -1.19 | 2.46 | -0.17 | 3.89 | 5.91 | -2.29 | -2.05 | -0.92 | 8.21 | 9.30 |
    | Workman | 1.48 | 0.55 | 3.62 | 1.68 | 5.09 | 7.93 | 1.02 | 1.58 | 1.79 | 10.23 | 11.22 |
    | MTGap 2.0 | -4.35 | -2.73 | 1.33 | 0.51 | 3.49 | 4.11 | 0.20 | 1.67 | 2.05 | 8.65 | 3.63 |
    | QGMLWB | 7.11 | 3.55 | 7.43 | 5.84 | 6.10 | 15.00 | 5.14 | 4.49 | 5.48 | 6.41 | 9.53 |
    | Colemak | 10.15 | 5.66 | 11.04 | 6.74 | 9.18 | 18.14 | 7.09 | 6.39 | 7.70 | 9.81 | 11.69 |
    | Asset | -0.51 | 0.36 | 4.56 | 1.22 | 5.58 | -1.07 | -1.03 | -0.78 | 0.05 | 8.59 | 10.55 |
    | Capewell-Dvorak | 8.25 | -0.09 | 4.46 | 5.10 | 4.86 | 9.23 | 2.72 | 2.62 | 5.00 | 7.55 | 5.18 |
    | Klausler | 2.97 | -3.06 | 1.53 | 4.18 | 4.21 | 6.88 | 2.17 | 2.47 | 4.35 | 7.11 | 4.96 |
    | Dvorak | 10.59 | 1.48 | 7.00 | 8.78 | 8.49 | 12.00 | 8.03 | 8.46 | 10.76 | 9.24 | 7.77 |
    | QWERTY | -9.58 | -5.51 | -3.25 | -6.14 | -3.32 | 0.25 | -11.23 | -11.75 | -10.92 | 1.50 | 4.59 |

Total finger distances

| Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram v2 | 566 | 14692 | 419215 | 132526 | 9338 | 8675 | 369688 | 2122428 | 66897 | 121992 | 5922 |
| Engram v2.5 | 581 | 14664 | 418898 | 132430 | 9110 | 8881 | 364615 | 2066500 | 65774 | 118645 | 5816 |
| Engram v3 | 581 | 14647 | 417532 | 132294 | 9102 | 8866 | 364165 | 2064657 | 65734 | 118636 | 5800 |
| Halmak | 527 | 14340 | 403026 | 131920 | 9122 | 8158 | 349569 | 2010306 | 63353 | 116433 | 5653 |
| Hieamtsrn | 544 | 14340 | 415403 | 133322 | 9188 | 8399 | 349726 | 2002603 | 62990 | 110227 | 5426 |
| Colemak Mod-DH | 549 | 13753 | 405828 | 131877 | 8957 | 8467 | 352487 | 2009008 | 63903 | 112411 | 5489 |
| Norman | 526 | 13998 | 403559 | 130814 | 8507 | 8225 | 352517 | 2031254 | 64017 | 114581 | 5490 |
| Workman | 528 | 13742 | 403910 | 130907 | 9088 | 8236 | 353539 | 2038019 | 64193 | 114758 | 5606 |
| MTGap 2.0 | 515 | 13527 | 396029 | 128049 | 8747 | 8265 | 340496 | 1939308 | 61611 | 110778 | 5352 |
| QGMLWB | 528 | 14684 | 420989 | 133989 | 9452 | 8466 | 369723 | 2128855 | 67002 | 117893 | 5687 |
| Colemak | 546 | 13734 | 407104 | 131671 | 8996 | 8430 | 351881 | 2004168 | 63686 | 112626 | 5458 |
| Asset | 547 | 14154 | 410554 | 132213 | 9050 | 8510 | 354715 | 2019875 | 64064 | 112119 | 5392 |
| Capewell-Dvorak | 527 | 14131 | 403672 | 129908 | 8964 | 8113 | 349514 | 2010879 | 63461 | 115380 | 5558 |
| Klausler | 538 | 14122 | 405001 | 130629 | 9055 | 8181 | 350589 | 2012388 | 63525 | 116691 | 5656 |
| Dvorak | 541 | 14528 | 425749 | 134617 | 9445 | 8391 | 371416 | 2127700 | 67529 | 118796 | 5814 |
| QWERTY | 789 | 17968 | 572030 | 173370 | 12263 | 11738 | 542839 | 3095912 | 97366 | 132669 | 6398 |

Left little finger distances

| Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram v2 | 33 | 1661 | 28603 | 11444 | 805 | 424 | 22658 | 128098 | 4009 | 11680 | 598 |
| Engram v2.5 | 32 | 1671 | 28740 | 12059 | 838 | 423 | 23637 | 137365 | 4240 | 12044 | 615 |
| Engram v3 | 32 | 1671 | 28740 | 12059 | 838 | 423 | 23637 | 137365 | 4240 | 12044 | 615 |
| Halmak | 32 | 1583 | 31042 | 11232 | 706 | 534 | 24614 | 128539 | 4013 | 12465 | 658 |
| Hieamtsrn | 21 | 1554 | 19967 | 9605 | 584 | 375 | 17196 | 96839 | 3249 | 8928 | 456 |
| Colemak Mod-DH | 21 | 1357 | 21199 | 8607 | 529 | 381 | 15254 | 76511 | 2374 | 11650 | 566 |
| Norman | 20 | 1423 | 21352 | 8738 | 553 | 384 | 15704 | 79222 | 2447 | 11771 | 582 |
| Workman | 20 | 1336 | 20341 | 8465 | 520 | 374 | 14944 | 76750 | 2307 | 11794 | 576 |
| MTGap 2.0 | 30 | 1478 | 23490 | 9610 | 628 | 483 | 18993 | 100039 | 3150 | 12772 | 654 |
| QGMLWB | 21 | 1396 | 19278 | 8379 | 507 | 365 | 13986 | 69598 | 2163 | 11703 | 579 |
| Colemak | 21 | 1357 | 21199 | 8607 | 529 | 381 | 15254 | 76511 | 2374 | 11650 | 566 |
| Asset | 21 | 1417 | 21197 | 8708 | 550 | 383 | 15584 | 78791 | 2427 | 11776 | 584 |
| Capewell-Dvorak | 26 | 1629 | 23483 | 10495 | 669 | 402 | 17392 | 91700 | 3012 | 12059 | 586 |
| Klausler | 24 | 1622 | 25094 | 10195 | 648 | 409 | 17789 | 98962 | 3139 | 10961 | 548 |
| Dvorak | 27 | 1641 | 23502 | 10542 | 669 | 394 | 17851 | 94145 | 3206 | 12610 | 608 |
| QWERTY | 20 | 1360 | 21156 | 8604 | 532 | 380 | 15385 | 77757 | 2391 | 11612 | 574 |

Right little finger distances

| Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram v2 | 37 | 2169 | 43562 | 17637 | 1059 | 1471 | 27599 | 161115 | 5695 | 20997 | 1011 |
| Engram v2.5 | 47 | 2223 | 47738 | 17735 | 1078 | 1567 | 29014 | 163358 | 5880 | 20727 | 973 |
| Engram v3 | 47 | 2213 | 47471 | 17724 | 1072 | 1562 | 28808 | 163058 | 5839 | 20646 | 970 |
| Halmak | 33 | 2293 | 39746 | 15532 | 1010 | 1445 | 22984 | 134783 | 5013 | 20261 | 1066 |
| Hieamtsrn | 43 | 2167 | 45368 | 17748 | 1112 | 1452 | 26600 | 155279 | 5411 | 22540 | 1120 |
| Colemak Mod-DH | 37 | 1990 | 39289 | 17159 | 1103 | 1459 | 23332 | 137552 | 4984 | 20236 | 1028 |
| Norman | 35 | 2046 | 37071 | 16596 | 1046 | 1447 | 21247 | 124299 | 4696 | 19640 | 959 |
| Workman | 36 | 2020 | 39605 | 17057 | 1108 | 1456 | 23439 | 135326 | 5061 | 20000 | 1018 |
| MTGap 2.0 | 32 | 2052 | 39523 | 15885 | 1070 | 1417 | 22061 | 131371 | 4737 | 19880 | 1011 |
| QGMLWB | 33 | 2295 | 38163 | 16712 | 1056 | 1422 | 21100 | 123679 | 4720 | 20139 | 1020 |
| Colemak | 37 | 1990 | 39289 | 17159 | 1103 | 1459 | 23332 | 137552 | 4984 | 20236 | 1028 |
| Asset | 34 | 2068 | 37241 | 16619 | 1065 | 1422 | 21809 | 129307 | 4813 | 19920 | 972 |
| Capewell-Dvorak | 35 | 2058 | 40927 | 15508 | 981 | 1447 | 22210 | 125580 | 4426 | 20535 | 1065 |
| Klausler | 41 | 2154 | 43650 | 17396 | 1122 | 1493 | 27840 | 162221 | 5527 | 21518 | 1098 |
| Dvorak | 47 | 2166 | 45609 | 16955 | 1099 | 1537 | 28238 | 161514 | 5578 | 18990 | 985 |
| QWERTY | 35 | 2039 | 39034 | 17264 | 1104 | 1449 | 24320 | 145897 | 5241 | 20353 | 1002 |

Left index finger distances

| Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram v2 | 41 | 640 | 22344 | 6247 | 435 | 559 | 21386 | 119845 | 3706 | 7327 | 366 |
| Engram v2.5 | 36 | 546 | 18271 | 5457 | 368 | 503 | 19232 | 108615 | 3439 | 7538 | 353 |
| Engram v3 | 36 | 546 | 18271 | 5457 | 368 | 503 | 19232 | 108615 | 3439 | 7538 | 353 |
| Halmak | 30 | 579 | 23946 | 8481 | 604 | 403 | 21375 | 119770 | 3522 | 4539 | 202 |
| Hieamtsrn | 39 | 687 | 27872 | 7406 | 553 | 481 | 22158 | 121270 | 3704 | 5860 | 268 |
| Colemak Mod-DH | 57 | 921 | 38538 | 11285 | 796 | 592 | 38793 | 223369 | 6899 | 6251 | 342 |
| Norman | 46 | 706 | 32988 | 9131 | 85 | 500 | 31236 | 175133 | 5309 | 5042 | 282 |
| Workman | 52 | 760 | 36446 | 10584 | 780 | 585 | 36741 | 210242 | 6412 | 5557 | 288 |
| MTGap 2.0 | 48 | 802 | 33204 | 9764 | 694 | 492 | 30576 | 178619 | 5386 | 5276 | 254 |
| QGMLWB | 69 | 1013 | 41348 | 11806 | 899 | 690 | 44207 | 259903 | 8162 | 7259 | 302 |
| Colemak | 58 | 934 | 39640 | 11393 | 823 | 598 | 39300 | 224921 | 6952 | 6329 | 322 |
| Asset | 51 | 826 | 34739 | 9715 | 691 | 536 | 33441 | 187843 | 5887 | 5293 | 265 |
| Capewell-Dvorak | 36 | 666 | 30220 | 8779 | 611 | 526 | 29085 | 171000 | 4807 | 4790 | 229 |
| Klausler | 40 | 702 | 28978 | 9170 | 626 | 435 | 27515 | 160939 | 4856 | 5804 | 254 |
| Dvorak | 50 | 908 | 42181 | 11038 | 853 | 653 | 38995 | 226118 | 6641 | 6728 | 289 |
| QWERTY | 95 | 1429 | 60189 | 16971 | 1285 | 1070 | 65288 | 372241 | 11440 | 9211 | 435 |

Right index finger distances

| Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram v2 | 53 | 1024 | 34818 | 10192 | 846 | 551 | 37026 | 216262 | 6684 | 9078 | 389 |
| Engram v2.5 | 60 | 1019 | 34821 | 10240 | 754 | 647 | 34944 | 191336 | 6204 | 7479 | 326 |
| Engram v3 | 49 | 907 | 33651 | 9576 | 711 | 612 | 31704 | 169835 | 5559 | 6962 | 350 |
| Halmak | 40 | 617 | 27940 | 7471 | 587 | 456 | 23076 | 128477 | 3811 | 4942 | 248 |
| Hieamtsrn | 64 | 1011 | 46382 | 11360 | 864 | 715 | 38464 | 217742 | 6707 | 5007 | 256 |
| Colemak Mod-DH | 67 | 1067 | 43775 | 11728 | 819 | 768 | 40459 | 224314 | 7263 | 4838 | 229 |
| Norman | 39 | 783 | 36039 | 9653 | 712 | 578 | 32304 | 189116 | 5464 | 4930 | 220 |
| Workman | 46 | 803 | 33802 | 8901 | 664 | 517 | 30376 | 176078 | 5258 | 4566 | 177 |
| MTGap 2.0 | 42 | 737 | 36478 | 9604 | 711 | 580 | 32249 | 185720 | 5578 | 4331 | 184 |
| QGMLWB | 61 | 1067 | 49600 | 12495 | 989 | 750 | 46246 | 264943 | 7953 | 6371 | 277 |
| Colemak | 65 | 1044 | 43311 | 11516 | 812 | 744 | 39648 | 220342 | 7102 | 4868 | 233 |
| Asset | 65 | 1073 | 48065 | 12691 | 895 | 839 | 42844 | 239079 | 7382 | 4886 | 249 |
| Capewell-Dvorak | 59 | 987 | 39221 | 10602 | 759 | 584 | 37987 | 221884 | 7102 | 5968 | 276 |
| Klausler | 66 | 970 | 40842 | 11258 | 862 | 693 | 42605 | 251133 | 7814 | 6504 | 279 |
| Dvorak | 61 | 1020 | 43094 | 11097 | 835 | 632 | 40406 | 230108 | 7388 | 6078 | 311 |
| QWERTY | 91 | 1523 | 63615 | 16201 | 1173 | 1182 | 61077 | 343059 | 10706 | 7162 | 318 |

Left little finger taps

| Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram v2 | 702 | 36656 | 601505 | 220582 | 15909 | 8730 | 522938 | 3059178 | 94115 | 197655 | 9723 |
| Engram v2.5 | 690 | 36943 | 606711 | 234165 | 16744 | 8684 | 546593 | 3285822 | 99588 | 205947 | 10153 |
| Engram v3 | 690 | 36943 | 606711 | 234165 | 16744 | 8684 | 546593 | 3285822 | 99588 | 205947 | 10153 |
| Halmak | 1026 | 40010 | 744317 | 249220 | 15111 | 14724 | 649523 | 3444960 | 113279 | 213638 | 11624 |
| Hieamtsrn | 871 | 38038 | 558249 | 217201 | 13063 | 11808 | 528656 | 2879031 | 97916 | 150500 | 8512 |
| Colemak Mod-DH | 888 | 40313 | 710680 | 235125 | 14916 | 12481 | 628201 | 3447309 | 108553 | 225473 | 11097 |
| Norman | 890 | 39190 | 711129 | 236003 | 15228 | 12463 | 634103 | 3487747 | 109496 | 227863 | 11454 |
| Workman | 880 | 39389 | 696710 | 232550 | 14746 | 12391 | 623934 | 3451809 | 107612 | 228367 | 11166 |
| MTGap 2.0 | 1097 | 41900 | 787727 | 246806 | 16963 | 14984 | 689492 | 3868187 | 117057 | 246974 | 14475 |
| QGMLWB | 633 | 34584 | 471124 | 176349 | 10488 | 8555 | 373626 | 2059911 | 66281 | 206392 | 10503 |
| Colemak | 888 | 40313 | 710680 | 235125 | 14916 | 12481 | 628201 | 3447309 | 108553 | 225473 | 11097 |
| Asset | 893 | 39194 | 710005 | 235948 | 15207 | 12548 | 632891 | 3483248 | 109300 | 228074 | 11467 |
| Capewell-Dvorak | 1015 | 42979 | 792134 | 257611 | 17702 | 13822 | 663564 | 3679810 | 112125 | 228832 | 12033 |
| Klausler | 981 | 42318 | 829682 | 258500 | 17654 | 13899 | 671647 | 3831110 | 113958 | 205790 | 11228 |
| Dvorak | 1023 | 42052 | 751676 | 265209 | 17353 | 12872 | 677492 | 3739024 | 121505 | 246022 | 11379 |
| QWERTY | 876 | 37950 | 706895 | 233338 | 14886 | 12482 | 629320 | 3463858 | 108544 | 223338 | 11132 |

Right little finger taps

| Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram v2 | 992 | 36036 | 878246 | 315596 | 19925 | 20185 | 723222 | 4239597 | 145817 | 294655 | 14543 |
| Engram v2.5 | 1188 | 37086 | 963903 | 317302 | 20562 | 22086 | 750777 | 4267126 | 148968 | 287671 | 13412 |
| Engram v3 | 1136 | 35621 | 929046 | 315415 | 19684 | 21408 | 723514 | 4222472 | 143489 | 277366 | 13027 |
| Halmak | 927 | 34370 | 854440 | 261398 | 18915 | 19900 | 638369 | 3689730 | 131312 | 302120 | 15207 |
| Hieamtsrn | 1047 | 35508 | 914629 | 320577 | 20935 | 19975 | 720370 | 4234858 | 144503 | 332278 | 16310 |
| Colemak Mod-DH | 1123 | 35858 | 924246 | 319835 | 21696 | 21528 | 680622 | 3943707 | 132401 | 308409 | 16009 |
| Norman | 1017 | 32507 | 701154 | 282448 | 17124 | 19804 | 499682 | 2747503 | 107837 | 279000 | 13199 |
| Workman | 996 | 34115 | 868000 | 301002 | 21336 | 19875 | 646056 | 3699865 | 132002 | 316062 | 15151 |
| MTGap 2.0 | 908 | 36771 | 942692 | 301638 | 22290 | 19895 | 659547 | 3798235 | 131301 | 313991 | 15502 |
| QGMLWB | 983 | 33753 | 706574 | 280334 | 17254 | 19594 | 497803 | 2724496 | 106987 | 281586 | 13523 |
| Colemak | 1123 | 35858 | 924246 | 319835 | 21696 | 21528 | 680622 | 3943707 | 132401 | 308409 | 16009 |
| Asset | 875 | 32748 | 709546 | 282876 | 19221 | 7724 | 549966 | 3304452 | 119259 | 314315 | 14540 |
| Capewell-Dvorak | 914 | 33547 | 819979 | 289475 | 18672 | 19711 | 594500 | 3505369 | 118109 | 304988 | 15694 |
| Klausler | 982 | 36300 | 874620 | 317922 | 20706 | 20629 | 715147 | 4303432 | 143207 | 315850 | 15636 |
| Dvorak | 1199 | 36285 | 955938 | 320119 | 21098 | 22179 | 762193 | 4517125 | 149645 | 280687 | 14173 |
| QWERTY | 570 | 28887 | 536961 | 245630 | 15586 | 14462 | 334346 | 2005118 | 76432 | 290115 | 13849 |

Same finger different key taps

| Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram v2 | 216 | 9807 | 320406 | 120286 | 7728 | 3514 | 137290 | 1064640 | 37534 | 125798 | 5822 |
| Engram v2.5 | 270 | 11742 | 339358 | 118954 | 9080 | 3538 | 145178 | 1055230 | 36990 | 121912 | 5766 |
| Engram v3 | 252 | 12272 | 343824 | 117568 | 8270 | 3744 | 156244 | 1168198 | 39530 | 123242 | 5414 |
| Halmak | 666 | 14962 | 633920 | 205600 | 14044 | 7826 | 362786 | 2487382 | 83702 | 141290 | 6200 |
| Hieamtsrn | 244 | 12096 | 311000 | 119490 | 8316 | 3192 | 155674 | 1100116 | 40882 | 158698 | 7324 |
| Colemak Mod-DH | 362 | 10960 | 352578 | 151736 | 9298 | 4644 | 153984 | 1233770 | 47438 | 117842 | 5328 |
| Norman | 938 | 20012 | 721602 | 213890 | 16014 | 9022 | 595168 | 3885282 | 135844 | 179752 | 7402 |
| Workman | 550 | 13086 | 451280 | 136692 | 10698 | 6156 | 287622 | 1975564 | 71150 | 132526 | 5550 |
| MTGap 2.0 | 226 | 14550 | 397690 | 139130 | 10386 | 6252 | 176724 | 1532844 | 58144 | 138484 | 7272 |
| QGMLWB | 812 | 17820 | 637788 | 189700 | 14364 | 7838 | 456442 | 3027530 | 100750 | 149366 | 8062 |
| Colemak | 362 | 10960 | 352578 | 151736 | 9298 | 4644 | 153984 | 1233770 | 47438 | 117842 | 5328 |
| Asset | 520 | 13572 | 519018 | 155246 | 11802 | 5664 | 332860 | 2269342 | 77406 | 140886 | 6020 |
| Capewell-Dvorak | 556 | 14226 | 501178 | 163878 | 12214 | 6816 | 335056 | 2391416 | 78152 | 151194 | 9008 |
| Klausler | 408 | 14734 | 455658 | 174998 | 11410 | 5212 | 257878 | 1794604 | 59566 | 135782 | 7444 |
| Dvorak | 516 | 13970 | 492604 | 171488 | 12208 | 5912 | 263018 | 1993346 | 64994 | 142084 | 6484 |
| QWERTY | 880 | 19580 | 736894 | 204712 | 16632 | 9264 | 581944 | 3765246 | 130184 | 173598 | 8052 |

Hand balances

| Layout | Alice | Memento | Tweets_100K | Tweets_20K | Tweets_MASC | Spoken_MASC | COCA_blogs | iweb | Monkey | Coder | Rosetta |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Engram v2 | 3.54 | 0.31 | 4.18 | 7.17 | 5.35 | 6.65 | 2.42 | 2.57 | 4.86 | 5.90 | 4.28 |
| Engram v2.5 | 3.79 | 0.02 | 4.02 | 5.71 | 4.10 | 6.72 | 1.67 | 1.32 | 3.90 | 4.58 | 2.85 |
| Engram v3 | 3.79 | 0.02 | 4.02 | 5.71 | 4.10 | 6.72 | 1.67 | 1.32 | 3.90 | 4.58 | 2.85 |
| Halmak | 2.34 | -1.67 | 2.03 | -3.02 | -1.40 | 7.58 | -0.85 | -0.56 | 0.16 | 4.71 | 5.96 |
| Hieamtsrn | 0.06 | -3.07 | 2.02 | 3.42 | 4.13 | 1.07 | 1.08 | 2.98 | 3.62 | 10.43 | 7.79 |
| Colemak Mod-DH | 10.15 | 5.66 | 11.04 | 6.74 | 9.18 | 18.14 | 7.09 | 6.39 | 7.70 | 9.81 | 11.69 |
| Norman | -2.34 | -1.19 | 2.46 | -0.17 | 3.89 | 5.91 | -2.29 | -2.05 | -0.92 | 8.21 | 9.30 |
| Workman | 1.48 | 0.55 | 3.62 | 1.68 | 5.09 | 7.93 | 1.02 | 1.58 | 1.79 | 10.23 | 11.22 |
| MTGap 2.0 | -4.35 | -2.73 | 1.33 | 0.51 | 3.49 | 4.11 | 0.20 | 1.67 | 2.05 | 8.65 | 3.63 |
| QGMLWB | 7.11 | 3.55 | 7.43 | 5.84 | 6.10 | 15.00 | 5.14 | 4.49 | 5.48 | 6.41 | 9.53 |
| Colemak | 10.15 | 5.66 | 11.04 | 6.74 | 9.18 | 18.14 | 7.09 | 6.39 | 7.70 | 9.81 | 11.69 |
| Asset | -0.51 | 0.36 | 4.56 | 1.22 | 5.58 | -1.07 | -1.03 | -0.78 | 0.05 | 8.59 | 10.55 |
| Capewell-Dvorak | 8.25 | -0.09 | 4.46 | 5.10 | 4.86 | 9.23 | 2.72 | 2.62 | 5.00 | 7.55 | 5.18 |
| Klausler | 2.97 | -3.06 | 1.53 | 4.18 | 4.21 | 6.88 | 2.17 | 2.47 | 4.35 | 7.11 | 4.96 |
| Dvorak | 10.59 | 1.48 | 7.00 | 8.78 | 8.49 | 12.00 | 8.03 | 8.46 | 10.76 | 9.24 | 7.77 |
| QWERTY | -9.58 | -5.51 | -3.25 | -6.14 | -3.32 | 0.25 | -11.23 | -11.75 | -10.92 | 1.50 | 4.59 |

### Construct heatmap tables

```python
layout_names_engrams = [x for i,x in enumerate(layout_names2) if i < 3]
for imatrix, score_matrix in enumerate(score_matrices):
    matrix_label = matrix_labels[imatrix]

    #if imatrix == 0:
    score_matrix = score_matrix[0:3,:]

    # Normalize by column:
    columns_max = score_matrix.max(axis=0)
    score_matrix = score_matrix / columns_max

    heatmap(data=score_matrix, title=matrix_label, xlabel="", ylabel="",
                       x_axis_labels=text_abbrs, y_axis_labels=layout_names_engrams,
                       print_output=print_output)
```

```python
layout_names2_copy = layout_names2.copy()
layout_names2_copy.remove('QWERTY')
for imatrix, score_matrix in enumerate(score_matrices):
    matrix_label = matrix_labels[imatrix]

    #if imatrix == 0:
    score_matrix = np.delete(score_matrix, (-1), axis=0)
    #    layout_names2_copy.remove('QWERTY')
    #elif imatrix == 1:
    #    layout_names2_copy.append('QWERTY')

    # Normalize by column:
    columns_max = score_matrix.max(axis=0)
    score_matrix = score_matrix / columns_max

    heatmap(data=score_matrix, title=matrix_label, xlabel="", ylabel="",
                       x_axis_labels=text_abbrs, y_axis_labels=layout_names2_copy,
                       print_output=print_output)
```

### Workspace for manual comparisons

```python
layout1 = ['B','Y','O','U','C','I','E','A','G','X','J','K', 'L','D','W','V','H','T','S','N','R','M','F','P', "'",',','-', '"','.','?', 'Z','Q']
layout2 = ['J','Y','G','K','C','I','E','A','W','P','U','O', 'V','L','D','X','H','T','S','N','R','M','F','B', "'",',','-', '"','.','?', 'Z','Q']
layout3 = ['J','K','Y','X','C','I','E','A','G','P','U','O', 'V','L','D','B','H','T','S','N','R','M','F','W', "'",',','-', '"','.','?', 'Z','Q']
layout4 = ['W','Y','O','U','C','I','E','A','G','P','J','K', 'V','L','D','X','H','T','S','N','R','M','F','B', "'",',','-', '"','.','?', 'Z','Q']

data_matrix = Factors32x32
s1 = score_layout(data_matrix, layout1, bigrams, bigram_frequencies, verbose=False)
s2 = score_layout(data_matrix, layout2, bigrams, bigram_frequencies, verbose=False)
s3 = score_layout(data_matrix, layout3, bigrams, bigram_frequencies, verbose=False)
s4 = score_layout(data_matrix, layout4, bigrams, bigram_frequencies, verbose=False)
print('Layout 1: {0}'.format(s1))
print('Layout 2: {0}'.format(s2))
print('Layout 3: {0}'.format(s3))
print('Layout 4: {0}'.format(s4))
```

    Layout 1: 0.7329151915874081
    Layout 2: 0.733112192971112
    Layout 3: 0.7331696596245132
    Layout 4: 0.7329437638133653