python-ternary
python-ternary copied to clipboard
area filling
Great code.
Would be very helpfull to implement the tax.fill() feature, to create base plots with filled areas, like the Dickinson, 1970 Qt ternary plot. Thank you!
I manually implemented this by using some of the code for 'background' fill!
Hi @vmeschke, do you want to share / contribute an example?
@marcharper I would love to! What's the best way to do so?
@vmeschke If you have an image and some code to generate it, you can add it to the examples directory. Otherwise you can paste the info here and I'll add it.
Here's an example of code and the filling demo! I just modified the tax.fill method to take an unspecified number of points. I can talk more/add additional comments if helpful.
Code: import ternary import pandas as pd import math import itertools import numpy as np from pymatgen.core import Element, Composition from matplotlib import cm import matplotlib.pyplot as plt
def permute_point(p, permutation=None): """ Permutes the point according to the permutation keyword argument. The default permutation is "012" which does not change the order of the coordinate. To rotate counterclockwise, use "120" and to rotate clockwise use "201".""" if not permutation: return p return [p[int(permutation[i])] for i in range(len(p))]
def unzip(l): """[(a1, b1), ..., (an, bn)] ----> ([a1, ..., an], [b1, ..., bn])""" return list(zip(*l))
def project_point(p, permutation=None): """ Maps (x,y,z) coordinates to planar simplex. Parameters ---------- p: 3-tuple The point to be projected p = (x, y, z) permutation: string, None, equivalent to "012" The order of the coordinates, counterclockwise from the origin """ permuted = permute_point(p, permutation=permutation) a = permuted[0] b = permuted[1] x = a + b/2. y = (np.sqrt(3)/2) * b return np.array([x, y])
def fill_region(ax, color, points, pattern=None, zorder=-1000, alpha=None): """Draws a triangle behind the plot to serve as the background color for a given region.""" vertices = map(project_point, points) xs, ys = unzip(vertices) poly = ax.fill(xs, ys, facecolor=color, edgecolor=color, hatch=pattern, zorder=zorder, alpha=alpha) return poly
def main(): scale = 100 fontsize = 12 figure, tax = ternary.figure(scale=scale) tax.gridlines(color="grey", multiple=10)
# corner points of the regions. Any number of points works.
regions = [[(0, 0, 100), (25, 0, 75), (25, 50, 25)],
[(25, 0, 75), (50, 50, 0), (30, 40, 30), (25, 50, 25)],
[(50, 50, 0), (43, 57, 0), (25, 50, 25), (70, 10, 20)],
[(40, 50, 10), (28.57, 71.43, 0), (25, 50, 25), (10, 80, 10), (20, 30, 50)]]
# Generating colors for the regions
cmap = cm.plasma
colorlist = []
for i in np.arange(0,1,1/len(regions)):
colorlist.append(cmap(i))
# generate the filled regions and make them all different colors
colorindex = 0
for r in regions:
fill_region(tax.get_axes(), color=colorlist[colorindex], points=r, alpha=.7)
colorindex += 1
# Final plot formatting
tax.boundary(linewidth=2)
tax.get_axes().axis('off')
tax.clear_matplotlib_ticks()
tax.get_axes().set_aspect(1)
tax._redraw_labels()
tax.savefig('filled_ternary.png')
if name == 'main': main()
If you add the following code to the 'ternary_axes_subplot.py' file, you should be able to call tax.fill_region() with the proper arguments and have it work ok. It works locally for me.
Additional Import:
from .helpers import unzip
Method:
def fill_region(self, color, points, pattern=None, zorder=-1000, alpha=None):
"""Draws a triangle behind the plot to serve as the background color
for a given region."""
ax = self.get_axes()
vertices = map(project_point, points)
xs, ys = unzip(vertices)
poly = ax.fill(xs, ys, facecolor=color, edgecolor=color, hatch=pattern, zorder=zorder, alpha=alpha)
return poly