Colemak's the winner.
I'm sure everyone here will like that bit of news. :)
I've seen digraph analysis mentioned a lot as a measurement for "goodness" of a layout, but I've never seen anyone actually do any kind of numerical approach to it. There are a lot of metrics you can use that capture aspects of "goodness"; same-finger repetition, hand usage, finger usage, same-hand row jumps, hand alternation, stroke flow, home position usage. It's somewhat frustrating to have to look at all of them and make a judgment call on the relative weight you want to assign them. I set out on trying to capture digraph "goodness" in the hopes that it would be somewhat more holistic, that is to say, that what's good in the other metrics might automatically be captured in a good digraph score. Intuitively I think there's some truth to that when I look at how I've pursued it here, but I have no appraisal of that theory to offer at the moment. I hope it can be argued that it can incorporate the attributes of some or all of the other metrics though, as my hope is to simplify the metrics, not complicate them by adding a new one to the mix. :)
If someone else has already done a metric like this, I'm all ears. I just did it as an exercise to deepen my understanding.
What I do have is a methodology, some data and a bare-bones implementation. I thought you all might like to see it and perhaps play with it or provide some feedback.
So the question was how to look at digraph usage and put some sort of number on how easy/difficult a layout is to use by looking at how your fingers have to move from one key to the next. The idea is to take a weighted average of the "difficulty rank" of every digraph on the keyboard. This requires you to look at each digraph on the keyboard and assign a difficulty index. Once you've mapped the combinations of all the keys and assigned these weights, you then take some digraph frequency data on how frequently each occurs. Simply multiplying each digraph weight by its associated frequency and adding them all together gives you a weighted average for the entire keyboard, et voila, a single number that represents digraph difficulty.
I had to use some assumptions to use this approach:
1. Approximation: don't go into trigraphs, even though they have an effect in the real world for advanced typists. I'm ok with this first-order approximation.
2. Define a simple keymask: The implementation simplifies things by putting the semicolon key in the qwerty "p" position like colemak. When I use the model to calculate the metric for qwerty and others like it, I do this substitution so it's not exactly qwerty I'm measuring, but close enough. This works for layouts like qwerty, minimak and colemak (my interests), but not for dvorak because it moves too many non-letter keys, so I don't have a number for dvorak yet.
3. Weights are subjective, but that's ok: With about 186 weights to classify, I think that the general comparative weights will come out consistently, even if individual weights are arguable. It's about having consistent comparative weights across the spectrum of digraphs, and I think most people will come to consensus on relative difficulties.
4. Use a difficulty metric rather than an ease metric: This lets you choose a base metric of difficulty 0 and move up from there. If in the course of evaluating the weights you discover that your scale was not broad enough, just add more at the top. It also simplifies the implementation while you're building the weights list by assuming weight 0 for any undefined digraph.
5. When considering weights, I only consider relative hand position, that is to say, I don't consider difficulty for reaching the digraph from the home position, just for reaching the keys from each other (when your hand is in the best position for that task). This is because hands float to some extent when they know the next two keys coming up and will move out of the home position to make it easier. This is the weight I want to capture, your idea of this may differ. You can reflect your desire by choosing different weights, it's entirely granular.
6. Ignore asymmetry: For simplicity, I ignore the fact that the rows on the keyboard are staggered and asymmetric. A better weighting would take this into account. That might help if you were using this metric to optimize a layout, but I don't think would affect the relative rankings of different layouts I've measured.
7. Hand alternations are 0 difficulty. I chose to ignore digraphs which cross hands, both to limit the scope of digraphs that need to be weighted, as well as the fact that having an entire free hand to find a key eliminates hand position difficulty (no stretched fingers) and gives you more time to locate your hand properly.
8. Digraphs are not order-specific. I don't consider "e-r" and "r-e" to be different digraphs (technically this might be called pairing rather than digraphs, but I still use the term). This is another simplification, and a good one I think because I'm interested in the difficulty of hand movement rather than, say stroke flow. Others might reasonably differ on the importance of stroke flow, but it's much harder to capture that so this metric doesn't try. This also means that your frequency data must merge the incidence of "e-r" and "r-e" into one number.
I've finished my weight categorization and written a python script which allows you to create Layout objects and ask them for their metric. It's meant to be run in the interpreter.
For weights, I used a simple 5-point ranking scale. The easiest digraphs are 0, as I've mentioned. The hardest ended up going up to 5, which are same-finger pinky jumps between top and bottom rows. The vast majority are between 0 and 3, 3 being most same-finger repetitions. You can see a graphic of all of the metrics I chose here: http://www.minimak.org/assets/media/weights.png. I use simple integer "ranks". A rank is based on the comparative difficulty with other digraphs. The simplest are the home positions, which I rank at 0 with each other. I left all of the 0 weight digraphs off the diagram and out of the data file, which assumes 0 if the rank is missing. There are no "half-ranks", there are only integers, so I'm sure there are several with the same rank that might be seen as disparate in difficulty. When you compare them with a 5, say, the difference becomes much smaller, so I've just tried to keep them comparatively accurate on the whole without going to 11 ranks.
The frequency data is included, which is a frequency analysis I did of my own email output for the last 10 years. Feel free to use your own instead, just remember that you need to use pairs rather than ordered digraphs. I also left out any of my digraph data with an incidence of less than .1%, so it doesn't add up to 100% and that's ok.
The python files are in my repository at https://github.com/binaryphile/minimak/ … ter/design. The main file is layout.py. The default frequency and weight data is in layout.yml. You can replace it with your own or load it into the object on instantiation. The main object is Layout.
Usage:
The script requires numpy to be installed: easy_install numpy or pip install numpy. If you're on windows, you can find builds on their site.
It also requires bunch and unipath, both can be pip installed.
Fire up the python interpreter from the layout.py directory.
from layout import Layout
Create a layout: l = Layout() # default layout is qwerty
Ask for its metric: l.metric
Create an explicit qwerty layout: m = Layout('qwertyuioasdfghjklpzxcvbnm')
The frequencies and weights default to mine but you can pass your own in dicts through the constructor.
The representation of a layout is simply a string of the letters, starting from the upper left corner, no newlines. Note that the keymask doesn't include semicolon, which is assumed to be in the upper right-hand corner, so you have to put "p" in the home row or somewhere else.
You can't modify a layout after it's been created, you have to make a new one.
The frequencies are a dict keyed by the two letters in question, in a single string in alphabetical order. So "e-r" in real life is keyed as "er", not "re". Note that yml reserves "no" as a keyword, so it requires quotes in the data file.
The weights are different. It's a dict, keyed by keyboard position, not by letter, since different layouts don't agree on lettering. I would have used numbers to denote key positions, but as you can see from the weights diagram, letters are naturally suited. So I just made a "numbering" of the positions with letters (like hexadecimal, only without the first 10 digits and going up to z), putting "a" in the upper left-hand corner and proceeding alphabetically. You have to use these positions as your dictionary key, again as a single string in alphabetical order (e.g. "ab", there is no "ba").
Here are some difficulty metrics I calculated (lower is better):
QWERTY:
a = Layout()
a.metric
0.67700000000000005
Minimak 12-key:
b = Layout('qwdfkyuilastrghneopzxcvbjm')
b.metric
0.39200000000000002
Colemak:
c = Layout('qwfpgjluyarstdhneiozxcvbkm')
c.metric
0.32800000000000001
carPalx fully-optimized QGMLWB:
d = Layout('qgmlwbyuvdstnriaeohzxcfjkp')
d.metric
0.35300000000000009
So there you have it. Thoughts?
Minimak - Better typing without losing QWERTY
http://www.minimak.org/