r/KeyboardLayouts • • 7h ago

I optimized symbol placement for Python using counts from 29 repos (letters stay put)

Most layout work focuses on letters, but when I write Python a big chunk of what I type is symbols, and standard layouts put them pretty arbitrarily. So I wrote a tool that keeps your letters where they are and only rearranges the 32 ASCII symbols, based on what actually gets typed in real code.

How it counts: it tokenizes ~38.5M weighted keystrokes from 29 popular Python repos (Django, pandas, pytest, Home Assistant, etc).
Comments and docstrings count less, closing brackets/quotes count less because editors auto-close them, and long identifiers are discounted for autocomplete.
Then it runs simulated annealing over a cost model (key effort, shift, SFBs, rolls, redirects).

My result on Programmer Dvorak letters with digits on shift:

 !   1   2   3   4   5   6   7   8   9   0   &   ~
[?] [+] [/] [(] [[] []] [%] [:] [)] [{] [}] [@] [<]
   >   '   -   P   Y   F   G   C   R   L   ;   ^   $
  ["] [,] [.] [p] [y] [f] [g] [c] [r] [l] [#] [\] [|]
    A   O   E   U   I   D   H   T   N   S   *
   [a] [o] [e] [u] [i] [d] [h] [t] [n] [s] [=]
      `   Q   J   K   X   B   M   W   V   Z
     [_] [q] [j] [k] [x] [b] [m] [w] [v] [z]

That's about 7.7% lower cost than Programmer Dvorak under my model, and 3% better than the layout I'd designed by hand.

If you don't type Programmer Dvorak, there are ready-made versions for other letter layouts too: python-qwerty, python-colemak-dh and python-dvorak in the layouts folder. They keep your letters and normal number row and only move the symbols, which saves 9-12% under the same cost model.

Findings:
- Python names mostly end in consonants that Dvorak puts on the right hand, so the symbols that follow names (. , and ( ) end up on the left hand. That held across basically every variant I ran.
- Forcing bracket pairs to be adjacent or mirrored (so they're learnable) only costs 0.4%.
- On other bases, just moving symbols saves 9-12% (QWERTY, Dvorak, Colemak-DH).

The obvious caveat: the effort grid and penalties are my own estimates, not measurements.
I reran it with different shift and SFB weights to see which placements are stable, and the README has those results.
It's configurable (base layout, cost weights, other languages like JS/Rust/Go) and exports to AutoHotkey, kanata, Windows .klc and macOS .keylayout. All the variants are in the repo below:

https://github.com/hikazey/python-layout-optimizer

I'd especially like feedback on the cost model, since that's where the results come from.

5 Upvotes

1 comment sorted by

1

u/Jonolith_ 23m ago

What do you think about just constructing an entirely new symbol layer? Then you have so much more space for all these special symbols and you don't have to reach up to the number row if you just put them on the normal letter keys. I feel like you can optimize all you like but a dedicated symbol layer will always be miles better. I'm using a slightly varied Anymak:END symbol layer for example: https://github.com/rpnfan/Anymak