Move StatisticsPen into fontTools.pens.statisticsPen

This commit is contained in:
Behdad Esfahbod 2017-02-20 13:18:08 -06:00
parent 5cbfaa2792
commit f3224d7d34
3 changed files with 80 additions and 81 deletions

View File

@ -0,0 +1,79 @@
from __future__ import print_function, division, absolute_import
from fontTools.misc.py23 import *
import math
from fontTools.pens.momentsPen import MomentsPen
class StatisticsPen(MomentsPen):
# Center of mass
# https://en.wikipedia.org/wiki/Center_of_mass#A_continuous_volume
@property
def meanX(self):
return self.momentX / self.area if self.area else 0
@property
def meanY(self):
return self.momentY / self.area if self.area else 0
# Var(X) = E[X^2] - E[X]^2
@property
def varianceX(self):
return self.momentXX / self.area - self.meanX**2 if self.area else 0
@property
def varianceY(self):
return self.momentYY / self.area - self.meanY**2 if self.area else 0
@property
def stddevX(self):
return math.copysign(abs(self.varianceX)**.5, self.varianceX)
@property
def stddevY(self):
return math.copysign(abs(self.varianceY)**.5, self.varianceY)
# Covariance(X,Y) = ( E[X.Y] - E[X]E[Y] )
@property
def covariance(self):
return self.momentXY / self.area - self.meanX*self.meanY if self.area else 0
# Correlation(X,Y) = Covariance(X,Y) / ( stddev(X) * stddev(Y) )
# https://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient
@property
def correlation(self):
correlation = self.covariance / (self.stddevX * self.stddevY) if self.area else 0
return correlation if abs(correlation) > 1e-3 else 0
@property
def slant(self):
slant = self.covariance / self.varianceY if self.area else 0
return slant if abs(slant) > 1e-3 else 0
def _test(glyphset, upem, glyphs):
from fontTools.pens.transformPen import TransformPen
from fontTools.misc.transform import Scale
print('upem', upem)
for glyph_name in glyphs:
print()
print("glyph:", glyph_name)
glyph = glyphset[glyph_name]
pen = StatisticsPen(glyphset=glyphset)
transformer = TransformPen(pen, Scale(1./upem))
glyph.draw(transformer)
for item in ['area', 'momentX', 'momentY', 'momentXX', 'momentYY', 'momentXY', 'meanX', 'meanY', 'varianceX', 'varianceY', 'stddevX', 'stddevY', 'covariance', 'correlation', 'slant']:
if item[0] == '_': continue
print ("%s: %g" % (item, getattr(pen, item)))
def main(args):
if not args:
return
filename, glyphs = args[0], args[1:]
if not glyphs:
glyphs = ['e', 'o', 'I', 'slash', 'E', 'zero', 'eight', 'minus', 'equal']
from fontTools.ttLib import TTFont
font = TTFont(filename)
_test(font.getGlyphSet(), font['head'].unitsPerEm, glyphs)
if __name__ == '__main__':
import sys
main(sys.argv[1:])

View File

@ -9,7 +9,7 @@ from __future__ import print_function, division, absolute_import
from fontTools.misc.py23 import * from fontTools.misc.py23 import *
from fontTools.pens.basePen import BasePen from fontTools.pens.basePen import BasePen
from symfont import StatisticsPen from fontTools.pens.statisticsPen import StatisticsPen
import itertools import itertools
class PerContourOrComponentPen(BasePen): class PerContourOrComponentPen(BasePen):

View File

@ -12,11 +12,7 @@ from fontTools.misc.py23 import *
import sympy as sp import sympy as sp
import sys import sys
import math
from fontTools.pens.basePen import BasePen from fontTools.pens.basePen import BasePen
from fontTools.pens.transformPen import TransformPen
from fontTools.pens.momentsPen import MomentsPen
from fontTools.misc.transform import Scale
from functools import partial from functools import partial
from itertools import count from itertools import count
@ -188,79 +184,3 @@ MomentXYPen = partial(GreenPen, func=x*y)
#
# Glyph statistics object
#
class StatisticsPen(MomentsPen):
# Center of mass
# https://en.wikipedia.org/wiki/Center_of_mass#A_continuous_volume
@property
def meanX(self):
return self.momentX / self.area if self.area else 0
@property
def meanY(self):
return self.momentY / self.area if self.area else 0
# Var(X) = E[X^2] - E[X]^2
@property
def varianceX(self):
return self.momentXX / self.area - self.meanX**2 if self.area else 0
@property
def varianceY(self):
return self.momentYY / self.area - self.meanY**2 if self.area else 0
@property
def stddevX(self):
return math.copysign(abs(self.varianceX)**.5, self.varianceX)
@property
def stddevY(self):
return math.copysign(abs(self.varianceY)**.5, self.varianceY)
# Covariance(X,Y) = ( E[X.Y] - E[X]E[Y] )
@property
def covariance(self):
return self.momentXY / self.area - self.meanX*self.meanY if self.area else 0
# Correlation(X,Y) = Covariance(X,Y) / ( stddev(X) * stddev(Y) )
# https://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient
@property
def correlation(self):
correlation = self.covariance / (self.stddevX * self.stddevY) if self.area else 0
return correlation if abs(correlation) > 1e-3 else 0
@property
def slant(self):
slant = self.covariance / self.varianceY if self.area else 0
return slant if abs(slant) > 1e-3 else 0
def test(glyphset, upem, glyphs):
print('upem', upem)
for glyph_name in glyphs:
print()
print("glyph:", glyph_name)
glyph = glyphset[glyph_name]
pen = StatisticsPen(glyphset=glyphset)
transformer = TransformPen(pen, Scale(1./upem))
glyph.draw(transformer)
for item in ['area', 'momentX', 'momentY', 'momentXX', 'momentYY', 'momentXY', 'meanX', 'meanY', 'varianceX', 'varianceY', 'stddevX', 'stddevY', 'covariance', 'correlation', 'slant']:
if item[0] == '_': continue
print ("%s: %g" % (item, getattr(pen, item)))
def main(args):
if not args:
return
filename, glyphs = args[0], args[1:]
if not glyphs:
glyphs = ['e', 'o', 'I', 'slash', 'E', 'zero', 'eight', 'minus', 'equal']
from fontTools.ttLib import TTFont
font = TTFont(filename)
test(font.getGlyphSet(), font['head'].unitsPerEm, glyphs)
if __name__ == '__main__':
import sys
main(sys.argv[1:])