# Source code for fontTools.varLib.plot

    """Visualize DesignSpaceDocument and resulting VariationModel."""

    from fontTools.varLib.models import VariationModel, supportScalar
    from fontTools.designspaceLib import DesignSpaceDocument
    from matplotlib import pyplot
    from mpl_toolkits.mplot3d import axes3d
    from itertools import cycle
    import math
    import logging
    import sys

    log = logging.getLogger(__name__)

    def stops(support, count=10):
    	a,b,c = support

    	return [a + (b - a) * i / count for i in range(count)] + \
    	       [b + (c - b) * i / count for i in range(count)] + \
    	       [c]

    def _plotLocationsDots(locations, axes, subplot, **kwargs):
    	for loc, color in zip(locations, cycle(pyplot.cm.Set1.colors)):
    		if len(axes) == 1:
    			subplot.plot(
    				[loc.get(axes[0], 0)],
    				[1.],
    				'o',
    				color=color,
    				**kwargs
    			)
    		elif len(axes) == 2:
    			subplot.plot(
    				[loc.get(axes[0], 0)],
    				[loc.get(axes[1], 0)],
    				[1.],
    				'o',
    				color=color,
    				**kwargs
    			)
    		else:
    			raise AssertionError(len(axes))

    def plotLocations(locations, fig, names=None, **kwargs):
    	n = len(locations)
    	cols = math.ceil(n**.5)
    	rows = math.ceil(n / cols)

    	if names is None:
    		names = [None] * len(locations)

    	model = VariationModel(locations)
    	names = [names[model.reverseMapping[i]] for i in range(len(names))]

    	axes = sorted(locations[0].keys())
    	if len(axes) == 1:
    		_plotLocations2D(
    			model, axes[0], fig, cols, rows, names=names, **kwargs
    		)
    	elif len(axes) == 2:
    		_plotLocations3D(
    			model, axes, fig, cols, rows, names=names, **kwargs
    		)
    	else:
    		raise ValueError("Only 1 or 2 axes are supported")

    def _plotLocations2D(model, axis, fig, cols, rows, names, **kwargs):
    	subplot = fig.add_subplot(111)
    	for i, (support, color, name) in enumerate(
    		zip(model.supports, cycle(pyplot.cm.Set1.colors), cycle(names))
    	):
    		if name is not None:
    			subplot.set_title(name)
    		subplot.set_xlabel(axis)
    		pyplot.xlim(-1.,+1.)

    		Xs = support.get(axis, (-1.,0.,+1.))
    		X, Y = [], []
    		for x in stops(Xs):
    			y = supportScalar({axis:x}, support)
    			X.append(x)
    			Y.append(y)
    		subplot.plot(X, Y, color=color, **kwargs)

    		_plotLocationsDots(model.locations, [axis], subplot)

    def _plotLocations3D(model, axes, fig, rows, cols, names, **kwargs):
    	ax1, ax2 = axes

    	axis3D = fig.add_subplot(111, projection='3d')
    	for i, (support, color, name) in enumerate(
    		zip(model.supports, cycle(pyplot.cm.Set1.colors), cycle(names))
    	):
    		if name is not None:
    			axis3D.set_title(name)
    		axis3D.set_xlabel(ax1)
    		axis3D.set_ylabel(ax2)
    		pyplot.xlim(-1.,+1.)
    		pyplot.ylim(-1.,+1.)

    		Xs = support.get(ax1, (-1.,0.,+1.))
    		Ys = support.get(ax2, (-1.,0.,+1.))
    		for x in stops(Xs):
    			X, Y, Z = [], [], []
    			for y in Ys:
    				z = supportScalar({ax1:x, ax2:y}, support)
    				X.append(x)
    				Y.append(y)
    				Z.append(z)
    			axis3D.plot(X, Y, Z, color=color, **kwargs)
    		for y in stops(Ys):
    			X, Y, Z = [], [], []
    			for x in Xs:
    				z = supportScalar({ax1:x, ax2:y}, support)
    				X.append(x)
    				Y.append(y)
    				Z.append(z)
    			axis3D.plot(X, Y, Z, color=color, **kwargs)

    		_plotLocationsDots(model.locations, [ax1, ax2], axis3D)

    def plotDocument(doc, fig, **kwargs):
    	doc.normalize()
    	locations = [s.location for s in doc.sources]
    	names = [s.name for s in doc.sources]
    	plotLocations(locations, fig, names, **kwargs)

    def _plotModelFromMasters2D(model, masterValues, fig, **kwargs):
    	assert len(model.axisOrder) == 1
    	axis = model.axisOrder[0]

    	axis_min = min(loc.get(axis, 0) for loc in model.locations)
    	axis_max = max(loc.get(axis, 0) for loc in model.locations)

    	import numpy as np
    	X = np.arange(axis_min, axis_max, (axis_max - axis_min) / 100)
    	Y = []

    	for x in X:
    		loc = {axis: x}
    		v = model.interpolateFromMasters(loc, masterValues)
    		Y.append(v)

    	subplot = fig.add_subplot(111)
    	subplot.plot(X, Y, '-', **kwargs)

    def _plotModelFromMasters3D(model, masterValues, fig, **kwargs):
    	assert len(model.axisOrder) == 2
    	axis1, axis2 = model.axisOrder[0], model.axisOrder[1]

    	axis1_min = min(loc.get(axis1, 0) for loc in model.locations)
    	axis1_max = max(loc.get(axis1, 0) for loc in model.locations)
    	axis2_min = min(loc.get(axis2, 0) for loc in model.locations)
    	axis2_max = max(loc.get(axis2, 0) for loc in model.locations)

    	import numpy as np
    	X = np.arange(axis1_min, axis1_max, (axis1_max - axis1_min) / 100)
    	Y = np.arange(axis2_min, axis2_max, (axis2_max - axis2_min) / 100)
    	X, Y = np.meshgrid(X, Y)
    	Z = []

    	for row_x,row_y in zip(X,Y):
    		z_row = []
    		Z.append(z_row)
    		for x,y in zip(row_x,row_y):
    			loc = {axis1: x, axis2: y}
    			v = model.interpolateFromMasters(loc, masterValues)
    			z_row.append(v)
    	Z = np.array(Z)

    	axis3D = fig.add_subplot(111, projection='3d')
    	axis3D.plot_surface(X, Y, Z, **kwargs)

    def plotModelFromMasters(model, masterValues, fig, **kwargs):
    	"""Plot a variation model and set of master values corresponding
    	to the locations to the model into a pyplot figure.  Variation
    	model must have axisOrder of size 1 or 2."""
    	if len(model.axisOrder) == 1:
    		_plotModelFromMasters2D(model, masterValues, fig, **kwargs)
    	elif len(model.axisOrder) == 2:
    		_plotModelFromMasters3D(model, masterValues, fig, **kwargs)
    	else:
    		raise ValueError("Only 1 or 2 axes are supported")

    def main(args=None):
    	from fontTools import configLogger

    	if args is None:
    		args = sys.argv[1:]

    	# configure the library logger (for >= WARNING)
    	configLogger()
    	# comment this out to enable debug messages from logger
    	# log.setLevel(logging.DEBUG)

    	if len(args) < 1:
    		print("usage: fonttools varLib.plot source.designspace", file=sys.stderr)
    		print("  or")
    		print("usage: fonttools varLib.plot location1 location2 ...", file=sys.stderr)
    		print("  or")
    		print("usage: fonttools varLib.plot location1=value1 location2=value2 ...", file=sys.stderr)
    		sys.exit(1)

    	fig = pyplot.figure()
    	fig.set_tight_layout(True)

    	if len(args) == 1 and args[0].endswith('.designspace'):
    		doc = DesignSpaceDocument()
    		doc.read(args[0])
    		plotDocument(doc, fig)
    	else:
    		axes = [chr(c) for c in range(ord('A'), ord('Z')+1)]
    		if '=' not in args[0]:
    			locs = [dict(zip(axes, (float(v) for v in s.split(',')))) for s in args]
    			plotLocations(locs, fig)
    		else:
    			locations = []
    			masterValues = []
    			for arg in args:
    				loc,v = arg.split('=')
    				locations.append(dict(zip(axes, (float(v) for v in loc.split(',')))))
    				masterValues.append(float(v))
    			model = VariationModel(locations, axes[:len(locations[0])])
    			plotModelFromMasters(model, masterValues, fig)

    	pyplot.show()

    if __name__ == '__main__':
    	import sys
    	sys.exit(main())