summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars-Dominik Braun <lars@6xq.net>2019-09-28 17:37:10 +0200
committerLars-Dominik Braun <lars@6xq.net>2019-09-28 17:37:10 +0200
commit33564f4996840e3a9d3867283abea2a085d77b3a (patch)
treed867cf93fb27370c6867b99502e46c340316fc64
parentc37d0e2e98d4aa1b3a4de0fecbf7ebde2e7de69c (diff)
downloadlulua-33564f4996840e3a9d3867283abea2a085d77b3a.tar.gz
lulua-33564f4996840e3a9d3867283abea2a085d77b3a.tar.bz2
lulua-33564f4996840e3a9d3867283abea2a085d77b3a.zip
analyze: Customizeable triadfreq output
Add commandline args to triadfreq.
-rw-r--r--lulua/plot.py44
-rw-r--r--lulua/render.py25
-rw-r--r--lulua/stats.py4
-rw-r--r--lulua/util.py23
4 files changed, 50 insertions, 46 deletions
diff --git a/lulua/plot.py b/lulua/plot.py
index 13077e0..453c6eb 100644
--- a/lulua/plot.py
+++ b/lulua/plot.py
@@ -18,7 +18,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-import sys, argparse, json, unicodedata, pickle, logging
+import sys, argparse, json, unicodedata, pickle, logging, math
from operator import itemgetter
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, LinearAxis, Range1d
@@ -26,7 +26,7 @@ from bokeh.embed import json_item
from .layout import *
from .keyboard import defaultKeyboards
-from .util import limit
+from .util import limit, displayText
from .writer import Writer
from .carpalx import Carpalx, model01
@@ -104,6 +104,17 @@ def letterfreq (args):
return 0
def triadfreq (args):
+ """ Dump triad frequency stats to stdout """
+ sorter = dict (
+ weight=lambda x: x['weight'],
+ effort=lambda x: x['effort'].effort,
+ # increase impact of extremely “bad” triads using math.pow
+ combined=lambda x: (x['weight']/weightSum)*math.pow (x['effort'].effort, 2)
+ )
+ def noLimit (l, n):
+ yield from l
+ limiter = limit if args.limit > 0 else noLimit
+
stats = pickle.load (sys.stdin.buffer)
# XXX: add layout to stats?
@@ -126,32 +137,19 @@ def triadfreq (args):
# triads that contribute to x% of the weight
topTriads = list ()
- topTriadsCutoff = 0.50
topTriadsWeight = 0
for data in sorted (binned.values (), key=lambda x: x['weight'], reverse=True):
- if topTriadsWeight < weightSum*topTriadsCutoff:
+ if topTriadsWeight < weightSum*args.cutoff:
topTriads.append (data)
topTriadsWeight += data['weight']
- # get top triads (by weight)
- print ('by weight')
- for data in limit (sorted (binned.values (), key=lambda x: x['weight'], reverse=True), 20):
- print (data['textTriad'], data['weight'], data['effort'].effort)
-
- logging.info (f'{len (topTriads)}/{len (stats["triads"].triads)} triads contribute to {topTriadsCutoff*100}% of the typing')
-
- print ('by effort')
- # only base layer
- includeBaseLayer = iter (topTriads)
- sortByEffort = sorted (includeBaseLayer, key=lambda x: x['effort'].effort, reverse=True)
- for data in limit (sortByEffort, 20):
- print (data['textTriad'], data['weight'], data['effort'].effort)
-
- print ('by effort and weight')
- includeBaseLayer = iter (topTriads)
- sortByEffortWeight = sorted (includeBaseLayer, key=lambda x: (x['weight']/weightSum)*x['effort'].effort, reverse=True)
- for data in limit (sortByEffortWeight, 20):
- print (data['textTriad'], data['weight'], data['effort'].effort)
+ logging.info (f'{len (topTriads)}/{len (stats["triads"].triads)} triads '
+ 'contribute to {args.cutoff*100}% of the typing')
+
+ # final output
+ sortByEffort = sorted (iter (topTriads), key=sorter[args.sort], reverse=args.reverse)
+ for data in limiter (sortByEffort, args.limit):
+ print (''.join (map (displayText, data['textTriad'])), data['weight'], data['effort'].effort)
return 0
diff --git a/lulua/render.py b/lulua/render.py
index cbe553b..16dc543 100644
--- a/lulua/render.py
+++ b/lulua/render.py
@@ -18,7 +18,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-import argparse, sys, unicodedata, logging
+import argparse, sys, logging
from collections import namedtuple, defaultdict
from operator import attrgetter
from datetime import datetime
@@ -30,7 +30,7 @@ import yaml
from .layout import LITTLE, RING, MIDDLE, INDEX, THUMB, GenericLayout, defaultLayouts
from .writer import Writer
from .keyboard import defaultKeyboards
-from .util import first
+from .util import first, displayText
RendererSettings = namedtuple ('RendererSetting', ['buttonMargin', 'middleGap', 'buttonWidth', 'rounded', 'shadowOffset'])
@@ -99,25 +99,6 @@ class Renderer:
return btn.width * self.settings.buttonWidth
def _addButton (self, btn):
- def toDisplayText (text):
- if text is None:
- return text
- if len (text) == 1 and unicodedata.combining (text) != 0:
- # add circle if combining
- return '\u25cc' + text
- invMap = {
- '\t': '⭾',
- '\n': '↳',
- ' ': '\u2423',
- '\u200e': '[LRM]', # left to right mark
- '\u061c': '[ALM]', # arabic letter mark
- '\u202c': '[PDF]', # pop directional formatting
- "\u2066": '[LRI]', # left-to-right isolate (lri)
- "\u2067": '[RLI]', # right-to-left isolate (rli)
- "\u2069": '[PDI]', # pop directional isolate (pdi)
- }
- return invMap.get (text, text)
-
xoff, yoff = self.cursor
settings = self.settings
width = self.buttonWidth (btn)
@@ -137,7 +118,7 @@ class Renderer:
buttonText = [layerToArrow[i]]
gclass.append ('modifier')
else:
- buttonText = list (map (toDisplayText, self.layout.getButtonText (btn)))
+ buttonText = list (map (displayText, self.layout.getButtonText (btn)))
# background rect
if any (buttonText):
diff --git a/lulua/stats.py b/lulua/stats.py
index fc2b202..6689616 100644
--- a/lulua/stats.py
+++ b/lulua/stats.py
@@ -234,6 +234,10 @@ def main ():
sp = subparsers.add_parser('letterfreq')
sp.set_defaults (func=letterfreq)
sp = subparsers.add_parser('triadfreq')
+ sp.add_argument('-c', '--cutoff', type=float, default=0.5, help='Only include the top x% of all triads')
+ sp.add_argument('-r', '--reverse', action='store_true', help='Reverse sorting order')
+ sp.add_argument('-s', '--sort', choices={'weight', 'effort', 'combined'}, default='weight', help='Sorter')
+ sp.add_argument('-n', '--limit', type=int, default=0, help='Sorter')
sp.set_defaults (func=triadfreq)
logging.basicConfig (level=logging.INFO)
diff --git a/lulua/util.py b/lulua/util.py
index dd35c23..1e2156d 100644
--- a/lulua/util.py
+++ b/lulua/util.py
@@ -22,11 +22,12 @@
Misc utilities
"""
-import os, yaml, pkg_resources
+import os, yaml, pkg_resources, unicodedata
first = lambda x: next (iter (x))
def limit (l, n):
+ """ Limit the number of items drawn from iterable l to n. """
it = iter (l)
for i in range (n):
yield next (it)
@@ -65,3 +66,23 @@ class YamlLoader:
for res in pkg_resources.resource_listdir (__package__, self.defaultDir):
yield self.__getitem__ (res, onlyRes=True)
+def displayText (text):
+ """ Convert text into a string that is always renderable without combining,
+ control or invisible characters """
+ if text is None:
+ return text
+ if len (text) == 1 and unicodedata.combining (text) != 0:
+ # add circle if combining
+ return '\u25cc' + text
+ invMap = {
+ '\t': '⭾',
+ '\n': '↳',
+ ' ': '\u2423',
+ '\u200e': '[LRM]', # left to right mark
+ '\u061c': '[ALM]', # arabic letter mark
+ '\u202c': '[PDF]', # pop directional formatting
+ "\u2066": '[LRI]', # left-to-right isolate (lri)
+ "\u2067": '[RLI]', # right-to-left isolate (rli)
+ "\u2069": '[PDI]', # pop directional isolate (pdi)
+ }
+ return invMap.get (text, text)