├── .gitignore
├── CITATION.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── README.txt
├── citations.md
├── examples
├── Scatter_plot_colorbar.pdf
├── Ternary-Examples.ipynb
├── color_coded_heatmap.py
├── colorbar_kwargs.py
├── custom_axis_scaling.py
├── sample_data
│ ├── curve.txt
│ ├── sample_heatmap_data.txt
│ └── scatter_colorbar.txt
├── scatter_colorbar.py
└── ternary_contours.py
├── readme_images
├── 16_80_1.png
├── 16_80_stationary.png
├── 23_80_0.png
├── 24_80_1.png
├── boundary_and_gridlines.png
├── btweinstein_example.png
├── btweinstein_example2.png
├── colored_boundary.png
├── colored_trajectory.png
├── heatmap-dual_vs_triangular.png
├── heatmap-dualtriangular.png
├── heatmap-grids.png
├── heatmap-grids.svg
├── heatmap-triangular.png
├── heatmap_rsp.png
├── heatmap_shannon.png
├── heatmap_styles.py
├── heatmap_styles_cubehelix.pdf
├── heatmap_styles_cubehelix.png
├── heatmap_styles_gray.pdf
├── heatmap_styles_gray.png
├── orientations.png
├── rgba_example.png
├── scatter.png
├── trajectory.png
└── various_lines.png
├── setup.cfg
├── setup.py
├── ternary
├── __init__.py
├── colormapping.py
├── heatmapping.py
├── helpers.py
├── lines.py
├── plotting.py
└── ternary_axes_subplot.py
└── tests
├── test_heatmapping.py
└── test_helpers.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 |
--------------------------------------------------------------------------------
/CITATION.md:
--------------------------------------------------------------------------------
1 | # Citation
2 |
3 | [](https://zenodo.org/badge/latestdoi/19505/marcharper/python-ternary)
4 |
5 | Please cite as follows:
6 |
7 | ```
8 | Marc Harper et al. (2015). python-ternary: Ternary Plots in Python. Zenodo. 10.5281/zenodo.594435
9 | ```
10 |
11 | Bibtex:
12 | ```
13 | @article{pythonternary,
14 | title={python-ternary: Ternary Plots in Python},
15 | author={Marc Harper et al},
16 | journal={Zenodo 10.5281/zenodo.594435},
17 | doi={10.5281/zenodo.594435},
18 | url={https://github.com/marcharper/python-ternary},
19 | }
20 | ```
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2015-2021 Marc Harper
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include *.md
2 | include *.txt
3 | include LICENSE
4 |
5 | graft examples
6 | graft readme_images
7 | graft tests
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # python-ternary
3 |
4 |
5 | [](https://zenodo.org/badge/latestdoi/19505/marcharper/python-ternary)
6 | [](https://gitter.im/marcharper/python-ternary?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
7 |
8 | This is a plotting library for use with [matplotlib](http://matplotlib.org/index.html) to make [ternary plots](http://en.wikipedia.org/wiki/Ternary_plot)
9 | plots in the two dimensional simplex projected onto a two dimensional plane.
10 |
11 | The library provides functions for plotting projected lines, curves (trajectories), scatter plots, and heatmaps. There are [several examples](examples/) and a short tutorial below.
12 |
13 | # Gallery
14 |
15 |
35 |
36 | # Citations and Recent Usage in Publications
37 |
38 | [](https://zenodo.org/badge/latestdoi/19505/marcharper/python-ternary)
39 |
40 | Have you used python-ternary in a publication? Open a PR or issue to include
41 | your citations or example plots!
42 |
43 | See the [partial list of citations](citations.md) and
44 | [instructions on how to cite](CITATION.md).
45 |
46 | # Installation
47 |
48 | ### Anaconda
49 |
50 | You can install python-ternary with conda:
51 |
52 | ```bash
53 | conda config --add channels conda-forge
54 | conda install python-ternary
55 | ```
56 |
57 | See [here](https://github.com/conda-forge/python-ternary-feedstock) for more
58 | information.
59 |
60 | ### Pip
61 |
62 | You can install the current release (1.0.6) with pip:
63 | ```bash
64 | pip install python-ternary
65 | ```
66 |
67 | ### With setup.py
68 |
69 | Alternatively you can clone the repository and run `setup.py` in the usual
70 | manner:
71 |
72 | ```bash
73 | git clone git@github.com:marcharper/python-ternary.git
74 | cd python-ternary
75 | python setup.py install
76 | ```
77 |
78 | # Usage, Examples, Plotting Functions
79 |
80 | You can explore some of these examples with
81 | [this Jupyter notebook](examples/Ternary-Examples.ipynb).
82 |
83 | The easiest way to use python-ternary is with the wrapper class
84 | `TernaryAxesSubplot`, which mimics Matplotlib's AxesSubplot. Start with:
85 |
86 | ```python
87 | fig, tax = ternary.figure()
88 | ```
89 |
90 | With a ternary axes object `tax` you can use many of the usual matplotlib
91 | axes object functions:
92 |
93 | ```python
94 | tax.set_title("Scatter Plot", fontsize=20)
95 | tax.scatter(points, marker='s', color='red', label="Red Squares")
96 | tax.legend()
97 | ```
98 |
99 | Most drawing functions can take standard matplotlib keyword arguments such as
100 | [linestyle](http://matplotlib.org/api/lines_api.html#matplotlib.lines.Line2D.set_linestyle)
101 | and linewidth. You can use LaTeX in titles and labels.
102 |
103 | If you need to act directly on the underlying matplotlib axes, you can access
104 | them easily:
105 |
106 | ```python
107 | ax = tax.get_axes()
108 | ```
109 |
110 | You can also wrap an existing Matplotlib AxesSubplot object:
111 |
112 | ```
113 | figure, ax = pyplot.subplots()
114 | tax = ternary.TernaryAxesSubplot(ax=ax)
115 | ```
116 |
117 | This is useful if you want to use ternary as a part of another figure, such as
118 |
119 | ```python
120 | from matplotlib import pyplot, gridspec
121 |
122 | pyplot.figure()
123 | gs = gridspec.GridSpec(2, 2)
124 | ax = pyplot.subplot(gs[0, 0])
125 | figure, tax = ternary.figure(ax=ax)
126 | ...
127 | ```
128 |
129 | Some ternary functions expect the simplex to be partitioned into some number
130 | of steps, determined by the `scale` parameter. A few functions will do this
131 | partitioning automatically for you, but when working with real data or
132 | simulation output, you may have partitioned already. If you are working with
133 | probability distributions, just use `scale=1` (the default). Otherwise the scale
134 | parameter effectively controls the resolution of many plot types
135 | (e.g. heatmaps).
136 |
137 | `TernaryAxesSubplot` objects keep track of the scale, axes, and other
138 | parameters, supplying them as needed to other functions.
139 |
140 | ## Simplex Boundary and Gridlines
141 |
142 | The following code draws a boundary for the simplex and gridlines.
143 |
144 | ```python
145 | import ternary
146 |
147 | ## Boundary and Gridlines
148 | scale = 40
149 | figure, tax = ternary.figure(scale=scale)
150 |
151 | # Draw Boundary and Gridlines
152 | tax.boundary(linewidth=2.0)
153 | tax.gridlines(color="black", multiple=5)
154 | tax.gridlines(color="blue", multiple=1, linewidth=0.5)
155 |
156 | # Set Axis labels and Title
157 | fontsize = 20
158 | tax.set_title("Simplex Boundary and Gridlines", fontsize=fontsize)
159 | tax.left_axis_label("Left label $\\alpha^2$", fontsize=fontsize)
160 | tax.right_axis_label("Right label $\\beta^2$", fontsize=fontsize)
161 | tax.bottom_axis_label("Bottom label $\\Gamma - \\Omega$", fontsize=fontsize)
162 |
163 | # Set ticks
164 | tax.ticks(axis='lbr', linewidth=1)
165 |
166 | # Remove default Matplotlib Axes
167 | tax.clear_matplotlib_ticks()
168 |
169 | ternary.plt.show()
170 | ```
171 |
172 |
173 |
174 |
175 | ## Drawing lines
176 |
177 | You can draw individual lines between any two points with `line` and lines
178 | parallel to the axes with `horizonal_line`, `left_parallel_line`, and
179 | `right_parallel_line`:
180 |
181 | ```python
182 | import ternary
183 |
184 | scale = 40
185 | figure, tax = ternary.figure(scale=scale)
186 |
187 | # Draw Boundary and Gridlines
188 | tax.boundary(linewidth=2.0)
189 | tax.gridlines(color="blue", multiple=5)
190 |
191 | # Set Axis labels and Title
192 | fontsize = 12
193 | offset = 0.14
194 | tax.set_title("Various Lines\n", fontsize=fontsize)
195 | tax.right_corner_label("X", fontsize=fontsize)
196 | tax.top_corner_label("Y", fontsize=fontsize)
197 | tax.left_corner_label("Z", fontsize=fontsize)
198 | tax.left_axis_label("Left label $\\alpha^2$", fontsize=fontsize, offset=offset)
199 | tax.right_axis_label("Right label $\\beta^2$", fontsize=fontsize, offset=offset)
200 | tax.bottom_axis_label("Bottom label $\\Gamma - \\Omega$", fontsize=fontsize, offset=offset)
201 |
202 | # Draw lines parallel to the axes
203 | tax.horizontal_line(16)
204 | tax.left_parallel_line(10, linewidth=2., color='red', linestyle="--")
205 | tax.right_parallel_line(20, linewidth=3., color='blue')
206 |
207 | # Draw an arbitrary line, ternary will project the points for you
208 | p1 = (22, 8, 10)
209 | p2 = (2, 22, 16)
210 | tax.line(p1, p2, linewidth=3., marker='s', color='green', linestyle=":")
211 |
212 | tax.ticks(axis='lbr', multiple=5, linewidth=1, offset=0.025)
213 | tax.get_axes().axis('off')
214 | tax.clear_matplotlib_ticks()
215 | tax.show()
216 | ```
217 |
218 | The line drawing functions accept the matplotlib keyword arguments of
219 | [Line2D](http://matplotlib.org/api/lines_api.html).
220 |
221 |
222 |
223 |
224 |
225 | ## Curves
226 |
227 | Curves can be plotted by specifying the points of the curve, just like
228 | matplotlib's plot. Simply use:
229 |
230 | ```
231 | ternary.plot(points)
232 | ```
233 |
234 | Points is a list of tuples or numpy arrays, such as
235 | `[(0.5, 0.25, 0.25), (1./3, 1./3, 1./3)]`,
236 |
237 | ```python
238 | import ternary
239 |
240 | ## Sample trajectory plot
241 | figure, tax = ternary.figure(scale=1.0)
242 | tax.boundary()
243 | tax.gridlines(multiple=0.2, color="black")
244 | tax.set_title("Plotting of sample trajectory data", fontsize=20)
245 | points = []
246 | # Load some data, tuples (x,y,z)
247 | with open("sample_data/curve.txt") as handle:
248 | for line in handle:
249 | points.append(list(map(float, line.split(' '))))
250 | # Plot the data
251 | tax.plot(points, linewidth=2.0, label="Curve")
252 | tax.ticks(axis='lbr', multiple=0.2, linewidth=1, tick_formats="%.1f")
253 | tax.legend()
254 | tax.show()
255 | ```
256 |
257 |
258 |
259 |
260 |
261 | There are many more examples in [this paper](http://arxiv.org/abs/1210.5539).
262 |
263 | ## Scatter Plots
264 |
265 | Similarly, ternary can make scatter plots:
266 |
267 | ```python
268 | import ternary
269 |
270 | ### Scatter Plot
271 | scale = 40
272 | figure, tax = ternary.figure(scale=scale)
273 | tax.set_title("Scatter Plot", fontsize=20)
274 | tax.boundary(linewidth=2.0)
275 | tax.gridlines(multiple=5, color="blue")
276 | # Plot a few different styles with a legend
277 | points = random_points(30, scale=scale)
278 | tax.scatter(points, marker='s', color='red', label="Red Squares")
279 | points = random_points(30, scale=scale)
280 | tax.scatter(points, marker='D', color='green', label="Green Diamonds")
281 | tax.legend()
282 | tax.ticks(axis='lbr', linewidth=1, multiple=5)
283 |
284 | tax.show()
285 | ```
286 |
287 |
288 |
289 |
290 |
291 | ## Heatmaps
292 |
293 | Ternary can plot heatmaps in two ways and three styles. Given a function, ternary
294 | will evaluate the function at the specified number of steps (determined by the
295 | scale, expected to be an integer in this case). The simplex can be split up into
296 | triangles or hexagons and colored according to one of three styles:
297 |
298 | - Triangular -- `triangular` (default): coloring triangles by summing the values on the
299 | vertices
300 | - Dual-triangular -- `dual-triangular`: mapping (i,j,k) to the upright
301 | triangles △ and blending the neigboring triangles for the downward
302 | triangles ▽
303 | - Hexagonal -- `hexagonal`: which does not blend values at all, and divides
304 | the simplex up into hexagonal regions
305 |
306 | The two triangular heatmap styles and the hexagonal heatmap style can be visualized
307 | as follows: left is triangular, right is dual triangular.
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 | Thanks to [chebee7i](https://github.com/chebee7i) for the above images.
316 |
317 | Let's define a function on the simplex for illustration, the [Shannon entropy](http://en.wikipedia.org/wiki/Entropy_%28information_theory%29) of a probability distribution:
318 |
319 | ```python
320 | def shannon_entropy(p):
321 | """Computes the Shannon Entropy at a distribution in the simplex."""
322 | s = 0.
323 | for i in range(len(p)):
324 | try:
325 | s += p[i] * math.log(p[i])
326 | except ValueError:
327 | continue
328 | return -1.*s
329 | ```
330 |
331 | We can get a heatmap of this function as follows:
332 |
333 | ```python
334 | import ternary
335 | scale = 60
336 |
337 | figure, tax = ternary.figure(scale=scale)
338 | tax.heatmapf(shannon_entropy, boundary=True, style="triangular")
339 | tax.boundary(linewidth=2.0)
340 | tax.set_title("Shannon Entropy Heatmap")
341 |
342 | tax.show()
343 | ```
344 |
345 | In this case the keyword argument *boundary* indicates whether you wish to
346 | evaluate points on the boundary of the partition (which is sometimes
347 | undesirable). Specify `style="hexagonal"` for hexagons. Large scalings can use
348 | a lot of RAM since the number of polygons rendered is O(n^2).
349 |
350 | You may specify a [matplotlib colormap](http://matplotlib.org/examples/color/colormaps_reference.html)
351 | (an instance or the colormap name) in the cmap argument.
352 |
353 |
354 |
355 |
356 |
357 | Ternary can also make heatmaps from data. In this case you need to supply a
358 | dictionary mapping `(i, j)` or `(i, j, k)` for `i + j + k = scale` to a float
359 | as input for a heatmap. It is not necessary to include `k` in the dictionary
360 | keys since it can be determined from `scale`, `i`, and `j`. This reduces the
361 | memory requirements when the partition is very fine (significant when `scale`
362 | is in the hundreds).
363 |
364 | Make the heatmap as follows:
365 |
366 | ```python
367 | ternary.heatmap(data, scale, ax=None, cmap=None)
368 | ```
369 |
370 | or on a `TernaryAxesSubplot` object:
371 |
372 | ```python
373 | tax.heatmap(data, cmap=None)
374 | ```
375 |
376 | This can produces images such as:
377 |
378 |
379 |
380 |
381 |
382 |
383 | # Axes Ticks and Orientations
384 |
385 | For a given ternary plot there are two valid ways to label the axes ticks
386 | corresponding to the clockwise and counterclockwise orientations. However note
387 | that the axes labels need to be adjusted accordingly, and `ternary` does not
388 | do so automatically when you pass `clockwise=True` to `tax.ticks()`.
389 |
390 |
391 |
392 |
393 |
394 | There is a [more detailed discussion](https://github.com/marcharper/python-ternary/issues/18)
395 | on issue #18 (closed).
396 |
397 |
398 | # RGBA colors
399 |
400 | You can alternatively specify colors as rgba tuples `(r, g, b, a)`
401 | (all between zero and one). To use this feature, pass `colormap=False` to
402 | `heatmap()` so that the library will not attempt to map the tuple to a value
403 | with a matplotlib colormap. Note that this disables the inclusion of a colorbar.
404 | Here is an example:
405 |
406 | ```python
407 | import math
408 | from matplotlib import pyplot as plt
409 | import ternary
410 |
411 | def color_point(x, y, z, scale):
412 | w = 255
413 | x_color = x * w / float(scale)
414 | y_color = y * w / float(scale)
415 | z_color = z * w / float(scale)
416 | r = math.fabs(w - y_color) / w
417 | g = math.fabs(w - x_color) / w
418 | b = math.fabs(w - z_color) / w
419 | return (r, g, b, 1.)
420 |
421 |
422 | def generate_heatmap_data(scale=5):
423 | from ternary.helpers import simplex_iterator
424 | d = dict()
425 | for (i, j, k) in simplex_iterator(scale):
426 | d[(i, j, k)] = color_point(i, j, k, scale)
427 | return d
428 |
429 |
430 | scale = 80
431 | data = generate_heatmap_data(scale)
432 | figure, tax = ternary.figure(scale=scale)
433 | tax.heatmap(data, style="hexagonal", use_rgba=True)
434 | tax.boundary()
435 | tax.set_title("RGBA Heatmap")
436 | plt.show()
437 |
438 | ```
439 |
440 | This produces the following image:
441 |
442 |
443 |
444 |
445 |
446 | # Unittests
447 |
448 | You can run the test suite as follows:
449 |
450 | ```python
451 | python -m unittest discover tests
452 | ```
453 |
454 | # Contributing
455 |
456 | Contributions are welcome! Please share any nice example plots, contribute
457 | features, and add unit tests! Use the pull request and issue systems to
458 | contribute.
459 |
460 | # Selected Contributors
461 |
462 | - Marc Harper [marcharper](https://github.com/marcharper): maintainer
463 | - Bryan Weinstein [btweinstein](https://github.com/btweinstein): Hexagonal heatmaps, colored trajectory plots
464 | - [chebee7i](https://github.com/chebee7i): Docs and figures, triangular heatmapping
465 | - [Cory Simon](https://github.com/CorySimon): Axis Colors, colored heatmap example
466 |
467 | # Known-Issues
468 |
469 | At one point there was an issue on macs that causes the axes
470 | labels not to render. The workaround is to manually call
471 | ```
472 | tax._redraw_labels()
473 | ```
474 | before showing or rendering the image.
475 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | python-ternary is a plotting library for use with matplotlib to make ternary
2 | plots, including heatmaps.
3 |
--------------------------------------------------------------------------------
/citations.md:
--------------------------------------------------------------------------------
1 | # Citations
2 |
3 | The python-ternary library has been cited in a variety of high-quality journals and in many fields including machine learning, statistics, particle physics, cosmology, geochemistry, biology, epidemiology, and genomics. Entries are roughly in reverse chronological order. This list is likely incomplete.
4 |
5 |
6 | ## How to Cite
7 |
8 | [Citation Instructions](CITATION.md)
9 |
10 |
11 | ## Journal Articles, Conference Proceedings, and Preprints
12 | 1. Jürries, Florian, et al. [Targeted hydrolysis and decrepitation of Mn3AlC precipitates: a route to a novel precursor of rare earth free MnAl–C permanent magnets](https://iopscience.iop.org/article/10.1088/1361-6463/ace5b9/meta). Journal of Physics D: Applied Physics 56.41 (2023): 415004.
13 | 1. Merrifield, Anna Louise, et al. [Climate model Selection by Independence, Performance, and Spread (ClimSIPS) for regional applications.](https://egusphere.copernicus.org/preprints/2023/egusphere-2022-1520/) EGUsphere 2023 (2023): 1-49.
14 | 1. Harris, Elizabeth K., et al. [Influence of an industrial discharge on long-term dynamics of abiotic and biotic resources in Lavaca Bay, Texas, USA](https://link.springer.com/article/10.1007/s10661-022-10665-w). Environmental monitoring and assessment 195.1 (2023): 1-24.
15 | 1. Senanayake, Ravithree D., et al. [Machine learning-assisted carbon dot synthesis: prediction of emission color and wavelength](https://pubs.acs.org/doi/pdf/10.1021/acs.jcim.2c01007). Journal of Chemical Information and Modeling 62.23 (2022): 5918-5928
16 | 1. Ronchetti, Claudio, et al. [Machine learning techniques for data analysis in materials science](https://ieeexplore.ieee.org/abstract/document/9951839). 2022 AEIT International Annual Conference (AEIT). IEEE, 2022.
17 | 1. Huang, Chenliang, David R. Rice, and Jason H. Steffen. [MAGRATHEA: an open-source spherical symmetric planet interior structure code](https://academic.oup.com/mnras/article-abstract/513/4/5256/6574421). Monthly Notices of the Royal Astronomical Society 513.4 (2022): 5256-5269.
18 | 3. Chen, Wei-Chih, Da Yan, and Cheng-Chien Chen. [Machine Learning and First-Principles Discovery of Ternary Superhard Materials](https://pubs.acs.org/doi/abs/10.1021/bk-2022-1416.ch009). Machine Learning in Materials Informatics: Methods and Applications. American Chemical Society, 2022. 211-238.
19 | 4. Chen, Wei-Chih, Yogesh K. Vohra, and Cheng-Chien Chen. [Discovering Superhard B–N–O Compounds by Iterative Machine Learning and Evolutionary Structure Predictions](https://pubs.acs.org/doi/full/10.1021/acsomega.2c01818). ACS omega 7.24 (2022): 21035-21042.
20 | 5. Srikanth, Neha, and Rachel Rudinger. [Partial-input baselines show that NLI models can ignore context, but they don't](https://arxiv.org/abs/2205.12181). arXiv preprint arXiv:2205.12181 (2022).
21 | 6. MacDonald, Mariah G., et al. [Confirming the 3: 2 Resonance Chain of K2-138](https://iopscience.iop.org/article/10.3847/1538-3881/ac524c/meta). The Astronomical Journal 163.4 (2022): 162.
22 | 7. Ravel, Guillaume, et al. [Inferring characteristics of bacterial swimming in biofilm matrix from time-lapse confocal laser scanning microscopy](https://arxiv.org/abs/2201.04371). arXiv preprint arXiv:2201.04371 (2022).
23 | 8. Uhl, Johannes H., and Stefan Leyk. [A framework for scale-sensitive, spatially explicit accuracy assessment of binary built-up surface layers](https://arxiv.org/abs/2203.11253). arXiv preprint arXiv:2203.11253 (2022).
24 | 9. Zion, Matan Yah Ben, et al. [Cooperation in a fluid swarm of fuel-free micro-swimmers](https://www.nature.com/articles/s41467-021-27870-9) Nature communications 13.1 [arXiv preprint arXiv:2012.15087](https://arxiv.org/abs/2012.15087). (2022).
25 | 10. Ravel, Guillaume, et al. "Inferring characteristics of bacterial swimming in biofilm matrix from time-lapse confocal laser scanning microscopy." [arXiv preprint arXiv:2201.04371](https://arxiv.org/abs/2201.04371) (2022).
26 | 11. Haldemann, Jonas, et al. [Exoplanet Characterization using Conditional Invertible Neural Networks](https://arxiv.org/abs/2202.00027). arXiv preprint arXiv:2202.00027 (2022).
27 | 12. Kumar, Darshan, et al. [Constraints on the Transition Redshift using the Cosmic Triangle and Hubble Phase Space Portrait](https://www.worldscientific.com/doi/abs/10.1142/S0218271823500396). International Journal of Modern Physics D 32.06 (2023): 2350039. [arXiv:2205.13247](https://arxiv.org/abs/2205.13247) (2022).
28 | 15. Stemplinger, Simon, et al. [Theory of Ternary Fluids under Centrifugal Fields.](https://pubs.acs.org/doi/abs/10.1021/acs.jpcb.1c05875) The Journal of Physical Chemistry B 125.43 (2021): 12054-12062.
29 | 16. Fatras, Kilian, et al. "Minibatch optimal transport distances; analysis and applications." [arXiv preprint arXiv:2101.01792](https://arxiv.org/abs/2101.01792) (2021).
30 | 17. Kim, Minjae, Jung-Kyoo Choi, and Seung Ki Baek. [Win-Stay-Lose-Shift as a self-confirming equilibrium in the iterated Prisoner’s Dilemma.](https://royalsocietypublishing.org/doi/full/10.1098/rspb.2021.1021) Proceedings of the Royal Society B 288.1953 (2021): 20211021.
31 | 18. Nanba, Yusuke, and Michihisa Koyama. [Thermodynamic Stabilities of PdRuM (M= Cu, Rh, Ir, Au) Alloy Nanoparticles Assessed by Wang–Landau Sampling Combined with DFT Calculations and Multiple Regression Analysis.](https://www.journal.csj.jp/doi/abs/10.1246/bcsj.20210199) Bulletin of the Chemical Society of Japan 94.10 (2021): 2484-2492.
32 | 19. Maturana, Carola J., et al. [Novel tool to quantify with single-cell resolution the number of incoming AAV genomes co-expressed in the mouse nervous system.](https://www.nature.com/articles/s41434-021-00272-8) Gene Therapy (2021): 1-6.
33 | 20. Chen, Wei-Chih, et al. [Machine learning and evolutionary prediction of superhard BCN compounds](https://www.nature.com/articles/s41524-021-00585-7). Nature npj Computational Materials 7.1 (2021): 1-8. (2021)
34 | 21. Nolan, Adelaide M., Eric D. Wachsman, and Yifei Mo. [Computation-guided discovery of coating materials to stabilize the interface between lithium garnet solid electrolyte and high-energy cathodes for all-solid-state lithium batteries](https://www.sciencedirect.com/science/article/abs/pii/S2405829721002932). Energy Storage Materials 41 (2021): 571-580.
35 | 22. Tönsmann, Max, et al. [Surface tension of binary and ternary polymer solutions: Experimental data of poly(vinyl acetate), poly(vinyl alcohol) and polyethylene glycol solutions and mixing rule evaluation over the entire concentration range](https://www.sciencedirect.com/science/article/pii/S2468023021004296) Surfaces and Interfaces 26 (2021).
36 | 23. Maturana, Carola J., et al. [Novel tool to quantify with single-cell resolution the number of incoming AAV genomes co-expressed in the mouse nervous system.](https://www.nature.com/articles/s41434-021-00272-8) Gene Therapy (2021): 1-6.
37 | 24. Bechtold, Andreas, et al. [Lunar meteorite Northwest Africa 11962: A regolith breccia containing records of titanium‐rich lunar volcanism and the high alkali suite](https://onlinelibrary.wiley.com/doi/abs/10.1111/maps.13659). Meteoritics & Planetary Science (2021). [(open pdf)](http://oro.open.ac.uk/75904/1/maps.13659.pdf)
38 | 25. Asai, Kento, Takeo Moroi, and Atsuya Niki. [Leptophilic gauge bosons at ILC beam dump experiment](https://www.sciencedirect.com/science/article/pii/S0370269321003142). Physics Letters B (2021): 136374. [ArXiv](https://arxiv.org/abs/2104.00888)
39 | 26. Chung, Wesley, et al. [Beyond variance reduction: Understanding the true impact of baselines on policy optimization](http://proceedings.mlr.press/v139/chung21a.html). International Conference on Machine Learning. PMLR, 2021. [arXiv:2008.13773](https://arxiv.org/abs/2008.13773)
40 | 27. Hao, Weiduo, et al. [The kaolinite shuttle links the Great Oxidation and Lomagundi events](https://doi.org/10.1038/s41467-021-23304-8). Nature Communications 12 (2021): 2944.
41 | 28. Mikhail, Sami, et al. [A genetic metasomatic link between eclogitic and peridotitic diamond inclusions](https://research-repository.st-andrews.ac.uk/handle/10023/21754). Geochemical Perspectives Letters (2021).
42 | 29. Donchev, Alexander G., et al. [Quantum chemical benchmark databases of gold-standard dimer interaction energies](https://www.nature.com/articles/s41597-021-00833-x). [Nature] Scientific data 8.1 (2021): 1-9.
43 | 30. Wang, Fengfan, et al. [Study on offshore seabed sediment classification based on particle size parameters using XGBoost algorithm](https://www.sciencedirect.com/science/article/pii/S0098300421000273). Computers & Geosciences 149 (2021): 104713.
44 | 31. Felkl, Tobias, Juan Herrero-Garcia, and Michael A. Schmidt. [The Singly-Charged Scalar Singlet as the Origin of Neutrino Masses](https://link.springer.com/article/10.1007/JHEP05(2021)122). Journal of High Energy Physics 2021.5 (2021): 1-39; arXiv preprint [arXiv:2102.09898](https://arxiv.org/abs/2102.09898) (2021).
45 | 32. Busnelli, Marco, et al. [Aortic Gene Expression Profiles Show How ApoA-I Levels Modulate Inflammation, Lysosomal Activity, and Sphingolipid Metabolism in Murine Atherosclerosis](https://www.ahajournals.org/doi/abs/10.1161/ATVBAHA.120.315669). Arteriosclerosis, Thrombosis, and Vascular Biology 41.2 (2021): 651-667.
46 | 33. Fink, Christoph, et al. "Mapping the online songbird trade in Indonesia." Applied Geography 134 (2021): 102505. [SocArxiv](https://osf.io/preprints/socarxiv/mxkgq/).
47 | 34. Molter, Felix, et al. [Gaze-dependent evidence accumulation predicts multi-alternative risky choice behaviour](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1010283) [psyarxiv](https://psyarxiv.com/x6nbf/download/?format=pdf). PsyArXiv. February 12 (2021).
48 | 35. Karkaria, Behzad D., Alex JH Fedorec, and Chris P. Barnes. [Automated design of synthetic microbial communities](https://www.nature.com/articles/s41467-020-20756-2). Nature communications 12.1 (2021): 1-12. [BioRxiv](https://www.biorxiv.org/content/10.1101/2020.06.30.180281v1.abstract).
49 | 36. Fatras, Kilian, et al. [Minibatch optimal transport distances; analysis and applications](https://arxiv.org/abs/2101.01792). arXiv preprint arXiv:2101.01792 (2021).
50 | 37. Tran, Xuan Quy, et al. [Statistical Evaluation of the Solid-Solution State in Ternary Nanoalloys.](https://pubs.acs.org/doi/abs/10.1021/acs.jpcc.0c06813) The Journal of Physical Chemistry C 124.39 (2020): 21843-21852.
51 | 38. Evans, Matthew L., and Andrew J. Morris. [matador: a Python library for analysing, curating and performing high-throughput density-functional theory calculations](https://joss.theoj.org/papers/10.21105/joss.02563.pdf). Journal of Open Source Software 5.54 (2020): 2563.
52 | 39. Liu, Shiyu, et al. [Quantitative analysis of the physiological contributions of glucose to the TCA cycle](https://www.sciencedirect.com/science/article/abs/pii/S1550413120304836). Cell Metabolism 32.4 (2020): 619-628.
53 | 40. Graziani, Carlo. [A Behavioral Multispread Epidemic Model](https://www.medrxiv.org/content/10.1101/2020.08.24.20181107v1.abstract). medRxiv (2020).
54 | 41. Tran, Xuan Quy, et al. [Statistical evaluation of the solid-solution state in ternary nanoalloys](https://pubs.acs.org/doi/abs/10.1021/acs.jpcc.0c06813). The Journal of Physical Chemistry C (2020).
55 | 42. McNally, Joshua S., et al. [Solute displacement in the aqueous phase of water–NaCl–organic ternary mixtures relevant to solvent-driven water treatment](https://pubs.rsc.org/en/content/articlelanding/2020/RA/D0RA06361D) RSC Advances 10.49 (2020)
56 | 43. Marc Harper and Joshua Safyan. [Momentum Accelerates Evolutionary Dynamics](https://arxiv.org/abs/2007.02449). ArXiv preprint. (2020)
57 | 44. Broquet, A., Mark A. Wieczorek, and Wenzhe Fa. [Flexure of the lithosphere beneath the north polar cap of Mars: Implications for ice composition and heat flow](https://agupubs.onlinelibrary.wiley.com/doi/epdf/10.1029/2019GL086746). Geophysical Research Letters (2020).
58 | 45. Choubisa, Hitarth, et al. [Crystal Site Feature Embedding Enables Exploration of Large Chemical Spaces](https://www.sciencedirect.com/science/article/pii/S2590238520301879). Matter (2020).
59 | 46. Daly, Clyde A., and Rigoberto Hernandez. [Learning from the Machine: Uncovering Sustainable Nanoparticle Design Rules.](https://pubs.acs.org/doi/abs/10.1021/acs.jpcc.0c01195) The Journal of Physical Chemistry C (2020).
60 | 47. Qian, Jimmy J., and Erol Akçay. [The balance of interaction types determines the assembly and stability of ecological communities](https://www.nature.com/articles/s41559-020-1121-x). Nature Ecology & Evolution 4.3 (2020): 356-365. [BioRxiv](https://www.biorxiv.org/content/10.1101/643478v1.full)
61 | 48. Bucalo, Maria Soledad, et al. [A Constellation of Horrors: Analysis and Visualization of the #Cuéntalo Movement.](https://dl.acm.org/doi/abs/10.1145/3308560.3316459) Companion Proceedings of The 2019 World Wide Web Conference. 2019.
62 | 49. Ke, Huibin, and Christopher D. Taylor. [Design of Corrosion Resistant Alloys Using Density Functional Theory: Part I. O and Cl Adsorption Energy](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3491237). O and Cl Adsorption Energy (November 27, 2019) (2019).
63 | 50. Choi, Kwangbom, Narayanan Raghupathy, and Gary A. Churchill. [scBASE: A Bayesian mixture model for the analysis of allelic expression in single cells.](https://www.nature.com/articles/s41467-019-13099-0) Nature Communications 10.1 (2019): 1-1. [bioRxiv](https://www.biorxiv.org/content/10.1101/383224v3.full) (2019): 383224.
64 | 51. Campbell, Ian Jackson, George Nelson Bennett, and Jonathan J. Silberg. [Evolutionary relationships between low potential ferredoxin and flavodoxin electron carriers.](https://www.frontiersin.org/articles/10.3389/fenrg.2019.00079/full) Frontiers in Energy Research 7 (2019): 79.
65 | 52. Bragman, Felix JS, et al. [Stochastic Filter Groups for Multi-Task CNNs: Learning Specialist and Generalist Convolution Kernels](http://openaccess.thecvf.com/content_ICCV_2019/html/Bragman_Stochastic_Filter_Groups_for_Multi-Task_CNNs_Learning_Specialist_and_Generalist_ICCV_2019_paper.html). Proceedings of the IEEE International Conference on Computer Vision. [arXiv:1908.09597](https://arxiv.org/abs/1908.09597) (2019).
66 | 53. Nelson, James, and Stefano Sanvito. [Predicting the Curie temperature of ferromagnets using machine learning](https://journals.aps.org/prmaterials/abstract/10.1103/PhysRevMaterials.3.104405). Phys. Rev. Materials 3, 104405 (2019) [arXiv:1906.08534](https://arxiv.org/abs/1906.08534)
67 | 54. Kirchner, Philipp, et al. [Proteome-wide analysis of chaperone-mediated autophagy targeting motifs.](https://journals.plos.org/plosbiology/article?id=10.1371/journal.pbio.3000301) PLoS biology 17.5 (2019): e3000301.
68 | 55. Gariazzo, S., P. F. de Salas, and S. Pastor Carpi. [Thermalisation of sterile neutrinos in the early Universe in the 3+ 1 scheme with full mixing matrix](https://iopscience.iop.org/article/10.1088/1475-7516/2019/07/014). Journal of Cosmology and Astroparticle Physics, Volume 2019, July 2019. [arXiv:1905.11290](https://arxiv.org/abs/1905.11290) (2019).
69 | 56. Keniley, Shane, and Davide Curreli. "CRANE: A MOOSE-based Open Source Tool for Plasma Chemistry Applications." [arXiv:1905.10004](https://arxiv.org/abs/1905.10004) (2019).
70 | 57. Abada, Asmaa, et al. [Inclusive displaced vertex searches for heavy neutral leptons at the LHC.](https://link.springer.com/article/10.1007/JHEP01(2019)093) Journal of High Energy Physics 2019.1 (2019): 93. [ArXiv](https://arxiv.org/abs/1807.10024).
71 | 58. Bustamante, Mauricio, and Sanjib Kumar Agarwalla. [Universe’s Worth of Electrons to Probe Long-Range Interactions of High-Energy Astrophysical Neutrinos.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.122.061103) Physical review letters 122.6 (2019): 061103. [ArXiv](https://arxiv.org/abs/1808.02042).
72 | 59. Hamilton, Nicholas E., and Michael Ferry. [ggtern: Ternary diagrams using ggplot2](https://www.jstatsoft.org/article/view/v087c03). Journal of Statistical Software 87.1 (2018): 1-17.
73 | 60. Makha, Mohammed, et al. [Insights into photovoltaic properties of ternary organic solar cells from phase diagrams](https://www.tandfonline.com/doi/abs/10.1080/14686996.2018.1509275). Science and Technology of Advanced Materials 19.1 (2018): 669-682.
74 | 61. Marc Harper and Dashiell Fryer. [Entropic Equilibria Selection of Stationary Extrema in Finite Populations](https://doi.org/10.3390/e20090631). Entropy 2018, 20(9), 631.
75 | 62. Profe, Jörn, et al. [Paleoenvironmental conditions and sedimentation dynamics in Central Europe inferred from geochemical data of the loess-paleosol sequence at Süttő (Hungary)](https://www.sciencedirect.com/science/article/pii/S027737911730834X). Quaternary Science Reviews 196 (2018): 21-37.
76 | 63. Ou, Longwen, et al. [Understanding the impacts of biomass blending on the uncertainty of hydrolyzed sugar yield from a stochastic perspective.](https://pubs.acs.org/doi/full/10.1021/acssuschemeng.8b02150#showReferences). Ou, Longwen, et al. ACS Sustainable Chemistry & Engineering (2018).
77 | 64. Nyberg, Björn, Casey W. Nixon, and David J. Sanderson. [NetworkGT: A GIS tool for geometric and topological analysis of two-dimensional fracture networks](https://pubs.geoscienceworld.org/gsa/geosphere/article/14/4/1618/531129/networkgt-a-gis-tool-for-geometric-and-topological). Geosphere (2018).
78 | 65. Fang Ren, Logan Ward, Travis Williams, Kevin J. Laws, Christopher Wolverton, Jason Hattrick-Simpers and Apurva Mehta. [Accelerated discovery of metallic glasses through iteration of machine learning and high-throughput experiments](http://advances.sciencemag.org/content/4/4/eaaq1566.full). Science Advances: Vol. 4, no. 4. (2018) DOI: 10.1126/sciadv.aaq1566
79 | 66. Pauly, Tyler, and Robin T. Garrod. [Modeling CO, CO2, and H2O Ice Abundances in the Envelopes of Young Stellar Objects in the Magellanic Clouds](http://iopscience.iop.org/article/10.3847/1538-4357/aaa96a/meta). The Astrophysical Journal, 854.1 (2018): 13.
80 | 67. Gotzias, A., Kainourgiakis, M. & Stubos. [Enhanced CO2 selectivity within the cavity of gmelinite frameworks](https://link.springer.com/article/10.1007%2Fs10450-018-9945-2). A. Adsorption (2018). https://doi.org/10.1007/s10450-018-9945-2
81 | 68. Maxim O. Lavrentovich, Wolfram Möbius, Andrew W. Murray, and David R. Nelson. [Genetic Drift and Selection in Many-Allele Range Expansions](http://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1005866). [Bryan T. Weinstein](https://github.com/btweinstein), PLoS computational biology 13.12 (2017): e1005866. (2017)
82 | 69. Xinqiang Ding, Jonah Z. Vilseck, Ryan L. Hayes, and Charles L. Brooks. [Gibbs Sampler-Based λ-Dynamics and Rao–Blackwell Estimator for Alchemical Free Energy Calculation](http://pubs.acs.org/doi/abs/10.1021/acs.jctc.7b00204?src=recsys&journalCode=jctcce). Journal of Chemical Theory and Computation. (2017)
83 | 70. Timothy J Durham, Maxwell W Libbrecht, Jeffry Howbert, Jeffrey Bilmes, William S Noble. [PREDICTD: PaRallel Epigenomics Data Imputation With Cloud-based Tensor Decomposition](http://biorxiv.org/content/early/2017/04/04/123927). Nature Communications, doi: 10.1038/s41467-018-03635-9 (2017)
84 | 71. Kottke, Daniel, et al. [Multi-class probabilistic active learning](http://ebooks.iospress.nl/publication/44803) Proc. of the 22nd Europ. Conf. on Artificial Intelligence (ECAI2016). 2016.
85 | 72. Joshua Meyers, Michael Carter, N Yi Mok, and Nathan Brown. [On the origins of three-dimensionality in drug-like molecules](http://www.future-science.com/doi/full/10.4155/fmc-2016-0095). Future Medicinal Chemistry, Vol. 8, No. 14 (2016)
86 | 73. Marc Harper and Dashiell Fryer. [Stationary Stability for Evolutionary Dynamics in Finite Populations](http://www.mdpi.com/1099-4300/18/9/316/htm). Entropy 18.9 (2016): 316.
87 | 74. Cory Simon. [pyIAST: Ideal adsorbed solution theory (IAST) Python package](http://www.sciencedirect.com/science/article/pii/S0010465515004403). Computer Physics Communications (2016)
88 | 75. Marc Harper and Dashiell Fryer. [Lyapunov Functions for Time-Scale Dynamics on Riemannian Geometries of the Simplex](https://link.springer.com/article/10.1007/s13235-014-0124-0). Dynamic Games and Applications (2015)
89 |
90 | ## Dissertations
91 | 1. Rice, David R. [Inferring the Compositions and Interior Structures of Small Planets](https://www.proquest.com/openview/f7504fbe891d2ec3a7673d4e2a1122c4/1?pq-origsite=gscholar&cbl=18750&diss=y). Diss. University of Nevada, Las Vegas, 2023.
92 | 1. Störiko, Anna. [Integrating Molecular-Biological Data and Process-Based Models of Nitrogen Cycling](https://tobias-lib.ub.uni-tuebingen.de/xmlui/handle/10900/135233). Doctoral Dissertation. (2022).
93 | 1. Levo, Emil. [Radiation Damage in High Entropy Alloys.](https://helda.helsinki.fi/handle/10138/337574). Doctoral Dissertation. (2022).
94 | 1. Nikolaev, Fedor. [Incorporating Word Dependencies Into Structured Document Retrieval Models](https://search.proquest.com/openview/94faf009d9ce22f3634b2bc29ebb02b6/1?pq-origsite=gscholar&cbl=18750&diss=y). Wayne State University, 2021.
95 | 1. Fatras, Kilian. [Deep learning and optimal transport: learning from one another](https://www.theses.fr/2021LORIS604) Diss. Lorient, 2021.
96 | 2. Chen, Wei-Chih. [Predictive Modeling of Superhard and Topological Materials by Density Functional Theory and Machine Learning](https://search.proquest.com/openview/85c7c0efd61123b8843fa3f3a34b0de1/1?pq-origsite=gscholar&cbl=18750&diss=y). Diss. The University of Alabama at Birmingham, 2021.
97 | 3. Lacour-Gogny-Goubert, Antoine. [Développement et étude d’alliages réfractaires complexes, à microstructure cubique centrée et orthorhombique, pour des applications aéronautiques.](https://hal.archives-ouvertes.fr/tel-03552645/) Diss. Université Paris-Est, 2020.
98 | 4. Durham, Timothy. [Toward comprehensive characterization of chromatin state](https://digital.lib.washington.edu/researchworks/handle/1773/44274). 2019.
99 | 5. Cremer, Pascal. [Algorithms for Cell Layout](http://hss.ulb.uni-bonn.de/2019/5428/5428.pdf). PhD Dissertation. Universitäts-und Landesbibliothek Bonn, 2019.
100 | 6. Ding, Xinqiang. [Methodological Advances for Drug Discovery and Protein Engineering](https://deepblue.lib.umich.edu/handle/2027.42/147634). 2018.
101 | 7. Weinstein, Bryan T. [Microbial Evolutionary Dynamics and Transport on Solid and Liquid Substrates](https://dash.harvard.edu/handle/1/40050028). Diss. 2018.
102 | 8. Triller, Thomas. [Diffusive properties of the system water/ethanol/triethylene glycol in microgravity and ground conditions](https://d-nb.info/1168324432/34). (Disseration, 2018)
103 | 9. Rueda Corredor, Henry Steven. [Desarrollo e implementación de un software que permita visualizar y procesar los datos de rayos X de microsonda para análisis petrológicos, mineralógicos y geoquímicos.](https://repositorio.uniandes.edu.co/bitstream/handle/1992/17924/u729475.pdf?sequence=1) (2016).
104 |
--------------------------------------------------------------------------------
/examples/Scatter_plot_colorbar.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/examples/Scatter_plot_colorbar.pdf
--------------------------------------------------------------------------------
/examples/color_coded_heatmap.py:
--------------------------------------------------------------------------------
1 | import ternary
2 | import matplotlib.pyplot as plt
3 |
4 |
5 | # Function to visualize for heat map
6 | def f(x):
7 | return 1.0 * x[0] / (1.0 * x[0] + 0.2 * x[1] + 0.05 * x[2])
8 |
9 | # Dictionary of axes colors for bottom (b), left (l), right (r).
10 | axes_colors = {'b': 'g', 'l': 'r', 'r': 'b'}
11 |
12 | scale = 10
13 |
14 | fig, ax = plt.subplots()
15 | ax.axis("off")
16 | figure, tax = ternary.figure(ax=ax, scale=scale)
17 |
18 | tax.heatmapf(f, boundary=False,
19 | style="hexagonal", cmap=plt.cm.get_cmap('Blues'),
20 | cbarlabel='Component 0 uptake',
21 | vmax=1.0, vmin=0.0)
22 |
23 | tax.boundary(linewidth=2.0, axes_colors=axes_colors)
24 |
25 | tax.left_axis_label("$x_1$", offset=0.16, color=axes_colors['l'])
26 | tax.right_axis_label("$x_0$", offset=0.16, color=axes_colors['r'])
27 | tax.bottom_axis_label("$x_2$", offset=0.06, color=axes_colors['b'])
28 |
29 | tax.gridlines(multiple=1, linewidth=2,
30 | horizontal_kwargs={'color': axes_colors['b']},
31 | left_kwargs={'color': axes_colors['l']},
32 | right_kwargs={'color': axes_colors['r']},
33 | alpha=0.7)
34 |
35 | # Set and format axes ticks.
36 | ticks = [i / float(scale) for i in range(scale+1)]
37 | tax.ticks(ticks=ticks, axis='rlb', linewidth=1, clockwise=True,
38 | axes_colors=axes_colors, offset=0.03, tick_formats="%0.1f")
39 |
40 | tax.clear_matplotlib_ticks()
41 | tax._redraw_labels()
42 | plt.tight_layout()
43 | tax.show()
44 |
--------------------------------------------------------------------------------
/examples/colorbar_kwargs.py:
--------------------------------------------------------------------------------
1 | import ternary
2 |
3 | ## Boundary and Gridlines
4 | scale = 9
5 | figure, tax = ternary.figure(scale=scale)
6 | tax.ax.axis("off")
7 | figure.set_facecolor('w')
8 |
9 | # Draw Boundary and Gridlines
10 | tax.boundary(linewidth=1.0)
11 | tax.gridlines(color="black", multiple=1, linewidth=0.5,ls='-')
12 |
13 | # Set Axis labels and Title
14 | fontsize = 15
15 | tax.left_axis_label("Barleygrow", fontsize=fontsize, offset=0.12)
16 | tax.right_axis_label("Beans", fontsize=fontsize, offset=0.12)
17 | tax.bottom_axis_label("Oats", fontsize=fontsize, offset=0.025)
18 |
19 | # Set ticks
20 | tax.ticks(axis='blr', linewidth=1,multiple=1)
21 |
22 |
23 |
24 | # Scatter some points
25 | points = [(2,3,5),(3,6,1),(5,4,1),(3,4,3),(2,2,6)]
26 | c = [90,20,30,10,64]
27 |
28 | cb_kwargs = {"shrink" : 0.6,
29 | "orientation" : "horizontal",
30 | "fraction" : 0.1,
31 | "pad" : 0.05,
32 | "aspect" : 30}
33 |
34 | tax.scatter(points,marker='s',c=c,edgecolor='k',s=40,linewidths=0.5,
35 | vmin=0,vmax=100,colorbar=True,colormap='jet',cbarlabel='Farmers',
36 | cb_kwargs=cb_kwargs,zorder=3)
37 |
38 |
39 | tax._redraw_labels()
40 |
41 | # Color coded heatmap example with colorbar kwargs
42 | # Slight modification so that we don't have to re-import pyplot
43 | # but make use of ternary.plt
44 |
45 |
46 | # Function to visualize for heat map
47 | def f(x):
48 | return 1.0 * x[0] / (1.0 * x[0] + 0.2 * x[1] + 0.05 * x[2])
49 |
50 | # dictionary of axes colors for bottom (b), left (l), right (r)
51 | axes_colors = {'b': 'g', 'l': 'r', 'r':'b'}
52 |
53 | scale = 10
54 |
55 | figure, tax = ternary.figure(scale=scale)
56 | tax.ax.axis("off")
57 | cb_kwargs = {"shrink" : 0.6,
58 | "pad" : 0.05,
59 | "aspect" : 30,
60 | "orientation" : "horizontal"}
61 |
62 | tax.heatmapf(f, boundary=False,
63 | style="hexagonal", cmap=ternary.plt.cm.get_cmap('Blues'),
64 | cbarlabel='Component 0 uptake',
65 | vmax=1.0, vmin=0.0, cb_kwargs=cb_kwargs)
66 |
67 | tax.boundary(linewidth=2.0, axes_colors=axes_colors)
68 |
69 | tax.left_axis_label("$x_1$", offset=0.16, color=axes_colors['l'])
70 | tax.right_axis_label("$x_0$", offset=0.16, color=axes_colors['r'])
71 | tax.bottom_axis_label("$x_2$", offset=-0.06, color=axes_colors['b'])
72 |
73 | tax.gridlines(multiple=1, linewidth=2,
74 | horizontal_kwargs={'color':axes_colors['b']},
75 | left_kwargs={'color':axes_colors['l']},
76 | right_kwargs={'color':axes_colors['r']},
77 | alpha=0.7)
78 |
79 | ticks = [round(i / float(scale), 1) for i in range(scale+1)]
80 | tax.ticks(ticks=ticks, axis='rlb', linewidth=1, clockwise=True,
81 | axes_colors=axes_colors, offset=0.03)
82 |
83 | tax.clear_matplotlib_ticks()
84 | tax._redraw_labels()
85 | ternary.plt.tight_layout()
86 | ternary.plt.show()
87 |
--------------------------------------------------------------------------------
/examples/custom_axis_scaling.py:
--------------------------------------------------------------------------------
1 | import ternary
2 |
3 | # Simple example:
4 | ## Boundary and Gridlines
5 | scale = 9
6 | figure, tax = ternary.figure(scale=scale)
7 |
8 | tax.ax.axis("off")
9 | figure.set_facecolor('w')
10 |
11 | # Draw Boundary and Gridlines
12 | tax.boundary(linewidth=1.0)
13 | tax.gridlines(color="black", multiple=1, linewidth=0.5, ls='-')
14 |
15 | # Set Axis labels and Title
16 | fontsize = 16
17 | tax.left_axis_label("Logs", fontsize=fontsize, offset=0.13)
18 | tax.right_axis_label("Dogs", fontsize=fontsize, offset=0.12)
19 | tax.bottom_axis_label("Hogs", fontsize=fontsize, offset=0.06)
20 |
21 |
22 | # Set custom axis limits by passing a dict into set_limits.
23 | # The keys are b, l and r for the three axes and the vals are a list
24 | # of the min and max in data coords for that axis. max-min for each
25 | # axis must be the same as the scale i.e. 9 in this case.
26 | tax.set_axis_limits({'b': [67, 76], 'l': [24, 33], 'r': [0, 9]})
27 | # get and set the custom ticks:
28 | tax.get_ticks_from_axis_limits()
29 | tax.set_custom_ticks(fontsize=10, offset=0.02)
30 |
31 | # data can be plotted by entering data coords (rather than simplex coords):
32 | points = [(70, 3, 27), (73, 2, 25), (68, 6, 26)]
33 | points_c = tax.convert_coordinates(points,axisorder='brl')
34 | tax.scatter(points_c, marker='o', s=25, c='r')
35 |
36 | tax.ax.set_aspect('equal', adjustable='box')
37 | tax._redraw_labels()
38 |
39 |
40 | ## Simple example with axis tick formatting:
41 | ## Boundary and Gridlines
42 | scale = 9
43 | figure, tax = ternary.figure(scale=scale)
44 |
45 | tax.ax.axis("off")
46 | figure.set_facecolor('w')
47 |
48 | # Draw Boundary and Gridlines
49 | tax.boundary(linewidth=1.0)
50 | tax.gridlines(color="black", multiple=1, linewidth=0.5, ls='-')
51 |
52 | # Set Axis labels and Title
53 | fontsize = 16
54 | tax.left_axis_label("Logs", fontsize=fontsize, offset=0.13)
55 | tax.right_axis_label("Dogs", fontsize=fontsize, offset=0.12)
56 | tax.bottom_axis_label("Hogs", fontsize=fontsize, offset=0.06)
57 |
58 |
59 | # Set custom axis limits by passing a dict into set_limits.
60 | # The keys are b, l and r for the three axes and the vals are a list
61 | # of the min and max in data coords for that axis. max-min for each
62 | # axis must be the same as the scale i.e. 9 in this case.
63 | tax.set_axis_limits({'b': [67, 76], 'l': [24, 33], 'r': [0, 9]})
64 | # get and set the custom ticks:
65 | # custom tick formats:
66 | # tick_formats can either be a dict, like below or a single format string
67 | # e.g. "%.3e" (valid for all 3 axes) or None, in which case, ints are
68 | # plotted for all 3 axes.
69 | tick_formats = {'b': "%.2f", 'r': "%d", 'l': "%.1f"}
70 |
71 | tax.get_ticks_from_axis_limits()
72 | tax.set_custom_ticks(fontsize=10, offset=0.02, tick_formats=tick_formats)
73 |
74 | # data can be plotted by entering data coords (rather than simplex coords):
75 | points = [(70, 3, 27), (73, 2, 25), (68, 6, 26)]
76 | points_c = tax.convert_coordinates(points,axisorder='brl')
77 | tax.scatter(points_c, marker='o', s=25, c='r')
78 |
79 | tax.ax.set_aspect('equal', adjustable='box')
80 | tax._redraw_labels()
81 |
82 | ## Zoom example:
83 | ## Draw a plot with the full range on the left and a second plot which
84 | ## shows a zoomed region of the left plot.
85 | fig = ternary.plt.figure(figsize=(11, 6))
86 | ax1 = fig.add_subplot(2, 1, 1)
87 | ax2 = fig.add_subplot(2, 1, 2)
88 |
89 | tax1 = ternary.TernaryAxesSubplot(ax=ax1, scale=100)
90 | tax1.boundary(linewidth=1.0)
91 | tax1.gridlines(color="black", multiple=10, linewidth=0.5, ls='-')
92 | tax1.ax.axis("equal")
93 | tax1.ax.axis("off")
94 |
95 | tax2 = ternary.TernaryAxesSubplot(ax=ax2,scale=30)
96 | axes_colors = {'b': 'r', 'r': 'r', 'l': 'r'}
97 | tax2.boundary(linewidth=1.0, axes_colors=axes_colors)
98 | tax2.gridlines(color="r", multiple=5, linewidth=0.5, ls='-')
99 | tax2.ax.axis("equal")
100 | tax2.ax.axis("off")
101 |
102 | fontsize = 16
103 | tax1.set_title("Entire range")
104 | tax1.left_axis_label("Logs", fontsize=fontsize, offset=0.12)
105 | tax1.right_axis_label("Dogs", fontsize=fontsize, offset=0.12)
106 | tax1.bottom_axis_label("Hogs", fontsize=fontsize, offset=0.)
107 | tax2.set_title("Zoomed region",color='r')
108 | tax2.left_axis_label("Logs", fontsize=fontsize, offset=0.17, color='r')
109 | tax2.right_axis_label("Dogs", fontsize=fontsize, offset=0.17, color='r')
110 | tax2.bottom_axis_label("Hogs", fontsize=fontsize, offset=0.03, color='r')
111 |
112 | tax1.ticks(multiple=10,offset=0.02)
113 |
114 | tax2.set_axis_limits({'b': [60, 75], 'l': [15, 30], 'r': [10, 25]})
115 | tax2.get_ticks_from_axis_limits(multiple=5)
116 | tick_formats = "%.1f"
117 | tax2.set_custom_ticks(fontsize=10, offset=0.025, multiple=5,
118 | axes_colors=axes_colors, tick_formats=tick_formats)
119 |
120 | # plot some data
121 | points = [(62, 12, 26), (63.5, 13.5, 23), (65, 14, 21), (61, 15, 24),
122 | (62, 16, 22), (67.5, 14.5, 18), (68.2, 16.5, 15.3), (62, 22.5, 15.5)]
123 |
124 | # data coords == simplex coords:
125 | tax1.scatter(points, marker='^', s=25, c='b')
126 | # data coords != simplex coords:
127 | points_c = tax2.convert_coordinates(points, axisorder='brl')
128 | tax2.scatter(points_c, marker='^', s=25, c='b')
129 |
130 | # draw the zoom region on the first plot
131 | tax1.line((60, 10, 30), (75, 10, 15), color='r', lw=2.0)
132 | tax1.line((60, 10, 30), (60, 25, 15), color='r', lw=2.0)
133 | tax1.line((75, 10, 15), (60, 25, 15), color='r', lw=2.0)
134 |
135 | fig.set_facecolor("w")
136 |
137 | tax1.ax.set_position([0.01, 0.05, 0.46, 0.8])
138 | tax2.ax.set_position([0.50, 0.05, 0.46, 0.8])
139 |
140 | tax1.resize_drawing_canvas()
141 | tax2.resize_drawing_canvas()
142 | ternary.plt.show()
143 |
--------------------------------------------------------------------------------
/examples/sample_data/sample_heatmap_data.txt:
--------------------------------------------------------------------------------
1 | 24 9 27 0.000576293331224
2 | 15 27 18 0.000597312322493
3 | 1 59 0 0.000518034490428
4 | 21 3 36 0.000538706957448
5 | 26 2 32 0.000588226360032
6 | 28 10 22 0.00057788496369
7 | 5 38 17 0.000498688979294
8 | 20 10 30 0.000567932192157
9 | 11 40 9 0.000465294284403
10 | 7 29 24 0.000563439276973
11 | 15 33 12 0.000546726531298
12 | 29 26 5 0.000561048821157
13 | 10 11 39 0.000477498435273
14 | 2 33 25 0.000583686849508
15 | 2 42 16 0.000495347908903
16 | 31 27 2 0.000591497111978
17 | 30 11 19 0.00057059401282
18 | 9 22 29 0.000569998719715
19 | 5 15 40 0.000475193799381
20 | 24 30 6 0.000558212941977
21 | 8 4 48 0.000379415766803
22 | 14 26 20 0.000599917880717
23 | 36 15 9 0.000513508110547
24 | 20 32 8 0.000550001670772
25 | 27 8 25 0.000571548093182
26 | 3 19 38 0.00051918527119
27 | 7 38 15 0.000492102347195
28 | 4 53 3 0.000339990113993
29 | 8 16 36 0.000513625240855
30 | 4 28 28 0.000564695427811
31 | 22 20 18 0.000618232740386
32 | 4 27 29 0.000564064666008
33 | 4 54 2 0.000345614053259
34 | 19 28 13 0.000587904261256
35 | 23 27 10 0.000581049081881
36 | 2 55 3 0.000343377513917
37 | 2 32 26 0.000588226360032
38 | 13 1 46 0.00048585847447
39 | 21 14 25 0.000603091017132
40 | 41 14 5 0.000462688733129
41 | 10 34 16 0.000535133560842
42 | 28 29 3 0.000573094946374
43 | 11 12 37 0.000501914704779
44 | 24 29 7 0.000563439276973
45 | 43 15 2 0.000481793851003
46 | 10 30 20 0.000567932192157
47 | 15 25 20 0.000606046935916
48 | 18 11 31 0.000563350221647
49 | 29 8 23 0.000566517703157
50 | 17 8 35 0.000524024255459
51 | 6 25 29 0.000561326032631
52 | 9 37 14 0.000502091716183
53 | 37 11 12 0.000501914704779
54 | 2 46 12 0.000439466945027
55 | 57 0 3 0.000472067807554
56 | 8 27 25 0.000571548093182
57 | 29 28 3 0.000573094946374
58 | 17 23 20 0.00061527433194
59 | 1 5 54 0.000376584228843
60 | 16 25 19 0.000608054593057
61 | 31 25 4 0.000559052024715
62 | 11 49 0 0.000577577412196
63 | 11 6 43 0.000432035856162
64 | 5 8 47 0.000385449128184
65 | 25 5 30 0.000558551095357
66 | 10 45 5 0.000410563857799
67 | 28 27 5 0.000562303307602
68 | 0 10 50 0.000558882190036
69 | 6 24 30 0.000558212941977
70 | 17 37 6 0.000505573889982
71 | 43 0 17 0.000690632698311
72 | 50 2 8 0.000384523914961
73 | 4 25 31 0.000559052024715
74 | 6 18 36 0.000515949173091
75 | 23 25 12 0.000594636992935
76 | 48 1 11 0.000455005153111
77 | 4 44 12 0.000431349703568
78 | 12 0 48 0.000596634336102
79 | 39 5 16 0.00048723137665
80 | 3 42 15 0.000471212939884
81 | 25 19 16 0.000608054593057
82 | 6 46 8 0.000394128000967
83 | 34 9 17 0.000534309679581
84 | 33 25 2 0.000583686849508
85 | 9 0 51 0.000540788525529
86 | 4 32 24 0.000554714471559
87 | 26 6 28 0.000563205272437
88 | 17 10 33 0.00054475886607
89 | 28 20 12 0.00058513062186
90 | 0 25 35 0.000799937494985
91 | 57 2 1 0.000373898666741
92 | 12 41 7 0.000455032512107
93 | 7 24 29 0.000563439276973
94 | 39 14 7 0.000480132083066
95 | 29 30 1 0.000644598993328
96 | 15 34 11 0.000535861017312
97 | 10 15 35 0.000524714144684
98 | 22 36 2 0.000562897480566
99 | 12 45 3 0.000430776639063
100 | 13 15 32 0.000557125584217
101 | 8 19 33 0.00054230015282
102 | 5 10 45 0.000410563857799
103 | 53 7 0 0.000507639277123
104 | 34 8 18 0.000533613397403
105 | 14 34 12 0.000536349975984
106 | 21 16 23 0.000613089417709
107 | 1 21 38 0.000596129646217
108 | 19 0 41 0.000724583462662
109 | 16 36 8 0.000513625240855
110 | 6 6 48 0.000372188153326
111 | 23 37 0 0.000780130337846
112 | 20 1 39 0.000584780420163
113 | 21 31 8 0.000556645045176
114 | 13 5 42 0.000449836829755
115 | 2 9 49 0.000397579514036
116 | 37 16 7 0.000503520406582
117 | 30 13 17 0.000574518286348
118 | 30 6 24 0.000558212941977
119 | 10 38 12 0.000489858926854
120 | 22 35 3 0.00054703893668
121 | 13 32 15 0.000557125584217
122 | 34 21 5 0.000536736834183
123 | 43 11 6 0.000432035856162
124 | 9 2 49 0.000397579514036
125 | 32 24 4 0.000554714471559
126 | 9 39 12 0.000477841915704
127 | 20 14 26 0.000599917880717
128 | 4 30 26 0.000562177966124
129 | 20 9 31 0.000558920375004
130 | 35 9 16 0.000524284544741
131 | 29 0 31 0.000820418017588
132 | 17 19 24 0.000612777218961
133 | 0 2 58 0.000481572115707
134 | 51 4 5 0.000348420109833
135 | 30 12 18 0.000572833115344
136 | 0 32 28 0.000817820521541
137 | 20 24 16 0.00061119221221
138 | 11 2 47 0.000425247956462
139 | 8 17 35 0.000524024255459
140 | 5 12 43 0.000436768161023
141 | 34 20 6 0.00053414903673
142 | 6 43 11 0.000432035856162
143 | 5 43 12 0.000436768161023
144 | 42 10 8 0.000440682063633
145 | 25 32 3 0.000565485562125
146 | 36 14 10 0.000513611204695
147 | 38 13 9 0.000490157910944
148 | 4 33 23 0.000549203580748
149 | 4 29 27 0.000564064666008
150 | 36 24 0 0.00079077667923
151 | 22 25 13 0.00059925571499
152 | 20 7 33 0.000541563717313
153 | 1 12 47 0.000470390572843
154 | 22 15 23 0.000609861242306
155 | 37 18 5 0.000509461743506
156 | 0 59 1 0.000518034490428
157 | 41 4 15 0.000470617386893
158 | 31 7 22 0.000554785832172
159 | 17 16 27 0.000598219286947
160 | 25 15 20 0.000606046935916
161 | 24 23 13 0.000600539275794
162 | 6 22 32 0.000548409201255
163 | 15 19 26 0.000602275177782
164 | 19 41 0 0.000724583462662
165 | 33 10 17 0.00054475886607
166 | 38 12 10 0.000489858926854
167 | 28 24 8 0.000569654303715
168 | 49 3 8 0.000377801164992
169 | 16 33 11 0.000545892195496
170 | 7 19 34 0.000533385575385
171 | 10 10 40 0.000465039644211
172 | 7 28 25 0.000565946301449
173 | 7 37 16 0.000503520406582
174 | 8 20 32 0.000550001670772
175 | 29 2 29 0.000594130761983
176 | 13 39 8 0.000478638959343
177 | 10 3 47 0.000403607001432
178 | 2 41 17 0.000508422014232
179 | 48 12 0 0.000596634336102
180 | 31 19 10 0.000561240961747
181 | 30 3 27 0.000571817425947
182 | 38 15 7 0.000492102347195
183 | 35 1 24 0.000623793059998
184 | 14 10 36 0.000513611204695
185 | 5 14 41 0.000462688733129
186 | 1 49 10 0.000439869993691
187 | 5 7 48 0.000373883418934
188 | 24 22 14 0.000605008670315
189 | 10 44 6 0.000419094260354
190 | 21 20 19 0.000620024731277
191 | 44 14 2 0.00046787785258
192 | 26 0 34 0.000807537834977
193 | 7 46 7 0.000392997219042
194 | 20 2 38 0.000543676659051
195 | 29 7 24 0.000563439276973
196 | 27 23 10 0.000581049081881
197 | 5 17 38 0.000498688979294
198 | 20 5 35 0.000528571188991
199 | 1 16 43 0.00053128655342
200 | 1 14 45 0.000501256623742
201 | 2 40 18 0.000520904307398
202 | 13 9 38 0.000490157910944
203 | 37 20 3 0.00052939568825
204 | 2 18 40 0.000520904307398
205 | 41 6 13 0.000457900975492
206 | 10 33 17 0.00054475886607
207 | 53 1 6 0.000386369230522
208 | 13 36 11 0.000513742592469
209 | 24 21 15 0.00060858507757
210 | 46 11 3 0.000417114121438
211 | 15 17 28 0.000591215071466
212 | 19 39 2 0.000532689007384
213 | 17 24 19 0.000612777218961
214 | 25 7 28 0.000565946301449
215 | 0 3 57 0.000472067807554
216 | 5 48 7 0.000373883418934
217 | 16 26 18 0.000603713170637
218 | 14 15 31 0.00056690063487
219 | 35 5 20 0.000528571188991
220 | 19 30 11 0.00057059401282
221 | 25 17 18 0.000609069388139
222 | 29 4 27 0.000564064666008
223 | 2 53 5 0.000352159833508
224 | 16 23 21 0.000613089417709
225 | 31 15 14 0.00056690063487
226 | 48 10 2 0.000411225549409
227 | 31 17 12 0.000565069647464
228 | 0 56 4 0.000473881568417
229 | 10 32 18 0.000553490763168
230 | 33 9 18 0.000543482679964
231 | 11 14 35 0.000525103680786
232 | 31 6 23 0.000553894267806
233 | 42 14 4 0.000457792403926
234 | 21 22 17 0.000616530447443
235 | 32 20 8 0.000550001670772
236 | 3 41 16 0.000484072500847
237 | 41 17 2 0.000508422014232
238 | 8 32 20 0.000550001670772
239 | 18 12 30 0.000572833115344
240 | 36 10 14 0.000513611204695
241 | 6 26 28 0.000563205272437
242 | 1 18 41 0.000559440397503
243 | 2 52 6 0.000361360418101
244 | 16 22 22 0.000613724258099
245 | 48 9 3 0.000390432381229
246 | 37 22 1 0.000606470645494
247 | 1 47 12 0.000470390572843
248 | 39 13 8 0.000478638959343
249 | 23 22 15 0.000609861242306
250 | 13 38 9 0.000490157910944
251 | 6 45 9 0.000406384681257
252 | 4 12 44 0.000431349703568
253 | 31 8 21 0.000556645045176
254 | 2 29 29 0.000594130761983
255 | 33 1 26 0.00063616965736
256 | 4 56 0 0.000473881568417
257 | 17 4 39 0.000494870083604
258 | 12 34 14 0.000536349975984
259 | 11 20 29 0.000576745146519
260 | 38 8 14 0.000490815596489
261 | 0 23 37 0.000780130337846
262 | 0 1 59 0.000518034490428
263 | 5 50 5 0.000354655431723
264 | 0 44 16 0.00067257173668
265 | 35 3 22 0.00054703893668
266 | 9 40 11 0.000465294284403
267 | 16 21 23 0.000613089417709
268 | 0 12 48 0.000596634336102
269 | 54 4 2 0.000345614053259
270 | 26 1 33 0.00063616965736
271 | 28 32 0 0.000817820521541
272 | 34 7 19 0.000533385575385
273 | 3 4 53 0.000339990113993
274 | 16 41 3 0.000484072500847
275 | 14 30 16 0.000575562514854
276 | 5 28 27 0.000562303307602
277 | 3 39 18 0.000508163523847
278 | 20 6 34 0.00053414903673
279 | 25 8 27 0.000571548093182
280 | 0 0 60 0.000672927508895
281 | 2 3 55 0.000343377513917
282 | 40 16 4 0.000483014315787
283 | 27 19 14 0.000595523628638
284 | 16 44 0 0.00067257173668
285 | 1 43 16 0.00053128655342
286 | 7 26 27 0.000567205618363
287 | 39 8 13 0.000478638959343
288 | 1 56 3 0.000367461057285
289 | 10 13 37 0.000501947385234
290 | 2 35 23 0.000570968029697
291 | 41 19 0 0.000724583462662
292 | 13 13 34 0.000536521423079
293 | 15 11 34 0.000535861017312
294 | 30 30 0 0.000821286248119
295 | 7 45 8 0.000404493816949
296 | 53 5 2 0.000352159833508
297 | 13 40 7 0.000467731273606
298 | 38 11 11 0.000489774401922
299 | 33 21 6 0.000541807496111
300 | 14 7 39 0.000480132083066
301 | 17 6 37 0.000505573889982
302 | 19 35 6 0.000525503361058
303 | 29 10 21 0.000573498390044
304 | 0 21 39 0.000754738932243
305 | 16 43 1 0.00053128655342
306 | 5 52 3 0.000346374006092
307 | 6 4 50 0.000357258223823
308 | 18 29 13 0.000581753357221
309 | 19 26 15 0.000602275177782
310 | 9 42 9 0.000440213838911
311 | 14 44 2 0.00046787785258
312 | 0 16 44 0.00067257173668
313 | 13 3 44 0.000444439223787
314 | 18 2 40 0.000520904307398
315 | 30 4 26 0.000562177966124
316 | 28 6 26 0.000563205272437
317 | 20 16 24 0.00061119221221
318 | 11 10 39 0.000477498435273
319 | 38 2 20 0.000543676659051
320 | 24 16 20 0.00061119221221
321 | 42 9 9 0.000440213838911
322 | 4 43 13 0.000444660026359
323 | 18 13 29 0.000581753357221
324 | 32 15 13 0.000557125584217
325 | 25 28 7 0.000565946301449
326 | 3 37 20 0.00052939568825
327 | 40 4 16 0.000483014315787
328 | 25 10 25 0.000583598958715
329 | 10 23 27 0.000581049081881
330 | 8 47 5 0.000385449128184
331 | 16 42 2 0.000495347908903
332 | 33 17 10 0.00054475886607
333 | 36 16 8 0.000513625240855
334 | 5 5 50 0.000354655431723
335 | 1 7 52 0.000398085617614
336 | 51 6 3 0.000355326542624
337 | 6 7 47 0.000382603299343
338 | 12 12 36 0.000513797505382
339 | 13 42 5 0.000449836829755
340 | 6 41 13 0.000457900975492
341 | 52 4 4 0.000342124459796
342 | 31 12 17 0.000565069647464
343 | 46 6 8 0.000394128000967
344 | 42 8 10 0.000440682063633
345 | 4 42 14 0.000457792403926
346 | 13 31 16 0.000566278233658
347 | 14 27 19 0.000595523628638
348 | 40 3 17 0.000496425389375
349 | 17 39 4 0.000494870083604
350 | 8 46 6 0.000394128000967
351 | 36 13 11 0.000513742592469
352 | 5 54 1 0.000376584228843
353 | 48 2 10 0.000411225549409
354 | 3 53 4 0.000339990113993
355 | 22 34 4 0.00054256788204
356 | 5 24 31 0.000554832508077
357 | 1 33 26 0.00063616965736
358 | 54 0 6 0.000493456285536
359 | 30 27 3 0.000571817425947
360 | 11 8 41 0.000453414475786
361 | 49 0 11 0.000577577412196
362 | 6 40 14 0.000470520169659
363 | 24 14 22 0.000605008670315
364 | 3 15 42 0.000471212939884
365 | 4 41 15 0.000470617386893
366 | 32 19 9 0.000551712985417
367 | 32 13 15 0.000557125584217
368 | 25 30 5 0.000558551095357
369 | 27 33 0 0.000813515266876
370 | 40 2 18 0.000520904307398
371 | 8 45 7 0.000404493816949
372 | 27 31 2 0.000591497111978
373 | 2 27 31 0.000591497111978
374 | 39 12 9 0.000477841915704
375 | 1 24 35 0.000623793059998
376 | 23 11 26 0.000588081747586
377 | 22 27 11 0.000585532967493
378 | 21 27 12 0.000589536586579
379 | 30 1 29 0.000644598993328
380 | 3 35 22 0.00054703893668
381 | 10 50 0 0.000558882190036
382 | 17 26 17 0.000604196392016
383 | 32 2 26 0.000588226360032
384 | 24 13 23 0.000600539275794
385 | 55 0 5 0.000481789016038
386 | 32 18 10 0.000553490763168
387 | 6 5 49 0.000363438071327
388 | 15 37 8 0.000502518420415
389 | 18 27 15 0.000597312322493
390 | 7 40 13 0.000467731273606
391 | 10 41 9 0.000452685505882
392 | 40 1 19 0.00057251691181
393 | 7 7 46 0.000392997219042
394 | 0 11 49 0.000577577412196
395 | 20 15 25 0.000606046935916
396 | 29 12 19 0.000579543525933
397 | 1 53 6 0.000386369230522
398 | 27 16 17 0.000598219286947
399 | 38 0 22 0.000768085194696
400 | 30 15 15 0.000575915999366
401 | 21 0 39 0.000754738932243
402 | 30 0 30 0.000821286248119
403 | 16 2 42 0.000495347908903
404 | 11 1 48 0.000455005153111
405 | 24 15 21 0.00060858507757
406 | 49 2 9 0.000397579514036
407 | 10 27 23 0.000581049081881
408 | 3 13 44 0.000444439223787
409 | 4 47 9 0.000391839926085
410 | 23 21 16 0.000613089417709
411 | 10 12 38 0.000489858926854
412 | 43 16 1 0.00053128655342
413 | 27 29 4 0.000564064666008
414 | 13 21 26 0.00059670199104
415 | 11 19 30 0.00057059401282
416 | 6 34 20 0.00053414903673
417 | 1 26 33 0.00063616965736
418 | 48 4 8 0.000379415766803
419 | 1 3 56 0.000367461057285
420 | 48 7 5 0.000373883418934
421 | 0 42 18 0.000708016814567
422 | 51 2 7 0.000372328832234
423 | 30 2 28 0.000593470924499
424 | 14 11 35 0.000525103680786
425 | 39 21 0 0.000754738932243
426 | 23 30 7 0.000559707654648
427 | 13 46 1 0.00048585847447
428 | 25 3 32 0.000565485562125
429 | 4 4 52 0.000342124459796
430 | 31 0 29 0.000820418017588
431 | 4 46 10 0.000404772750137
432 | 9 16 35 0.000524284544741
433 | 4 48 8 0.000379415766803
434 | 19 12 29 0.000579543525933
435 | 11 28 21 0.000581741494327
436 | 17 35 8 0.000524024255459
437 | 24 36 0 0.00079077667923
438 | 28 4 28 0.000564695427811
439 | 0 9 51 0.000540788525529
440 | 2 2 56 0.000349138531125
441 | 29 14 17 0.000583277471058
442 | 16 16 28 0.000591639193906
443 | 48 6 6 0.000372188153326
444 | 31 5 24 0.000554832508077
445 | 0 52 8 0.000523584874616
446 | 21 2 37 0.000553774587906
447 | 0 39 21 0.000754738932243
448 | 0 46 14 0.000635017886853
449 | 31 10 19 0.000561240961747
450 | 3 11 46 0.000417114121438
451 | 44 1 15 0.000516443688638
452 | 4 45 11 0.000418002012485
453 | 14 29 17 0.000583277471058
454 | 14 22 24 0.000605008670315
455 | 11 22 27 0.000585532967493
456 | 43 4 13 0.000444660026359
457 | 16 28 16 0.000591639193906
458 | 27 27 6 0.000563833588954
459 | 23 35 2 0.000570968029697
460 | 2 31 27 0.000591497111978
461 | 17 32 11 0.000555087730158
462 | 10 5 45 0.000410563857799
463 | 48 5 7 0.000373883418934
464 | 1 19 40 0.00057251691181
465 | 0 51 9 0.000540788525529
466 | 5 39 16 0.00048723137665
467 | 30 29 1 0.000644598993328
468 | 0 45 15 0.00065398171375
469 | 19 25 16 0.000608054593057
470 | 34 5 21 0.000536736834183
471 | 55 4 1 0.000369686093265
472 | 3 6 51 0.000355326542624
473 | 9 25 26 0.000577564346527
474 | 9 18 33 0.000543482679964
475 | 14 28 18 0.00058995627968
476 | 18 31 11 0.000563350221647
477 | 7 44 9 0.00041670467739
478 | 35 13 12 0.000525327868788
479 | 45 0 15 0.00065398171375
480 | 8 40 12 0.000466122480142
481 | 39 3 18 0.000508163523847
482 | 26 26 8 0.000572181333105
483 | 44 2 14 0.00046787785258
484 | 39 10 11 0.000477498435273
485 | 35 25 0 0.000799937494985
486 | 5 30 25 0.000558551095357
487 | 22 29 9 0.000569998719715
488 | 22 33 5 0.00054387644544
489 | 0 50 10 0.000558882190036
490 | 21 4 35 0.000534865688674
491 | 30 28 2 0.000593470924499
492 | 53 3 4 0.000339990113993
493 | 38 10 12 0.000489858926854
494 | 34 4 22 0.00054256788204
495 | 10 31 19 0.000561240961747
496 | 31 11 18 0.000563350221647
497 | 12 3 45 0.000430776639063
498 | 19 1 40 0.00057251691181
499 | 17 13 30 0.000574518286348
500 | 25 20 15 0.000606046935916
501 | 15 7 38 0.000492102347195
502 | 17 21 22 0.000616530447443
503 | 8 39 13 0.000478638959343
504 | 13 25 22 0.00059925571499
505 | 23 33 4 0.000549203580748
506 | 17 34 9 0.000534309679581
507 | 22 28 10 0.00057788496369
508 | 12 40 8 0.000466122480142
509 | 18 0 42 0.000708016814567
510 | 12 2 46 0.000439466945027
511 | 13 44 3 0.000444439223787
512 | 15 1 44 0.000516443688638
513 | 19 23 18 0.000616376538476
514 | 2 10 48 0.000411225549409
515 | 0 48 12 0.000596634336102
516 | 24 7 29 0.000563439276973
517 | 31 4 25 0.000559052024715
518 | 12 5 43 0.000436768161023
519 | 14 19 27 0.000595523628638
520 | 43 13 4 0.000444660026359
521 | 25 1 34 0.000630629627707
522 | 16 39 5 0.00048723137665
523 | 7 0 53 0.000507639277123
524 | 45 1 14 0.000501256623742
525 | 7 35 18 0.0005242606635
526 | 0 40 20 0.000740199339251
527 | 7 53 0 0.000507639277123
528 | 36 20 4 0.000526164563267
529 | 0 6 54 0.000493456285536
530 | 51 8 1 0.000411152021077
531 | 16 19 25 0.000608054593057
532 | 11 39 10 0.000477498435273
533 | 1 41 18 0.000559440397503
534 | 21 6 33 0.000541807496111
535 | 30 19 11 0.00057059401282
536 | 49 8 3 0.000377801164992
537 | 24 6 30 0.000558212941977
538 | 20 23 17 0.00061527433194
539 | 32 27 1 0.000640366337092
540 | 14 25 21 0.000603091017132
541 | 20 8 32 0.000550001670772
542 | 25 22 13 0.00059925571499
543 | 38 3 19 0.00051918527119
544 | 11 18 31 0.000563350221647
545 | 16 38 6 0.000494473283901
546 | 27 7 26 0.000567205618363
547 | 21 30 9 0.000565035203114
548 | 37 8 15 0.000502518420415
549 | 20 27 13 0.000592904844502
550 | 30 25 5 0.000558551095357
551 | 17 20 23 0.00061527433194
552 | 10 49 1 0.000439869993691
553 | 4 14 42 0.000457792403926
554 | 9 33 18 0.000543482679964
555 | 24 5 31 0.000554832508077
556 | 15 31 14 0.00056690063487
557 | 3 2 55 0.000343377513917
558 | 3 24 33 0.000560486469349
559 | 14 24 22 0.000605008670315
560 | 5 26 29 0.000561048821157
561 | 16 37 7 0.000503520406582
562 | 7 15 38 0.000492102347195
563 | 15 22 23 0.000609861242306
564 | 26 30 4 0.000562177966124
565 | 7 33 20 0.000541563717313
566 | 44 0 16 0.00067257173668
567 | 35 21 4 0.000534865688674
568 | 19 14 27 0.000595523628638
569 | 2 37 21 0.000553774587906
570 | 48 0 12 0.000596634336102
571 | 11 37 12 0.000501914704779
572 | 8 9 43 0.000428118760096
573 | 6 30 24 0.000558212941977
574 | 30 24 6 0.000558212941977
575 | 14 14 32 0.000557395520244
576 | 10 48 2 0.000411225549409
577 | 49 10 1 0.000439869993691
578 | 33 23 4 0.000549203580748
579 | 55 2 3 0.000343377513917
580 | 10 19 31 0.000561240961747
581 | 10 28 22 0.00057788496369
582 | 31 22 7 0.000554785832172
583 | 32 25 3 0.000565485562125
584 | 18 6 36 0.000515949173091
585 | 7 42 11 0.000442181806539
586 | 12 28 20 0.00058513062186
587 | 3 57 0 0.000472067807554
588 | 10 4 46 0.000404772750137
589 | 15 24 21 0.00060858507757
590 | 18 1 41 0.000559440397503
591 | 13 29 18 0.000581753357221
592 | 45 15 0 0.00065398171375
593 | 1 20 39 0.000584780420163
594 | 6 42 12 0.000445024944313
595 | 1 2 57 0.000373898666741
596 | 2 36 22 0.000562897480566
597 | 28 15 17 0.000591215071466
598 | 9 7 44 0.00041670467739
599 | 20 25 15 0.000606046935916
600 | 18 18 24 0.000613308980689
601 | 17 22 21 0.000616530447443
602 | 19 19 22 0.00061880325113
603 | 23 6 31 0.000553894267806
604 | 26 31 3 0.000569273557353
605 | 42 11 7 0.000442181806539
606 | 31 24 5 0.000554832508077
607 | 14 36 10 0.000513611204695
608 | 12 9 39 0.000477841915704
609 | 26 8 26 0.000572181333105
610 | 37 15 8 0.000502518420415
611 | 0 7 53 0.000507639277123
612 | 7 4 49 0.00036776787047
613 | 13 19 28 0.000587904261256
614 | 45 5 10 0.000410563857799
615 | 0 4 56 0.000473881568417
616 | 35 19 6 0.000525503361058
617 | 11 35 14 0.000525103680786
618 | 0 60 0 0.000672927508895
619 | 26 22 12 0.000592716196383
620 | 28 5 27 0.000562303307602
621 | 23 24 13 0.000600539275794
622 | 43 9 8 0.000428118760096
623 | 31 2 27 0.000591497111978
624 | 18 14 28 0.00058995627968
625 | 3 20 37 0.00052939568825
626 | 14 21 25 0.000603091017132
627 | 6 19 35 0.000525503361058
628 | 3 55 2 0.000343377513917
629 | 11 30 19 0.00057059401282
630 | 43 12 5 0.000436768161023
631 | 4 15 41 0.000470617386893
632 | 27 3 30 0.000571817425947
633 | 16 24 20 0.00061119221221
634 | 5 37 18 0.000509461743506
635 | 24 3 33 0.000560486469349
636 | 1 22 37 0.000606470645494
637 | 6 27 27 0.000563833588954
638 | 37 12 11 0.000501914704779
639 | 20 31 9 0.000558920375004
640 | 30 21 9 0.000565035203114
641 | 15 45 0 0.00065398171375
642 | 33 5 22 0.00054387644544
643 | 2 45 13 0.000453724638536
644 | 12 15 33 0.000546726531298
645 | 14 20 26 0.000599917880717
646 | 43 6 11 0.000432035856162
647 | 22 18 20 0.000618232740386
648 | 5 40 15 0.000475193799381
649 | 1 38 21 0.000596129646217
650 | 0 5 55 0.000481789016038
651 | 33 12 15 0.000546726531298
652 | 26 25 9 0.000577564346527
653 | 17 9 34 0.000534309679581
654 | 8 10 42 0.000440682063633
655 | 5 29 26 0.000561048821157
656 | 6 20 34 0.00053414903673
657 | 9 44 7 0.00041670467739
658 | 19 10 31 0.000561240961747
659 | 24 20 16 0.00061119221221
660 | 22 14 24 0.000605008670315
661 | 14 0 46 0.000635017886853
662 | 0 58 2 0.000481572115707
663 | 30 20 10 0.000567932192157
664 | 52 3 5 0.000346374006092
665 | 33 19 8 0.00054230015282
666 | 24 0 36 0.00079077667923
667 | 3 8 49 0.000377801164992
668 | 3 1 56 0.000367461057285
669 | 41 9 10 0.000452685505882
670 | 2 50 8 0.000384523914961
671 | 25 12 23 0.000594636992935
672 | 47 7 6 0.000382603299343
673 | 40 20 0 0.000740199339251
674 | 16 32 12 0.000556335751302
675 | 15 28 17 0.000591215071466
676 | 26 24 10 0.000582959937935
677 | 41 0 19 0.000724583462662
678 | 2 28 30 0.000593470924499
679 | 24 19 17 0.000612777218961
680 | 37 14 9 0.000502091716183
681 | 1 55 4 0.000369686093265
682 | 18 8 34 0.000533613397403
683 | 12 10 38 0.000489858926854
684 | 5 49 6 0.000363438071327
685 | 55 5 0 0.000481789016038
686 | 52 2 6 0.000361360418101
687 | 10 29 21 0.000573498390044
688 | 42 15 3 0.000471212939884
689 | 31 28 1 0.000643184095371
690 | 12 13 35 0.000525327868788
691 | 18 28 14 0.00058995627968
692 | 26 34 0 0.000807537834977
693 | 5 42 13 0.000449836829755
694 | 0 27 33 0.000813515266876
695 | 33 14 13 0.000547166402343
696 | 23 9 28 0.000573763413236
697 | 45 9 6 0.000406384681257
698 | 4 31 25 0.000559052024715
699 | 9 46 5 0.000397766746838
700 | 24 18 18 0.000613308980689
701 | 12 36 12 0.000513797505382
702 | 51 0 9 0.000540788525529
703 | 11 47 2 0.000425247956462
704 | 19 21 20 0.000620024731277
705 | 38 6 16 0.000494473283901
706 | 23 28 9 0.000573763413236
707 | 1 15 44 0.000516443688638
708 | 52 1 7 0.000398085617614
709 | 23 29 8 0.000566517703157
710 | 5 47 8 0.000385449128184
711 | 32 3 25 0.000565485562125
712 | 14 17 29 0.000583277471058
713 | 20 0 40 0.000740199339251
714 | 25 14 21 0.000603091017132
715 | 3 51 6 0.000355326542624
716 | 11 26 23 0.000588081747586
717 | 40 18 2 0.000520904307398
718 | 13 0 47 0.000615843998012
719 | 7 2 51 0.000372328832234
720 | 27 15 18 0.000597312322493
721 | 41 2 17 0.000508422014232
722 | 10 7 43 0.000429342904055
723 | 3 49 8 0.000377801164992
724 | 4 2 54 0.000345614053259
725 | 1 8 51 0.000411152021077
726 | 0 47 13 0.000615843998012
727 | 48 3 9 0.000390432381229
728 | 22 11 27 0.000585532967493
729 | 21 11 28 0.000581741494327
730 | 0 41 19 0.000724583462662
731 | 30 17 13 0.000574518286348
732 | 10 2 48 0.000411225549409
733 | 11 32 17 0.000555087730158
734 | 14 16 30 0.000575562514854
735 | 14 31 15 0.00056690063487
736 | 6 21 33 0.000541807496111
737 | 43 2 15 0.000481793851003
738 | 40 17 3 0.000496425389375
739 | 33 18 9 0.000543482679964
740 | 9 5 46 0.000397766746838
741 | 31 21 8 0.000556645045176
742 | 6 16 38 0.000494473283901
743 | 22 38 0 0.000768085194696
744 | 25 25 10 0.000583598958715
745 | 10 47 3 0.000403607001432
746 | 1 37 22 0.000606470645494
747 | 11 45 4 0.000418002012485
748 | 30 16 14 0.000575562514854
749 | 14 6 40 0.000470520169659
750 | 49 4 7 0.00036776787047
751 | 11 17 32 0.000555087730158
752 | 5 44 11 0.000423624580479
753 | 32 23 5 0.000549926340121
754 | 1 44 15 0.000516443688638
755 | 32 1 27 0.000640366337092
756 | 23 19 18 0.000616376538476
757 | 13 2 45 0.000453724638536
758 | 15 16 29 0.000584054427249
759 | 3 31 26 0.000569273557353
760 | 15 44 1 0.000516443688638
761 | 27 13 20 0.000592904844502
762 | 17 40 3 0.000496425389375
763 | 15 3 42 0.000471212939884
764 | 58 1 1 0.000400921212213
765 | 6 50 4 0.000357258223823
766 | 1 10 49 0.000439869993691
767 | 1 51 8 0.000411152021077
768 | 12 14 34 0.000536349975984
769 | 35 4 21 0.000534865688674
770 | 14 12 34 0.000536349975984
771 | 2 11 47 0.000425247956462
772 | 1 57 2 0.000373898666741
773 | 15 39 6 0.000482751300565
774 | 23 14 23 0.0006056501852
775 | 52 6 2 0.000361360418101
776 | 32 22 6 0.000548409201255
777 | 31 16 13 0.000566278233658
778 | 15 21 24 0.00060858507757
779 | 17 15 28 0.000591215071466
780 | 10 25 25 0.000583598958715
781 | 29 27 4 0.000564064666008
782 | 46 10 4 0.000404772750137
783 | 5 46 9 0.000397766746838
784 | 37 7 16 0.000503520406582
785 | 15 26 19 0.000602275177782
786 | 13 27 20 0.000592904844502
787 | 12 19 29 0.000579543525933
788 | 58 0 2 0.000481572115707
789 | 27 20 13 0.000592904844502
790 | 8 29 23 0.000566517703157
791 | 15 9 36 0.000513508110547
792 | 7 23 30 0.000559707654648
793 | 0 36 24 0.00079077667923
794 | 20 17 23 0.00061527433194
795 | 49 6 5 0.000363438071327
796 | 2 8 50 0.000384523914961
797 | 52 5 3 0.000346374006092
798 | 1 48 11 0.000455005153111
799 | 18 15 27 0.000597312322493
800 | 31 26 3 0.000569273557353
801 | 32 21 7 0.000548719190895
802 | 1 46 13 0.00048585847447
803 | 18 22 20 0.000618232740386
804 | 23 17 20 0.00061527433194
805 | 10 1 49 0.000439869993691
806 | 4 3 53 0.000339990113993
807 | 13 4 43 0.000444660026359
808 | 45 3 12 0.000430776639063
809 | 11 16 33 0.000545892195496
810 | 19 36 5 0.000519452341439
811 | 6 38 16 0.000494473283901
812 | 9 43 8 0.000428118760096
813 | 23 5 32 0.000549926340121
814 | 4 6 50 0.000357258223823
815 | 2 43 15 0.000481793851003
816 | 24 17 19 0.000612777218961
817 | 0 35 25 0.000799937494985
818 | 39 17 4 0.000494870083604
819 | 23 26 11 0.000588081747586
820 | 20 30 10 0.000567932192157
821 | 10 6 44 0.000419094260354
822 | 3 22 35 0.00054703893668
823 | 2 26 32 0.000588226360032
824 | 6 17 37 0.000505573889982
825 | 24 1 35 0.000623793059998
826 | 3 47 10 0.000403607001432
827 | 43 14 3 0.000457961301012
828 | 22 26 12 0.000592716196383
829 | 4 20 36 0.000526164563267
830 | 26 10 24 0.000582959937935
831 | 16 35 9 0.000524284544741
832 | 1 29 30 0.000644598993328
833 | 9 36 15 0.000513508110547
834 | 50 1 9 0.000425176279456
835 | 22 13 25 0.00059925571499
836 | 0 34 26 0.000807537834977
837 | 52 7 1 0.000398085617614
838 | 37 1 22 0.000606470645494
839 | 1 50 9 0.000425176279456
840 | 3 0 57 0.000472067807554
841 | 2 16 42 0.000495347908903
842 | 6 15 39 0.000482751300565
843 | 21 9 30 0.000565035203114
844 | 17 29 14 0.000583277471058
845 | 25 4 31 0.000559052024715
846 | 4 1 55 0.000369686093265
847 | 13 6 41 0.000457900975492
848 | 9 15 36 0.000513508110547
849 | 36 12 12 0.000513797505382
850 | 15 20 25 0.000606046935916
851 | 3 27 30 0.000571817425947
852 | 37 13 10 0.000501947385234
853 | 14 13 33 0.000547166402343
854 | 17 36 7 0.000514274201223
855 | 19 13 28 0.000587904261256
856 | 22 12 26 0.000592716196383
857 | 54 3 3 0.000337791784896
858 | 0 55 5 0.000481789016038
859 | 0 33 27 0.000813515266876
860 | 14 8 38 0.000490815596489
861 | 2 15 43 0.000481793851003
862 | 3 28 29 0.000573094946374
863 | 9 8 43 0.000428118760096
864 | 10 21 29 0.000573498390044
865 | 9 29 22 0.000569998719715
866 | 31 20 9 0.000558920375004
867 | 27 21 12 0.000589536586579
868 | 32 12 16 0.000556335751302
869 | 20 33 7 0.000541563717313
870 | 19 9 32 0.000551712985417
871 | 32 0 28 0.000817820521541
872 | 33 24 3 0.000560486469349
873 | 18 3 39 0.000508163523847
874 | 7 16 37 0.000503520406582
875 | 12 23 25 0.000594636992935
876 | 3 36 21 0.000538706957448
877 | 7 51 2 0.000372328832234
878 | 6 35 19 0.000525503361058
879 | 9 38 13 0.000490157910944
880 | 5 19 36 0.000519452341439
881 | 21 33 6 0.000541807496111
882 | 13 7 40 0.000467731273606
883 | 0 54 6 0.000493456285536
884 | 38 5 17 0.000498688979294
885 | 23 13 24 0.000600539275794
886 | 14 42 4 0.000457792403926
887 | 21 24 15 0.00060858507757
888 | 10 20 30 0.000567932192157
889 | 18 17 25 0.000609069388139
890 | 18 26 16 0.000603713170637
891 | 47 11 2 0.000425247956462
892 | 16 34 10 0.000535133560842
893 | 25 6 29 0.000561326032631
894 | 26 32 2 0.000588226360032
895 | 4 7 49 0.00036776787047
896 | 13 8 39 0.000478638959343
897 | 12 22 26 0.000592716196383
898 | 17 38 5 0.000498688979294
899 | 18 9 33 0.000543482679964
900 | 0 53 7 0.000507639277123
901 | 28 14 18 0.00058995627968
902 | 20 11 29 0.000576745146519
903 | 2 34 24 0.00057791759599
904 | 28 16 16 0.000591639193906
905 | 9 49 2 0.000397579514036
906 | 9 10 41 0.000452685505882
907 | 42 12 6 0.000445024944313
908 | 32 16 12 0.000556335751302
909 | 18 16 26 0.000603713170637
910 | 3 18 39 0.000508163523847
911 | 8 28 24 0.000569654303715
912 | 8 50 2 0.000384523914961
913 | 10 24 26 0.000582959937935
914 | 43 10 7 0.000429342904055
915 | 33 26 1 0.00063616965736
916 | 12 47 1 0.000470390572843
917 | 12 21 27 0.000589536586579
918 | 7 49 4 0.00036776787047
919 | 14 3 43 0.000457961301012
920 | 21 18 21 0.000618854081602
921 | 32 14 14 0.000557395520244
922 | 57 3 0 0.000472067807554
923 | 8 15 37 0.000502518420415
924 | 2 17 41 0.000508422014232
925 | 18 30 12 0.000572833115344
926 | 29 31 0 0.000820418017588
927 | 10 0 50 0.000558882190036
928 | 37 5 18 0.000509461743506
929 | 21 26 13 0.00059670199104
930 | 33 7 20 0.000541563717313
931 | 21 39 0 0.000754738932243
932 | 32 9 19 0.000551712985417
933 | 47 9 4 0.000391839926085
934 | 4 5 51 0.000348420109833
935 | 13 10 37 0.000501947385234
936 | 9 11 40 0.000465294284403
937 | 26 27 7 0.000567205618363
938 | 14 9 37 0.000502091716183
939 | 12 37 11 0.000501914704779
940 | 1 4 55 0.000369686093265
941 | 11 31 18 0.000563350221647
942 | 5 33 22 0.00054387644544
943 | 22 8 30 0.000562167683825
944 | 15 15 30 0.000575915999366
945 | 9 47 4 0.000391839926085
946 | 29 21 10 0.000573498390044
947 | 14 4 42 0.000457792403926
948 | 14 39 7 0.000480132083066
949 | 8 48 4 0.000379415766803
950 | 39 19 2 0.000532689007384
951 | 8 26 26 0.000572181333105
952 | 16 15 29 0.000584054427249
953 | 19 5 36 0.000519452341439
954 | 24 4 32 0.000554714471559
955 | 7 11 42 0.000442181806539
956 | 15 18 27 0.000597312322493
957 | 18 7 35 0.0005242606635
958 | 7 20 33 0.000541563717313
959 | 35 15 10 0.000524714144684
960 | 12 27 21 0.000589536586579
961 | 50 10 0 0.000558882190036
962 | 27 9 24 0.000576293331224
963 | 21 37 2 0.000553774587906
964 | 27 28 5 0.000562303307602
965 | 12 35 13 0.000525327868788
966 | 8 13 39 0.000478638959343
967 | 7 31 22 0.000554785832172
968 | 35 6 19 0.000525503361058
969 | 6 23 31 0.000553894267806
970 | 38 1 21 0.000596129646217
971 | 6 9 45 0.000406384681257
972 | 23 8 29 0.000566517703157
973 | 21 28 11 0.000581741494327
974 | 31 18 11 0.000563350221647
975 | 29 23 8 0.000566517703157
976 | 8 25 27 0.000571548093182
977 | 2 12 46 0.000439466945027
978 | 16 14 30 0.000575562514854
979 | 13 12 35 0.000525327868788
980 | 42 3 15 0.000471212939884
981 | 45 11 4 0.000418002012485
982 | 12 26 22 0.000592716196383
983 | 6 37 17 0.000505573889982
984 | 1 6 53 0.000386369230522
985 | 10 8 42 0.000440682063633
986 | 27 22 11 0.000585532967493
987 | 30 22 8 0.000562167683825
988 | 15 8 37 0.000502518420415
989 | 39 7 14 0.000480132083066
990 | 0 43 17 0.000690632698311
991 | 15 43 2 0.000481793851003
992 | 3 9 48 0.000390432381229
993 | 8 36 16 0.000513625240855
994 | 50 6 4 0.000357258223823
995 | 53 0 7 0.000507639277123
996 | 16 13 31 0.000566278233658
997 | 11 24 25 0.000589362493229
998 | 19 3 38 0.00051918527119
999 | 24 2 34 0.00057791759599
1000 | 7 9 44 0.00041670467739
1001 | 26 9 25 0.000577564346527
1002 | 19 38 3 0.00051918527119
1003 | 12 25 23 0.000594636992935
1004 | 6 36 18 0.000515949173091
1005 | 3 23 34 0.000554319763761
1006 | 20 36 4 0.000526164563267
1007 | 10 40 10 0.000465039644211
1008 | 18 34 8 0.000533613397403
1009 | 25 16 19 0.000608054593057
1010 | 11 15 34 0.000535861017312
1011 | 31 14 15 0.00056690063487
1012 | 8 35 17 0.000524024255459
1013 | 1 58 1 0.000400921212213
1014 | 33 3 24 0.000560486469349
1015 | 39 0 21 0.000754738932243
1016 | 2 24 34 0.00057791759599
1017 | 14 18 28 0.00058995627968
1018 | 12 7 41 0.000455032512107
1019 | 13 14 33 0.000547166402343
1020 | 25 35 0 0.000799937494985
1021 | 36 4 20 0.000526164563267
1022 | 6 1 53 0.000386369230522
1023 | 5 9 46 0.000397766746838
1024 | 41 16 3 0.000484072500847
1025 | 14 5 41 0.000462688733129
1026 | 13 34 13 0.000536521423079
1027 | 1 39 20 0.000584780420163
1028 | 11 0 49 0.000577577412196
1029 | 29 25 6 0.000561326032631
1030 | 15 41 4 0.000470617386893
1031 | 52 8 0 0.000523584874616
1032 | 27 25 8 0.000571548093182
1033 | 8 34 18 0.000533613397403
1034 | 9 21 30 0.000565035203114
1035 | 53 2 5 0.000352159833508
1036 | 8 49 3 0.000377801164992
1037 | 22 22 16 0.000613724258099
1038 | 33 0 27 0.000813515266876
1039 | 8 14 38 0.000490815596489
1040 | 35 11 14 0.000525103680786
1041 | 12 31 17 0.000565069647464
1042 | 22 2 36 0.000562897480566
1043 | 23 32 5 0.000549926340121
1044 | 41 12 7 0.000455032512107
1045 | 35 2 23 0.000570968029697
1046 | 25 18 17 0.000609069388139
1047 | 2 13 45 0.000453724638536
1048 | 38 22 0 0.000768085194696
1049 | 23 12 25 0.000594636992935
1050 | 3 3 54 0.000337791784896
1051 | 8 33 19 0.00054230015282
1052 | 3 12 45 0.000430776639063
1053 | 42 5 13 0.000449836829755
1054 | 41 13 6 0.000457900975492
1055 | 18 25 17 0.000609069388139
1056 | 47 3 10 0.000403607001432
1057 | 10 22 28 0.00057788496369
1058 | 7 18 35 0.0005242606635
1059 | 3 17 40 0.000496425389375
1060 | 3 38 19 0.00051918527119
1061 | 44 7 9 0.00041670467739
1062 | 41 18 1 0.000559440397503
1063 | 6 33 21 0.000541807496111
1064 | 4 8 48 0.000379415766803
1065 | 11 43 6 0.000432035856162
1066 | 27 18 15 0.000597312322493
1067 | 4 18 38 0.000506078605648
1068 | 18 4 38 0.000506078605648
1069 | 15 12 33 0.000546726531298
1070 | 10 18 32 0.000553490763168
1071 | 31 3 26 0.000569273557353
1072 | 37 23 0 0.000780130337846
1073 | 11 48 1 0.000455005153111
1074 | 18 24 18 0.000613308980689
1075 | 2 6 52 0.000361360418101
1076 | 53 4 3 0.000339990113993
1077 | 33 20 7 0.000541563717313
1078 | 3 45 12 0.000430776639063
1079 | 33 2 25 0.000583686849508
1080 | 22 7 31 0.000554785832172
1081 | 16 1 43 0.00053128655342
1082 | 7 39 14 0.000480132083066
1083 | 19 34 7 0.000533385575385
1084 | 12 29 19 0.000579543525933
1085 | 9 9 42 0.000440213838911
1086 | 8 7 45 0.000404493816949
1087 | 2 25 33 0.000583686849508
1088 | 18 38 4 0.000506078605648
1089 | 17 3 40 0.000496425389375
1090 | 13 11 36 0.000513742592469
1091 | 32 7 21 0.000548719190895
1092 | 39 4 17 0.000494870083604
1093 | 50 0 10 0.000558882190036
1094 | 40 12 8 0.000466122480142
1095 | 19 20 21 0.000620024731277
1096 | 18 10 32 0.000553490763168
1097 | 22 19 19 0.00061880325113
1098 | 35 7 18 0.0005242606635
1099 | 30 5 25 0.000558551095357
1100 | 9 3 48 0.000390432381229
1101 | 26 19 15 0.000602275177782
1102 | 5 13 42 0.000449836829755
1103 | 14 1 45 0.000501256623742
1104 | 20 21 19 0.000620024731277
1105 | 57 1 2 0.000373898666741
1106 | 13 16 31 0.000566278233658
1107 | 16 27 17 0.000598219286947
1108 | 1 35 24 0.000623793059998
1109 | 12 4 44 0.000431349703568
1110 | 7 32 21 0.000548719190895
1111 | 21 25 14 0.000603091017132
1112 | 29 29 2 0.000594130761983
1113 | 35 20 5 0.000528571188991
1114 | 0 19 41 0.000724583462662
1115 | 38 19 3 0.00051918527119
1116 | 37 3 20 0.00052939568825
1117 | 20 29 11 0.000576745146519
1118 | 11 36 13 0.000513742592469
1119 | 0 22 38 0.000768085194696
1120 | 4 36 20 0.000526164563267
1121 | 15 5 40 0.000475193799381
1122 | 40 11 9 0.000465294284403
1123 | 53 6 1 0.000386369230522
1124 | 17 31 12 0.000565069647464
1125 | 1 13 46 0.00048585847447
1126 | 33 22 5 0.00054387644544
1127 | 5 0 55 0.000481789016038
1128 | 21 29 10 0.000573498390044
1129 | 27 4 29 0.000564064666008
1130 | 24 8 28 0.000569654303715
1131 | 8 5 47 0.000385449128184
1132 | 23 36 1 0.000615717503072
1133 | 1 31 28 0.000643184095371
1134 | 17 41 2 0.000508422014232
1135 | 6 31 23 0.000553894267806
1136 | 16 17 27 0.000598219286947
1137 | 8 2 50 0.000384523914961
1138 | 1 32 27 0.000640366337092
1139 | 9 31 20 0.000558920375004
1140 | 32 5 23 0.000549926340121
1141 | 3 43 14 0.000457961301012
1142 | 40 10 10 0.000465039644211
1143 | 1 27 32 0.000640366337092
1144 | 10 17 33 0.00054475886607
1145 | 4 19 37 0.000516540749585
1146 | 18 5 37 0.000509461743506
1147 | 22 24 14 0.000605008670315
1148 | 3 34 23 0.000554319763761
1149 | 44 11 5 0.000423624580479
1150 | 23 3 34 0.000554319763761
1151 | 6 54 0 0.000493456285536
1152 | 3 29 28 0.000573094946374
1153 | 27 30 3 0.000571817425947
1154 | 4 22 34 0.00054256788204
1155 | 13 18 29 0.000581753357221
1156 | 56 0 4 0.000473881568417
1157 | 15 0 45 0.00065398171375
1158 | 21 23 16 0.000613089417709
1159 | 38 7 15 0.000492102347195
1160 | 17 27 16 0.000598219286947
1161 | 23 10 27 0.000581049081881
1162 | 28 28 4 0.000564695427811
1163 | 34 3 23 0.000554319763761
1164 | 18 19 23 0.000616376538476
1165 | 1 17 42 0.000545658867504
1166 | 46 14 0 0.000635017886853
1167 | 31 13 16 0.000566278233658
1168 | 21 17 22 0.000616530447443
1169 | 13 23 24 0.000600539275794
1170 | 8 8 44 0.000415957532029
1171 | 25 27 8 0.000571548093182
1172 | 44 10 6 0.000419094260354
1173 | 5 2 53 0.000352159833508
1174 | 25 34 1 0.000630629627707
1175 | 5 55 0 0.000481789016038
1176 | 15 10 35 0.000524714144684
1177 | 20 28 12 0.00058513062186
1178 | 18 33 9 0.000543482679964
1179 | 42 4 14 0.000457792403926
1180 | 18 42 0 0.000708016814567
1181 | 20 22 18 0.000618232740386
1182 | 1 52 7 0.000398085617614
1183 | 37 17 6 0.000505573889982
1184 | 1 34 25 0.000630629627707
1185 | 3 16 41 0.000484072500847
1186 | 2 0 58 0.000481572115707
1187 | 1 11 48 0.000455005153111
1188 | 13 33 14 0.000547166402343
1189 | 4 10 46 0.000404772750137
1190 | 2 54 4 0.000345614053259
1191 | 43 8 9 0.000428118760096
1192 | 4 17 39 0.000494870083604
1193 | 26 23 11 0.000588081747586
1194 | 19 40 1 0.00057251691181
1195 | 44 9 7 0.00041670467739
1196 | 22 10 28 0.00057788496369
1197 | 28 0 32 0.000817820521541
1198 | 13 20 27 0.000592904844502
1199 | 2 19 39 0.000532689007384
1200 | 7 36 17 0.000514274201223
1201 | 18 32 10 0.000553490763168
1202 | 29 1 30 0.000644598993328
1203 | 28 13 19 0.000587904261256
1204 | 10 42 8 0.000440682063633
1205 | 52 0 8 0.000523584874616
1206 | 32 6 22 0.000548409201255
1207 | 39 2 19 0.000532689007384
1208 | 17 11 32 0.000555087730158
1209 | 22 21 17 0.000616530447443
1210 | 34 19 7 0.000533385575385
1211 | 25 33 2 0.000583686849508
1212 | 33 8 19 0.00054230015282
1213 | 26 29 5 0.000561048821157
1214 | 8 6 46 0.000394128000967
1215 | 12 46 2 0.000439466945027
1216 | 5 4 51 0.000348420109833
1217 | 29 15 16 0.000584054427249
1218 | 6 51 3 0.000355326542624
1219 | 5 35 20 0.000528571188991
1220 | 42 2 16 0.000495347908903
1221 | 32 4 24 0.000554714471559
1222 | 17 5 38 0.000498688979294
1223 | 20 3 37 0.00052939568825
1224 | 11 7 42 0.000442181806539
1225 | 3 32 25 0.000565485562125
1226 | 4 51 5 0.000348420109833
1227 | 1 54 5 0.000376584228843
1228 | 27 17 16 0.000598219286947
1229 | 28 11 21 0.000581741494327
1230 | 21 8 31 0.000556645045176
1231 | 9 27 24 0.000576293331224
1232 | 41 5 14 0.000462688733129
1233 | 18 37 5 0.000509461743506
1234 | 17 17 26 0.000604196392016
1235 | 0 49 11 0.000577577412196
1236 | 12 32 16 0.000556335751302
1237 | 4 23 33 0.000549203580748
1238 | 26 28 6 0.000563205272437
1239 | 6 14 40 0.000470520169659
1240 | 4 13 43 0.000444660026359
1241 | 34 18 8 0.000533613397403
1242 | 4 0 56 0.000473881568417
1243 | 43 17 0 0.000690632698311
1244 | 27 26 7 0.000567205618363
1245 | 13 22 25 0.00059925571499
1246 | 23 34 3 0.000554319763761
1247 | 0 37 23 0.000780130337846
1248 | 15 4 41 0.000470617386893
1249 | 19 33 8 0.00054230015282
1250 | 32 26 2 0.000588226360032
1251 | 38 20 2 0.000543676659051
1252 | 9 12 39 0.000477841915704
1253 | 3 14 43 0.000457961301012
1254 | 9 1 50 0.000425176279456
1255 | 18 23 19 0.000616376538476
1256 | 50 9 1 0.000425176279456
1257 | 13 47 0 0.000615843998012
1258 | 21 21 18 0.000618854081602
1259 | 9 24 27 0.000576293331224
1260 | 24 32 4 0.000554714471559
1261 | 3 40 17 0.000496425389375
1262 | 7 47 6 0.000382603299343
1263 | 6 39 15 0.000482751300565
1264 | 5 6 49 0.000363438071327
1265 | 48 11 1 0.000455005153111
1266 | 34 11 15 0.000535861017312
1267 | 11 25 24 0.000589362493229
1268 | 10 43 7 0.000429342904055
1269 | 11 5 44 0.000423624580479
1270 | 16 4 40 0.000483014315787
1271 | 6 10 44 0.000419094260354
1272 | 14 46 0 0.000635017886853
1273 | 10 16 34 0.000535133560842
1274 | 37 21 2 0.000553774587906
1275 | 21 10 29 0.000573498390044
1276 | 50 8 2 0.000384523914961
1277 | 13 37 10 0.000501947385234
1278 | 6 32 22 0.000548409201255
1279 | 32 28 0 0.000817820521541
1280 | 7 6 47 0.000382603299343
1281 | 0 20 40 0.000740199339251
1282 | 4 21 35 0.000534865688674
1283 | 26 11 23 0.000588081747586
1284 | 17 12 31 0.000565069647464
1285 | 44 13 3 0.000444439223787
1286 | 0 31 29 0.000820418017588
1287 | 39 1 20 0.000584780420163
1288 | 17 18 25 0.000609069388139
1289 | 13 24 23 0.000600539275794
1290 | 21 15 24 0.00060858507757
1291 | 5 25 30 0.000558551095357
1292 | 2 23 35 0.000570968029697
1293 | 59 0 1 0.000518034490428
1294 | 19 31 10 0.000561240961747
1295 | 16 0 44 0.00067257173668
1296 | 29 5 26 0.000561048821157
1297 | 12 17 31 0.000565069647464
1298 | 9 14 37 0.000502091716183
1299 | 36 3 21 0.000538706957448
1300 | 11 44 5 0.000423624580479
1301 | 19 22 19 0.00061880325113
1302 | 22 17 21 0.000616530447443
1303 | 16 31 13 0.000566278233658
1304 | 29 19 12 0.000579543525933
1305 | 9 26 25 0.000577564346527
1306 | 9 19 32 0.000551712985417
1307 | 28 21 11 0.000581741494327
1308 | 5 11 44 0.000423624580479
1309 | 2 14 44 0.00046787785258
1310 | 0 30 30 0.000821286248119
1311 | 42 6 12 0.000445024944313
1312 | 27 12 21 0.000589536586579
1313 | 28 8 24 0.000569654303715
1314 | 7 34 19 0.000533385575385
1315 | 11 3 46 0.000417114121438
1316 | 35 22 3 0.00054703893668
1317 | 28 19 13 0.000587904261256
1318 | 38 17 5 0.000498688979294
1319 | 11 38 11 0.000489774401922
1320 | 36 2 22 0.000562897480566
1321 | 21 12 27 0.000589536586579
1322 | 16 8 36 0.000513625240855
1323 | 9 23 28 0.000573763413236
1324 | 8 31 21 0.000556645045176
1325 | 23 23 14 0.0006056501852
1326 | 22 16 22 0.000613724258099
1327 | 16 30 14 0.000575562514854
1328 | 17 14 29 0.000583277471058
1329 | 34 22 4 0.00054256788204
1330 | 6 53 1 0.000386369230522
1331 | 0 29 31 0.000820418017588
1332 | 34 1 25 0.000630629627707
1333 | 27 6 27 0.000563833588954
1334 | 20 35 5 0.000528571188991
1335 | 13 26 21 0.00059670199104
1336 | 35 0 25 0.000799937494985
1337 | 19 29 12 0.000579543525933
1338 | 33 15 12 0.000546726531298
1339 | 9 41 10 0.000452685505882
1340 | 17 1 42 0.000545658867504
1341 | 14 43 3 0.000457961301012
1342 | 5 3 52 0.000346374006092
1343 | 3 10 47 0.000403607001432
1344 | 36 1 23 0.000615717503072
1345 | 41 15 4 0.000470617386893
1346 | 8 30 22 0.000562167683825
1347 | 1 25 34 0.000630629627707
1348 | 9 32 19 0.000551712985417
1349 | 46 13 1 0.00048585847447
1350 | 16 29 15 0.000584054427249
1351 | 24 11 25 0.000589362493229
1352 | 15 30 15 0.000575915999366
1353 | 8 0 52 0.000523584874616
1354 | 23 16 21 0.000613089417709
1355 | 25 9 26 0.000577564346527
1356 | 47 1 12 0.000470390572843
1357 | 6 52 2 0.000361360418101
1358 | 34 15 11 0.000535861017312
1359 | 23 1 36 0.000615717503072
1360 | 20 34 6 0.00053414903673
1361 | 45 2 13 0.000453724638536
1362 | 7 27 26 0.000567205618363
1363 | 15 2 43 0.000481793851003
1364 | 20 20 20 0.000620624876737
1365 | 18 41 1 0.000559440397503
1366 | 28 17 15 0.000591215071466
1367 | 51 9 0 0.000540788525529
1368 | 8 51 1 0.000411152021077
1369 | 1 42 17 0.000545658867504
1370 | 21 7 32 0.000548719190895
1371 | 50 3 7 0.000365979242514
1372 | 39 16 5 0.00048723137665
1373 | 3 33 24 0.000560486469349
1374 | 14 2 44 0.00046787785258
1375 | 46 12 2 0.000439466945027
1376 | 44 6 10 0.000419094260354
1377 | 20 13 27 0.000592904844502
1378 | 45 7 8 0.000404493816949
1379 | 24 24 12 0.000595279433757
1380 | 26 15 19 0.000602275177782
1381 | 19 32 9 0.000551712985417
1382 | 8 18 34 0.000533613397403
1383 | 27 11 22 0.000585532967493
1384 | 17 42 1 0.000545658867504
1385 | 5 53 2 0.000352159833508
1386 | 13 28 19 0.000587904261256
1387 | 19 27 14 0.000595523628638
1388 | 29 9 22 0.000569998719715
1389 | 8 44 8 0.000415957532029
1390 | 36 7 17 0.000514274201223
1391 | 19 18 23 0.000616376538476
1392 | 9 34 17 0.000534309679581
1393 | 0 24 36 0.00079077667923
1394 | 2 1 57 0.000373898666741
1395 | 12 16 32 0.000556335751302
1396 | 26 21 13 0.00059670199104
1397 | 25 29 6 0.000561326032631
1398 | 27 32 1 0.000640366337092
1399 | 16 3 41 0.000484072500847
1400 | 9 35 16 0.000524284544741
1401 | 42 1 17 0.000545658867504
1402 | 4 35 21 0.000534865688674
1403 | 45 4 11 0.000418002012485
1404 | 7 25 28 0.000565946301449
1405 | 46 2 12 0.000439466945027
1406 | 30 8 22 0.000562167683825
1407 | 35 18 7 0.0005242606635
1408 | 28 23 9 0.000573763413236
1409 | 19 4 37 0.000516540749585
1410 | 46 7 7 0.000392997219042
1411 | 22 3 35 0.00054703893668
1412 | 51 7 2 0.000372328832234
1413 | 11 34 15 0.000535861017312
1414 | 36 6 18 0.000515949173091
1415 | 2 20 38 0.000543676659051
1416 | 6 11 43 0.000432035856162
1417 | 17 25 18 0.000609069388139
1418 | 25 0 35 0.000799937494985
1419 | 49 11 0 0.000577577412196
1420 | 46 3 11 0.000417114121438
1421 | 21 35 4 0.000534865688674
1422 | 30 10 20 0.000567932192157
1423 | 26 20 14 0.000599917880717
1424 | 12 20 28 0.00058513062186
1425 | 34 17 9 0.000534309679581
1426 | 3 54 3 0.000337791784896
1427 | 34 26 0 0.000807537834977
1428 | 6 49 5 0.000363438071327
1429 | 4 24 32 0.000554714471559
1430 | 42 0 18 0.000708016814567
1431 | 27 2 31 0.000591497111978
1432 | 5 21 34 0.000536736834183
1433 | 20 39 1 0.000584780420163
1434 | 13 30 17 0.000574518286348
1435 | 4 52 4 0.000342124459796
1436 | 28 22 10 0.00057788496369
1437 | 2 38 20 0.000543676659051
1438 | 9 4 47 0.000391839926085
1439 | 47 13 0 0.000615843998012
1440 | 36 5 19 0.000519452341439
1441 | 41 11 8 0.000453414475786
1442 | 49 1 10 0.000439869993691
1443 | 46 9 5 0.000397766746838
1444 | 33 4 23 0.000549203580748
1445 | 39 15 6 0.000482751300565
1446 | 6 12 42 0.000445024944313
1447 | 23 20 17 0.00061527433194
1448 | 34 16 10 0.000535133560842
1449 | 24 28 8 0.000569654303715
1450 | 33 11 16 0.000545892195496
1451 | 6 48 6 0.000372188153326
1452 | 22 6 32 0.000548409201255
1453 | 3 7 50 0.000365979242514
1454 | 20 38 2 0.000543676659051
1455 | 45 6 9 0.000406384681257
1456 | 8 37 15 0.000502518420415
1457 | 10 35 15 0.000524714144684
1458 | 11 13 36 0.000513742592469
1459 | 16 12 32 0.000556335751302
1460 | 14 45 1 0.000501256623742
1461 | 14 38 8 0.000490815596489
1462 | 9 51 0 0.000540788525529
1463 | 51 5 4 0.000348420109833
1464 | 18 21 21 0.000618854081602
1465 | 50 7 3 0.000365979242514
1466 | 39 20 1 0.000584780420163
1467 | 13 45 2 0.000453724638536
1468 | 20 26 14 0.000599917880717
1469 | 25 2 33 0.000583686849508
1470 | 46 8 6 0.000394128000967
1471 | 2 47 11 0.000425247956462
1472 | 21 19 20 0.000620024731277
1473 | 7 14 39 0.000480132083066
1474 | 41 8 11 0.000453414475786
1475 | 16 7 37 0.000503520406582
1476 | 26 3 31 0.000569273557353
1477 | 1 9 50 0.000425176279456
1478 | 47 6 7 0.000382603299343
1479 | 24 27 9 0.000576293331224
1480 | 28 12 20 0.00058513062186
1481 | 11 27 22 0.000585532967493
1482 | 20 37 3 0.00052939568825
1483 | 18 35 7 0.0005242606635
1484 | 7 48 5 0.000373883418934
1485 | 38 9 13 0.000490157910944
1486 | 29 13 18 0.000581753357221
1487 | 29 17 14 0.000583277471058
1488 | 9 6 45 0.000406384681257
1489 | 37 19 4 0.000516540749585
1490 | 18 20 22 0.000618232740386
1491 | 8 24 28 0.000569654303715
1492 | 13 35 12 0.000525327868788
1493 | 35 8 17 0.000524024255459
1494 | 13 17 30 0.000574518286348
1495 | 7 1 52 0.000398085617614
1496 | 30 7 23 0.000559707654648
1497 | 33 6 21 0.000541807496111
1498 | 8 52 0 0.000523584874616
1499 | 1 0 59 0.000518034490428
1500 | 20 18 22 0.000618232740386
1501 | 47 8 5 0.000385449128184
1502 | 24 26 10 0.000582959937935
1503 | 5 16 39 0.00048723137665
1504 | 40 9 11 0.000465294284403
1505 | 3 5 52 0.000346374006092
1506 | 4 39 17 0.000494870083604
1507 | 45 8 7 0.000404493816949
1508 | 2 21 37 0.000553774587906
1509 | 11 11 38 0.000489774401922
1510 | 16 10 34 0.000535133560842
1511 | 51 3 6 0.000355326542624
1512 | 11 46 3 0.000417114121438
1513 | 8 23 29 0.000566517703157
1514 | 19 24 17 0.000612777218961
1515 | 23 31 6 0.000553894267806
1516 | 22 23 15 0.000609861242306
1517 | 12 44 4 0.000431349703568
1518 | 41 10 9 0.000452685505882
1519 | 42 7 11 0.000442181806539
1520 | 12 24 24 0.000595279433757
1521 | 3 50 7 0.000365979242514
1522 | 24 25 11 0.000589362493229
1523 | 5 1 54 0.000376584228843
1524 | 15 29 16 0.000584054427249
1525 | 27 14 19 0.000595523628638
1526 | 4 38 18 0.000506078605648
1527 | 17 7 36 0.000514274201223
1528 | 35 24 1 0.000623793059998
1529 | 49 7 4 0.00036776787047
1530 | 28 26 6 0.000563205272437
1531 | 22 5 33 0.00054387644544
1532 | 14 35 11 0.000525103680786
1533 | 7 13 40 0.000467731273606
1534 | 36 11 13 0.000513742592469
1535 | 41 7 12 0.000455032512107
1536 | 40 15 5 0.000475193799381
1537 | 2 49 9 0.000397579514036
1538 | 2 58 0 0.000481572115707
1539 | 46 5 9 0.000397766746838
1540 | 31 29 0 0.000820418017588
1541 | 13 41 6 0.000457900975492
1542 | 6 8 46 0.000394128000967
1543 | 11 23 26 0.000588081747586
1544 | 5 18 37 0.000509461743506
1545 | 27 24 9 0.000576293331224
1546 | 26 33 1 0.00063616965736
1547 | 4 37 19 0.000516540749585
1548 | 45 10 5 0.000410563857799
1549 | 10 39 11 0.000477498435273
1550 | 54 5 1 0.000376584228843
1551 | 17 33 10 0.00054475886607
1552 | 14 41 5 0.000462688733129
1553 | 1 36 23 0.000615717503072
1554 | 29 3 28 0.000573094946374
1555 | 8 21 31 0.000556645045176
1556 | 2 48 10 0.000411225549409
1557 | 46 4 10 0.000404772750137
1558 | 54 2 4 0.000345614053259
1559 | 23 18 19 0.000616376538476
1560 | 26 7 27 0.000567205618363
1561 | 38 16 6 0.000494473283901
1562 | 34 13 13 0.000536521423079
1563 | 12 43 5 0.000436768161023
1564 | 3 30 27 0.000571817425947
1565 | 56 4 0 0.000473881568417
1566 | 35 12 13 0.000525327868788
1567 | 39 11 10 0.000477498435273
1568 | 18 39 3 0.000508163523847
1569 | 7 52 1 0.000398085617614
1570 | 25 11 24 0.000589362493229
1571 | 14 40 6 0.000470520169659
1572 | 26 18 16 0.000603713170637
1573 | 39 18 3 0.000508163523847
1574 | 40 13 7 0.000467731273606
1575 | 35 17 8 0.000524024255459
1576 | 15 38 7 0.000492102347195
1577 | 31 9 20 0.000558920375004
1578 | 11 33 16 0.000545892195496
1579 | 26 13 21 0.00059670199104
1580 | 25 21 14 0.000603091017132
1581 | 47 12 1 0.000470390572843
1582 | 11 21 28 0.000581741494327
1583 | 16 11 33 0.000545892195496
1584 | 5 20 35 0.000528571188991
1585 | 1 40 19 0.00057251691181
1586 | 34 12 14 0.000536349975984
1587 | 5 51 4 0.000348420109833
1588 | 56 3 1 0.000367461057285
1589 | 45 12 3 0.000430776639063
1590 | 9 13 38 0.000490157910944
1591 | 28 31 1 0.000643184095371
1592 | 21 1 38 0.000596129646217
1593 | 11 42 7 0.000442181806539
1594 | 6 2 52 0.000361360418101
1595 | 18 40 2 0.000520904307398
1596 | 30 18 12 0.000572833115344
1597 | 15 40 5 0.000475193799381
1598 | 10 9 41 0.000452685505882
1599 | 4 11 45 0.000418002012485
1600 | 12 48 0 0.000596634336102
1601 | 19 37 4 0.000516540749585
1602 | 28 30 2 0.000593470924499
1603 | 26 12 22 0.000592716196383
1604 | 3 52 5 0.000346374006092
1605 | 34 25 1 0.000630629627707
1606 | 34 2 24 0.00057791759599
1607 | 4 16 40 0.000483014315787
1608 | 27 10 23 0.000581049081881
1609 | 56 2 2 0.000349138531125
1610 | 39 9 12 0.000477841915704
1611 | 19 17 24 0.000612777218961
1612 | 19 6 35 0.000525503361058
1613 | 10 14 36 0.000513611204695
1614 | 10 26 24 0.000582959937935
1615 | 9 17 34 0.000534309679581
1616 | 7 5 48 0.000373883418934
1617 | 41 3 16 0.000484072500847
1618 | 20 4 36 0.000526164563267
1619 | 6 13 41 0.000457900975492
1620 | 49 9 2 0.000397579514036
1621 | 46 1 13 0.00048585847447
1622 | 0 14 46 0.000635017886853
1623 | 7 22 31 0.000554785832172
1624 | 8 3 49 0.000377801164992
1625 | 2 39 19 0.000532689007384
1626 | 44 4 12 0.000431349703568
1627 | 3 56 1 0.000367461057285
1628 | 34 24 2 0.00057791759599
1629 | 16 9 35 0.000524284544741
1630 | 5 22 33 0.00054387644544
1631 | 36 9 15 0.000513508110547
1632 | 22 1 37 0.000606470645494
1633 | 0 57 3 0.000472067807554
1634 | 8 38 14 0.000490815596489
1635 | 56 1 3 0.000367461057285
1636 | 45 14 1 0.000501256623742
1637 | 1 28 31 0.000643184095371
1638 | 47 5 8 0.000385449128184
1639 | 45 13 2 0.000453724638536
1640 | 37 9 14 0.000502091716183
1641 | 14 37 9 0.000502091716183
1642 | 4 26 30 0.000562177966124
1643 | 42 13 5 0.000449836829755
1644 | 4 9 47 0.000391839926085
1645 | 37 0 23 0.000780130337846
1646 | 46 0 14 0.000635017886853
1647 | 59 1 0 0.000518034490428
1648 | 20 19 21 0.000620024731277
1649 | 17 28 15 0.000591215071466
1650 | 32 8 20 0.000550001670772
1651 | 35 23 2 0.000570968029697
1652 | 22 4 34 0.00054256788204
1653 | 28 18 14 0.00058995627968
1654 | 15 23 22 0.000609861242306
1655 | 3 26 31 0.000569273557353
1656 | 29 6 25 0.000561326032631
1657 | 2 7 51 0.000372328832234
1658 | 19 15 26 0.000602275177782
1659 | 32 11 17 0.000555087730158
1660 | 11 9 40 0.000465294284403
1661 | 36 19 5 0.000519452341439
1662 | 29 16 15 0.000584054427249
1663 | 50 5 5 0.000354655431723
1664 | 23 0 37 0.000780130337846
1665 | 13 43 4 0.000444660026359
1666 | 44 15 1 0.000516443688638
1667 | 0 18 42 0.000708016814567
1668 | 55 3 2 0.000343377513917
1669 | 48 8 4 0.000379415766803
1670 | 9 28 23 0.000573763413236
1671 | 31 23 6 0.000553894267806
1672 | 8 1 51 0.000411152021077
1673 | 3 44 13 0.000444439223787
1674 | 7 43 10 0.000429342904055
1675 | 47 0 13 0.000615843998012
1676 | 21 13 26 0.00059670199104
1677 | 12 11 37 0.000501914704779
1678 | 21 5 34 0.000536736834183
1679 | 7 50 3 0.000365979242514
1680 | 1 30 29 0.000644598993328
1681 | 29 11 20 0.000576745146519
1682 | 28 3 29 0.000573094946374
1683 | 21 32 7 0.000548719190895
1684 | 36 8 16 0.000513625240855
1685 | 51 1 8 0.000411152021077
1686 | 36 18 6 0.000515949173091
1687 | 50 4 6 0.000357258223823
1688 | 40 8 12 0.000466122480142
1689 | 19 16 25 0.000608054593057
1690 | 23 7 30 0.000559707654648
1691 | 22 31 7 0.000554785832172
1692 | 7 8 45 0.000404493816949
1693 | 37 2 21 0.000553774587906
1694 | 2 44 14 0.00046787785258
1695 | 44 5 11 0.000423624580479
1696 | 24 35 1 0.000623793059998
1697 | 25 31 4 0.000559052024715
1698 | 47 10 3 0.000403607001432
1699 | 17 30 13 0.000574518286348
1700 | 17 43 0 0.000690632698311
1701 | 34 6 20 0.00053414903673
1702 | 12 1 47 0.000470390572843
1703 | 2 30 28 0.000593470924499
1704 | 26 5 29 0.000561048821157
1705 | 35 16 9 0.000524284544741
1706 | 6 44 10 0.000419094260354
1707 | 19 2 39 0.000532689007384
1708 | 28 2 30 0.000593470924499
1709 | 5 31 24 0.000554832508077
1710 | 7 3 50 0.000365979242514
1711 | 0 15 45 0.00065398171375
1712 | 7 21 32 0.000548719190895
1713 | 36 17 7 0.000514274201223
1714 | 29 18 13 0.000581753357221
1715 | 12 8 40 0.000466122480142
1716 | 40 7 13 0.000467731273606
1717 | 2 57 1 0.000373898666741
1718 | 12 33 15 0.000546726531298
1719 | 9 48 3 0.000390432381229
1720 | 55 1 4 0.000369686093265
1721 | 9 30 21 0.000565035203114
1722 | 15 14 31 0.00056690063487
1723 | 24 34 2 0.00057791759599
1724 | 7 41 12 0.000455032512107
1725 | 44 8 8 0.000415957532029
1726 | 44 3 13 0.000444439223787
1727 | 5 23 32 0.000549926340121
1728 | 20 40 0 0.000740199339251
1729 | 43 1 16 0.00053128655342
1730 | 8 22 30 0.000562167683825
1731 | 4 34 22 0.00054256788204
1732 | 16 6 38 0.000494473283901
1733 | 5 27 28 0.000562303307602
1734 | 28 1 31 0.000643184095371
1735 | 21 34 5 0.000536736834183
1736 | 14 33 13 0.000547166402343
1737 | 27 5 28 0.000562303307602
1738 | 6 3 51 0.000355326542624
1739 | 40 6 14 0.000470520169659
1740 | 15 6 39 0.000482751300565
1741 | 2 56 2 0.000349138531125
1742 | 16 18 26 0.000603713170637
1743 | 37 4 19 0.000516540749585
1744 | 1 1 58 0.000400921212213
1745 | 24 33 3 0.000560486469349
1746 | 11 4 45 0.000418002012485
1747 | 43 7 10 0.000429342904055
1748 | 5 41 14 0.000462688733129
1749 | 22 0 38 0.000768085194696
1750 | 10 46 4 0.000404772750137
1751 | 33 13 14 0.000547166402343
1752 | 27 0 33 0.000813515266876
1753 | 17 0 43 0.000690632698311
1754 | 10 37 13 0.000501947385234
1755 | 9 45 6 0.000406384681257
1756 | 19 11 30 0.00057059401282
1757 | 32 17 11 0.000555087730158
1758 | 5 32 23 0.000549926340121
1759 | 14 32 14 0.000557395520244
1760 | 0 13 47 0.000615843998012
1761 | 26 17 17 0.000604196392016
1762 | 36 23 1 0.000615717503072
1763 | 29 20 11 0.000576745146519
1764 | 40 5 15 0.000475193799381
1765 | 23 4 33 0.000549203580748
1766 | 38 4 18 0.000506078605648
1767 | 12 39 9 0.000477841915704
1768 | 9 50 1 0.000425176279456
1769 | 6 47 7 0.000382603299343
1770 | 31 1 28 0.000643184095371
1771 | 7 12 41 0.000455032512107
1772 | 11 41 8 0.000453414475786
1773 | 38 18 4 0.000506078605648
1774 | 37 10 13 0.000501947385234
1775 | 40 19 1 0.00057251691181
1776 | 44 12 4 0.000431349703568
1777 | 25 13 22 0.00059925571499
1778 | 47 4 9 0.000391839926085
1779 | 11 29 20 0.000576745146519
1780 | 33 27 0 0.000813515266876
1781 | 30 9 21 0.000565035203114
1782 | 3 25 32 0.000565485562125
1783 | 35 14 11 0.000525103680786
1784 | 41 1 18 0.000559440397503
1785 | 10 36 14 0.000513611204695
1786 | 28 7 25 0.000565946301449
1787 | 21 36 3 0.000538706957448
1788 | 16 40 4 0.000483014315787
1789 | 26 16 18 0.000603713170637
1790 | 7 30 23 0.000559707654648
1791 | 36 22 2 0.000562897480566
1792 | 2 4 54 0.000345614053259
1793 | 15 32 13 0.000557125584217
1794 | 6 28 26 0.000563205272437
1795 | 12 38 10 0.000489858926854
1796 | 37 6 17 0.000505573889982
1797 | 12 6 42 0.000445024944313
1798 | 12 30 18 0.000572833115344
1799 | 30 26 4 0.000562177966124
1800 | 26 4 30 0.000562177966124
1801 | 40 14 6 0.000470520169659
1802 | 43 5 12 0.000436768161023
1803 | 34 10 16 0.000535133560842
1804 | 58 2 0 0.000481572115707
1805 | 4 40 16 0.000483014315787
1806 | 42 16 2 0.000495347908903
1807 | 15 35 10 0.000524714144684
1808 | 4 50 6 0.000357258223823
1809 | 17 2 41 0.000508422014232
1810 | 18 36 6 0.000515949173091
1811 | 8 11 41 0.000453414475786
1812 | 0 17 43 0.000690632698311
1813 | 5 34 21 0.000536736834183
1814 | 32 10 18 0.000553490763168
1815 | 27 1 32 0.000640366337092
1816 | 39 6 15 0.000482751300565
1817 | 36 21 3 0.000538706957448
1818 | 29 22 9 0.000569998719715
1819 | 15 42 3 0.000471212939884
1820 | 0 28 32 0.000817820521541
1821 | 34 23 3 0.000554319763761
1822 | 3 48 9 0.000390432381229
1823 | 34 0 26 0.000807537834977
1824 | 24 12 24 0.000595279433757
1825 | 0 8 52 0.000523584874616
1826 | 19 7 34 0.000533385575385
1827 | 4 49 7 0.00036776787047
1828 | 25 24 11 0.000589362493229
1829 | 20 12 28 0.00058513062186
1830 | 19 8 33 0.00054230015282
1831 | 16 20 24 0.00061119221221
1832 | 8 43 9 0.000428118760096
1833 | 21 38 1 0.000596129646217
1834 | 60 0 0 0.000672927508895
1835 | 54 6 0 0.000493456285536
1836 | 2 51 7 0.000372328832234
1837 | 34 14 12 0.000536349975984
1838 | 28 25 7 0.000565946301449
1839 | 30 14 16 0.000575562514854
1840 | 15 13 32 0.000557125584217
1841 | 43 3 14 0.000457961301012
1842 | 5 45 10 0.000410563857799
1843 | 12 18 30 0.000572833115344
1844 | 23 15 22 0.000609861242306
1845 | 33 16 11 0.000545892195496
1846 | 14 23 23 0.0006056501852
1847 | 6 29 25 0.000561326032631
1848 | 22 32 6 0.000548409201255
1849 | 54 1 5 0.000376584228843
1850 | 8 42 10 0.000440682063633
1851 | 5 36 19 0.000519452341439
1852 | 26 14 20 0.000599917880717
1853 | 22 30 8 0.000562167683825
1854 | 29 24 7 0.000563439276973
1855 | 0 38 22 0.000768085194696
1856 | 42 18 0 0.000708016814567
1857 | 49 5 6 0.000363438071327
1858 | 22 37 1 0.000606470645494
1859 | 0 26 34 0.000807537834977
1860 | 1 45 14 0.000501256623742
1861 | 9 20 31 0.000558920375004
1862 | 6 0 54 0.000493456285536
1863 | 30 23 7 0.000559707654648
1864 | 44 16 0 0.00067257173668
1865 | 16 5 39 0.00048723137665
1866 | 24 10 26 0.000582959937935
1867 | 7 17 36 0.000514274201223
1868 | 3 21 36 0.000538706957448
1869 | 35 10 15 0.000524714144684
1870 | 4 55 1 0.000369686093265
1871 | 25 26 9 0.000577564346527
1872 | 2 5 53 0.000352159833508
1873 | 2 22 36 0.000562897480566
1874 | 38 14 8 0.000490815596489
1875 | 38 21 1 0.000596129646217
1876 | 8 41 11 0.000453414475786
1877 | 36 0 24 0.00079077667923
1878 | 1 23 36 0.000615717503072
1879 | 28 9 23 0.000573763413236
1880 | 23 2 35 0.000570968029697
1881 | 40 0 20 0.000740199339251
1882 | 15 36 9 0.000513508110547
1883 | 22 9 29 0.000569998719715
1884 | 12 42 6 0.000445024944313
1885 | 8 12 40 0.000466122480142
1886 | 7 10 43 0.000429342904055
1887 | 42 17 1 0.000545658867504
1888 | 3 46 11 0.000417114121438
1889 | 25 23 12 0.000594636992935
1890 | 47 2 11 0.000425247956462
1891 | 24 31 5 0.000554832508077
1892 |
--------------------------------------------------------------------------------
/examples/sample_data/scatter_colorbar.txt:
--------------------------------------------------------------------------------
1 | -3.5516350089 -3.768116 [1, 0, 0]
2 | -3.6107113221 -3.7428188 [0, 1, 0]
3 | -5.5340766951 -5.6648602 [0, 0, 1]
4 | -3.8885230693 -3.8800445 [1, 1, 0]
5 | -5.1831640024 -5.3274035 [1, 0, 1]
6 | -4.5860779101 -4.63911865 [0, 1, 1]
7 | -3.8582884462 -3.80612533333 [2, 1, 0]
8 | -4.8246118011 -4.74736266667 [2, 0, 1]
9 | -3.9374442451 -3.927809 [1, 2, 0]
10 | -4.7107623548 -4.69750666667 [1, 1, 1]
11 | -5.4847222747 -5.41731266667 [1, 0, 2]
12 | -4.299050653 -4.32673233333 [0, 2, 1]
13 | -4.9278056438 -4.91713166667 [0, 1, 2]
14 | -3.7918765121 -3.77761425 [3, 1, 0]
15 | -3.9334829147 -3.87298 [2, 2, 0]
16 | -5.2930576848 -5.2492885 [2, 0, 2]
17 | -4.6020280147 -4.62266175 [0, 2, 2]
18 | -4.1732688356 -4.1810615 [0, 3, 1]
19 | -5.0812068962 -5.07164775 [0, 1, 3]
20 | -4.5908249024 -4.4235635 [3, 0, 1]
21 | -4.6292620683 -4.6366255 [2, 1, 1]
22 | -3.9330784897 -3.90738275 [1, 3, 0]
23 | -4.5075466764 -4.48218575 [1, 2, 1]
24 | -5.0790857704 -5.05795275 [1, 1, 2]
25 | -5.5859055259 -5.55121625 [1, 0, 3]
26 | -3.7297509817 -3.7711188 [4, 1, 0]
27 | -4.3513002862 -4.3223486 [4, 0, 1]
28 | -3.8810894808 -3.8212586 [3, 2, 0]
29 | -4.4325382428 -4.3894644 [3, 1, 1]
30 | -4.9762728808 -4.9188892 [3, 0, 2]
31 | -4.4666296158 -4.4877356 [2, 2, 1]
32 | -4.9523843543 -4.953122 [2, 1, 2]
33 | -5.3610469718 -5.392246 [2, 0, 3]
34 | -4.7204991847 -4.7393156 [1, 2, 2]
35 | -4.0430221394 -4.089954 [0, 4, 1]
36 | -4.4284726916 -4.4518532 [0, 3, 2]
37 | -4.8039206658 -4.8049582 [0, 2, 3]
38 | -5.1665783768 -5.1565688 [0, 1, 4]
39 | -3.9482746053 -3.9075942 [2, 3, 0]
40 | -3.8801324223 -3.8785168 [1, 4, 0]
41 | -4.3048528253 -4.2988998 [1, 3, 1]
42 | -5.1075585164 -5.1256452 [1, 1, 3]
43 | -5.4955264297 -5.5354066 [1, 0, 4]
44 | -3.708404418 -3.770192 [5, 1, 0]
45 | -4.2566357209 -4.19883733333 [5, 0, 1]
46 | -3.8666678803 -3.805213 [4, 2, 0]
47 | -4.7813491745 -4.69178716667 [4, 0, 2]
48 | -4.8324965613 -4.798458 [3, 1, 2]
49 | -5.2610223833 -5.266337 [3, 0, 3]
50 | -4.3571877153 -4.259283 [4, 1, 1]
51 | -3.946121769 -3.85589233333 [3, 3, 0]
52 | -4.3979912932 -4.39659016667 [3, 2, 1]
53 | -3.9578580089 -3.921597 [2, 4, 0]
54 | -4.3509212964 -4.33789166667 [2, 3, 1]
55 | -3.8646628238 -3.85115833333 [1, 5, 0]
56 | -4.210446155 -4.20694483333 [1, 4, 1]
57 | -4.7460561247 -4.73313233333 [2, 2, 2]
58 | -5.138545099 -5.133973 [2, 1, 3]
59 | -5.4497436201 -5.47727483333 [2, 0, 4]
60 | -4.5920429908 -4.55728516667 [1, 3, 2]
61 | -4.9261615845 -4.90742216667 [1, 2, 3]
62 | -5.2381707853 -5.20405283333 [1, 1, 4]
63 | -5.5474766625 -5.5434185 [1, 0, 5]
64 | -3.9931738718 -4.03026933333 [0, 5, 1]
65 | -4.3195665973 -4.33611783333 [0, 4, 2]
66 | -4.6222877542 -4.62166833333 [0, 3, 3]
67 | -4.9277442522 -4.91617566667 [0, 2, 4]
68 | -5.243250382 -5.2117395 [0, 1, 5]
69 | -3.6824641556 -3.767123 [6, 1, 0]
70 | -3.821406806 -3.79040471429 [5, 2, 0]
71 | -4.2361902594 -4.16207571429 [5, 1, 1]
72 | -4.6430350904 -4.54129057143 [5, 0, 2]
73 | -3.9048545745 -3.83878885714 [4, 3, 0]
74 | -4.3214478923 -4.225693 [4, 2, 1]
75 | -4.7235312799 -4.621964 [4, 1, 2]
76 | -5.0935793702 -5.031116 [4, 0, 3]
77 | -4.3060264808 -4.32989314286 [3, 3, 1]
78 | -3.9231867574 -3.91952857143 [2, 5, 0]
79 | -4.6798717775 -4.72529871429 [3, 2, 2]
80 | -4.2483479041 -4.25536642857 [2, 4, 1]
81 | -4.5785846185 -4.58113271429 [2, 3, 2]
82 | -5.0294657739 -4.98922357143 [3, 1, 3]
83 | -4.4343518764 -4.41991885714 [1, 4, 2]
84 | -5.1925500978 -5.17112471429 [2, 1, 4]
85 | -5.3711010531 -5.300876 [3, 0, 4]
86 | -4.9012181941 -4.90228271429 [2, 2, 3]
87 | -4.7115376705 -4.71086828571 [1, 3, 3]
88 | -5.2705792795 -5.27069971429 [1, 1, 5]
89 | -5.4850641336 -5.47430714286 [2, 0, 5]
90 | -4.9931658559 -4.99310914286 [1, 2, 4]
91 | -5.542442371 -5.54071371429 [1, 0, 6]
92 | -4.2213694583 -4.243943 [0, 5, 2]
93 | -4.4836834514 -4.49826414286 [0, 4, 3]
94 | -4.7457815334 -4.74761871429 [0, 3, 4]
95 | -5.0105503028 -5.00489371429 [0, 2, 5]
96 | -5.2735987484 -5.25585914286 [0, 1, 6]
97 | -4.1618604201 -4.136912 [6, 0, 1]
98 | -3.9430561929 -3.890784 [3, 4, 0]
99 | -3.8291959782 -3.833868 [1, 6, 0]
100 | -4.1304575436 -4.12222142857 [1, 5, 1]
101 | -3.9333869526 -3.98696685714 [0, 6, 1]
102 | -4.2487402217 -4.153603875 [5, 2, 1]
103 | -4.952668382 -4.9254345 [4, 1, 3]
104 | -4.9215743661 -4.9020525 [5, 0, 3]
105 | -5.2346015584 -5.281576 [4, 0, 4]
106 | -4.1730112808 -4.180098125 [0, 6, 2]
107 | -3.6651610987 -3.763555375 [7, 1, 0]
108 | -4.0897470008 -4.079031125 [7, 0, 1]
109 | -3.7928842444 -3.78196675 [6, 2, 0]
110 | -4.5431993652 -4.427433125 [6, 0, 2]
111 | -5.4194545677 -5.4114045 [3, 0, 5]
112 | -3.9172533636 -3.912145125 [2, 6, 0]
113 | -4.8032931608 -4.76755925 [2, 3, 3]
114 | -4.8423787783 -4.847835375 [1, 3, 4]
115 | -5.0674290296 -5.045691875 [2, 2, 4]
116 | -5.5703108204 -5.5460685 [2, 0, 6]
117 | -5.0958702405 -5.069048625 [1, 2, 5]
118 | -5.3320782195 -5.30919925 [1, 1, 6]
119 | -5.5572163162 -5.543709875 [1, 0, 7]
120 | -4.2880057945 -4.2057985 [4, 3, 1]
121 | -4.2796218857 -4.26705175 [3, 4, 1]
122 | -4.6489074692 -4.557628625 [4, 2, 2]
123 | -3.9419127464 -3.873263375 [4, 4, 0]
124 | -4.5934617794 -4.56407125 [3, 3, 2]
125 | -3.8055462989 -3.8189175 [1, 7, 0]
126 | -4.360901065 -4.334686125 [1, 5, 2]
127 | -4.6172633318 -4.58989425 [1, 4, 3]
128 | -5.3349605533 -5.301304125 [2, 1, 5]
129 | -4.4067338525 -4.392397 [0, 5, 3]
130 | -5.0951323456 -5.064469625 [0, 2, 6]
131 | -5.3205431851 -5.28996125 [0, 1, 7]
132 | -3.8766945586 -3.81710175 [5, 3, 0]
133 | -4.6177314437 -4.49004075 [5, 1, 2]
134 | -3.9612502519 -3.93056025 [3, 5, 0]
135 | -4.877751374 -4.87929125 [3, 2, 3]
136 | -5.1647158882 -5.185500375 [3, 1, 4]
137 | -4.2108244985 -4.093884625 [6, 1, 1]
138 | -4.2451328699 -4.192140375 [2, 5, 1]
139 | -4.0840207737 -4.0766765 [1, 6, 1]
140 | -4.5391462861 -4.473015625 [2, 4, 2]
141 | -3.9040675 -3.957148625 [0, 7, 1]
142 | -4.6302034172 -4.62012425 [0, 4, 4]
143 | -4.8565778696 -4.83882625 [0, 3, 5]
144 | -4.105224808 -4.07548155556 [7, 1, 1]
145 | -4.545368994 -4.45389666667 [5, 2, 2]
146 | -4.192665009 -4.10639533333 [6, 2, 1]
147 | -4.2313633469 -4.152341 [5, 3, 1]
148 | -4.5120032813 -4.42059611111 [6, 1, 2]
149 | -4.8213015828 -4.79074833333 [5, 1, 3]
150 | -5.117983255 -5.06511455556 [5, 0, 4]
151 | -5.0865049862 -5.03806033333 [4, 1, 4]
152 | -5.341372146 -5.27398855556 [4, 0, 5]
153 | -4.23136069 -4.24106344444 [4, 4, 1]
154 | -4.2102926569 -4.20981666667 [3, 5, 1]
155 | -4.5411577195 -4.50239366667 [4, 3, 2]
156 | -4.8150452306 -4.78662922222 [4, 2, 3]
157 | -4.140938015 -4.143179 [2, 6, 1]
158 | -4.4818943853 -4.48634766667 [3, 4, 2]
159 | -4.7327143393 -4.72855277778 [3, 3, 3]
160 | -4.6301308171 -4.60341377778 [2, 4, 3]
161 | -4.8570307462 -4.83371088889 [2, 3, 4]
162 | -5.4489284495 -5.433402 [3, 0, 6]
163 | -5.0831662949 -5.06704666667 [2, 2, 5]
164 | -4.2600740853 -4.26405844444 [1, 6, 2]
165 | -4.4911390658 -4.48037022222 [1, 5, 3]
166 | -4.9232335991 -4.90755622222 [1, 3, 5]
167 | -5.3234106221 -5.27473244444 [2, 1, 6]
168 | -5.1422572155 -5.11832088889 [1, 2, 6]
169 | -5.5170549971 -5.535185 [2, 0, 7]
170 | -4.1010181405 -4.13031788889 [0, 7, 2]
171 | -4.3116469457 -4.33175455556 [0, 6, 3]
172 | -4.7778220934 -4.72123922222 [6, 0, 3]
173 | -3.7636979584 -3.78582055556 [7, 2, 0]
174 | -3.8636435771 -3.92726666667 [0, 8, 1]
175 | -3.6588423313 -3.75984977778 [8, 1, 0]
176 | -4.9967811284 -4.94089511111 [3, 2, 4]
177 | -5.2326038894 -5.18279355556 [3, 1, 5]
178 | -4.929002684 -4.92638455556 [0, 3, 6]
179 | -5.1395555635 -5.11683211111 [0, 2, 7]
180 | -3.8685485938 -3.807925 [6, 3, 0]
181 | -3.9242897758 -3.83940233333 [5, 4, 0]
182 | -3.9544947102 -3.87116588889 [4, 5, 0]
183 | -3.9464346833 -3.91724733333 [3, 6, 0]
184 | -3.8946310949 -3.87697388889 [2, 7, 0]
185 | -3.7861327529 -3.809299 [1, 8, 0]
186 | -4.0230444758 -4.04966944444 [1, 7, 1]
187 | -5.3444573191 -5.32486422222 [1, 1, 7]
188 | -5.560463628 -5.53839922222 [1, 0, 8]
189 | -5.3453205825 -5.312919 [0, 1, 8]
190 | -4.0424099597 -4.04840922222 [8, 0, 1]
191 | -4.4286128245 -4.37175888889 [7, 0, 2]
192 | -4.3961630597 -4.32915844444 [2, 5, 2]
193 | -4.7259107426 -4.68479777778 [1, 4, 4]
194 | -4.534285475 -4.52679811111 [0, 5, 4]
195 | -4.7271667005 -4.72140277778 [0, 4, 5]
196 | -3.6435909094 -3.760073 [9, 1, 0]
197 | -3.9996042003 -4.015916 [9, 0, 1]
198 | -4.3885904124 -4.2951711 [8, 0, 2]
199 | -4.0640994132 -4.0328226 [8, 1, 1]
200 | -4.44451877 -4.3090425 [7, 1, 2]
201 | -4.70467933 -4.5776975 [7, 0, 3]
202 | -3.8979199858 -3.8279354 [6, 4, 0]
203 | -3.8369257454 -3.7923549 [7, 3, 0]
204 | -4.1534395836 -4.0514061 [7, 2, 1]
205 | -4.4735433051 -4.3638444 [6, 2, 2]
206 | -4.1864569052 -4.1016462 [6, 3, 1]
207 | -4.7438370198 -4.6562458 [6, 1, 3]
208 | -5.0261440811 -4.9780596 [5, 1, 4]
209 | -4.2133454559 -4.1478528 [5, 4, 1]
210 | -3.9459501045 -3.857769 [5, 5, 0]
211 | -4.7504373666 -4.732628 [5, 2, 3]
212 | -4.7200564402 -4.6931144 [4, 3, 3]
213 | -5.0117869191 -4.9476955 [6, 0, 4]
214 | -5.2739664681 -5.2601815 [5, 0, 5]
215 | -4.964407793 -4.9201717 [4, 2, 4]
216 | -5.185598455 -5.1383469 [4, 1, 5]
217 | -5.4030275493 -5.3484978 [4, 0, 6]
218 | -4.4895889532 -4.4942395 [5, 3, 2]
219 | -3.9540494155 -3.9002677 [4, 6, 0]
220 | -4.2161238613 -4.2059649 [4, 5, 1]
221 | -3.9414873653 -3.9179358 [3, 7, 0]
222 | -4.1884765655 -4.159668 [3, 6, 1]
223 | -4.426767754 -4.3906296 [3, 5, 2]
224 | -4.6643195966 -4.6339868 [3, 4, 3]
225 | -4.4795315652 -4.4284201 [4, 4, 2]
226 | -4.1081284559 -4.1001906 [2, 7, 1]
227 | -4.3442679341 -4.3278547 [2, 6, 2]
228 | -3.8834702602 -3.8625704 [2, 8, 0]
229 | -3.7679284153 -3.8004972 [1, 9, 0]
230 | -3.987720645 -4.0032055 [1, 8, 1]
231 | -4.2116871002 -4.2074086 [1, 7, 2]
232 | -4.5538262199 -4.5415542 [2, 5, 3]
233 | -4.421069784 -4.4124556 [1, 6, 3]
234 | -4.7766512192 -4.7638867 [2, 4, 4]
235 | -4.8071062715 -4.7907832 [1, 4, 5]
236 | -4.9059481624 -4.8670905 [3, 3, 4]
237 | -5.1230877936 -5.1050966 [3, 2, 5]
238 | -5.3151503049 -5.301167 [3, 1, 6]
239 | -5.5152406939 -5.5064975 [3, 0, 7]
240 | -4.9886727321 -4.9664374 [2, 3, 5]
241 | -5.1855161713 -5.1655773 [2, 2, 6]
242 | -5.3847725964 -5.3546898 [2, 1, 7]
243 | -5.5678785704 -5.553211 [2, 0, 8]
244 | -4.6236277205 -4.6126109 [1, 5, 4]
245 | -5.000524251 -4.9895405 [1, 3, 6]
246 | -5.1859859009 -5.1652321 [1, 2, 7]
247 | -5.3699546348 -5.3515233 [1, 1, 8]
248 | -5.5588069415 -5.537609 [1, 0, 9]
249 | -3.8430157026 -3.9082544 [0, 9, 1]
250 | -4.0712627937 -4.0913811 [0, 8, 2]
251 | -4.2612089647 -4.2733476 [0, 7, 3]
252 | -4.63025218 -4.6195317 [0, 5, 5]
253 | -4.4431625742 -4.4452638 [0, 6, 4]
254 | -4.8072700784 -4.7991914 [0, 4, 6]
255 | -4.9901734373 -4.9791327 [0, 3, 7]
256 | -5.1760767041 -5.1549013 [0, 2, 8]
257 | -5.3553312283 -5.3348554 [0, 1, 9]
258 | -3.7397625478 -3.7747771 [8, 2, 0]
259 |
--------------------------------------------------------------------------------
/examples/scatter_colorbar.py:
--------------------------------------------------------------------------------
1 | """An example of the colorbar display on the scatter plot."""
2 | import ternary
3 | import matplotlib.pyplot as plt
4 |
5 |
6 | def _en_to_enth(energy, concs, A, B, C):
7 | """Converts an energy to an enthalpy.
8 |
9 | Converts energy to enthalpy using the following formula:
10 | Enthalpy = energy - (energy contribution from A) - (energy contribution from B) -
11 | (energy contribution from C)
12 | An absolute value is taken afterward for convenience.
13 |
14 | Parameters
15 | ----------
16 | energy : float
17 | The energy of the structure
18 | concs : list of floats
19 | The concentrations of each element
20 | A : float
21 | The energy of pure A
22 | B : float
23 | The energy of pure B
24 | C : float
25 | The energy of pure C
26 |
27 | Returns
28 | -------
29 | enth : float
30 | The enthalpy of formation.
31 | """
32 |
33 | enth = abs(energy - concs[0]*A - concs[1] * B - concs[2] * C)
34 | return enth
35 |
36 |
37 | def _energy_to_enthalpy(energy):
38 | """Converts energy to enthalpy.
39 |
40 | This function take the energies stored in the energy array and
41 | converts them to formation enthalpy.
42 |
43 | Parameters
44 | ---------
45 | energy : list of lists of floats
46 |
47 | Returns
48 | -------
49 | enthalpy : list of lists containing the enthalpies.
50 | """
51 |
52 | pureA = [energy[0][0], energy[0][1]]
53 | pureB = [energy[1][0], energy[1][1]]
54 | pureC = [energy[2][0], energy[2][1]]
55 |
56 | enthalpy = []
57 | for en in energy:
58 | c = en[2]
59 | conc = [float(i) / sum(c) for i in c]
60 |
61 | CE = _en_to_enth(en[0], conc, pureA[0], pureB[0], pureC[0])
62 | VASP = _en_to_enth(en[1], conc, pureA[1], pureB[1], pureC[1])
63 |
64 | enthalpy.append([CE, VASP, c])
65 |
66 | return enthalpy
67 |
68 |
69 | def _find_error(vals):
70 | """Find the errors in the energy values.
71 |
72 | This function finds the errors in the enthalpys.
73 |
74 | Parameters
75 | ----------
76 | vals : list of lists of floats
77 |
78 | Returns
79 | -------
80 | err_vals : list of lists containing the errors.
81 | """
82 |
83 | err_vals = []
84 | for en in vals:
85 | c = en[2]
86 | conc = [float(i) / sum(c) for i in c]
87 |
88 | err = abs(en[0] - en[1])
89 |
90 | err_vals.append([conc, err])
91 |
92 | return err_vals
93 |
94 |
95 | def _read_data(fname):
96 | """Reads data from file.
97 |
98 | Reads the data in 'fname' into a list where each list entry contains
99 | [energy predicted, energy calculated, list of concentrations].
100 |
101 | Parameters
102 | ----------
103 | fname : str
104 | The name and path to the data file.
105 |
106 | Returns
107 | -------
108 | energy : list of lists of floats
109 | A list of the energies and the concentrations.
110 | """
111 |
112 | energy = []
113 | with open(fname,'r') as f:
114 | for line in f:
115 | CE = abs(float(line.strip().split()[0]))
116 | VASP = abs(float(line.strip().split()[1]))
117 | conc = [i for i in line.strip().split()[2:]]
118 |
119 | conc_f = []
120 | for c in conc:
121 | if '[' in c and ']' in c:
122 | conc_f.append(int(c[1:-1]))
123 | elif '[' in c:
124 | conc_f.append(int(c[1:-1]))
125 | elif ']' in c or ',' in c:
126 | conc_f.append(int(c[:-1]))
127 | else:
128 | conc_f.append(int(c))
129 | energy.append([CE, VASP, conc_f])
130 | return energy
131 |
132 |
133 | def conc_err_plot(fname):
134 | """Plots the error in the CE data.
135 |
136 | This plots the error in the CE predictions within a ternary concentration diagram.
137 |
138 | Parameters
139 | ----------
140 | fname : string containing the input file name.
141 | """
142 |
143 | energies = _read_data(fname)
144 | enthalpy = _energy_to_enthalpy(energies)
145 | this_errors = _find_error(enthalpy)
146 |
147 | points = []
148 | colors = []
149 | for er in this_errors:
150 | concs = er[0]
151 | points.append((concs[0] * 100, concs[1] * 100, concs[2] * 100))
152 | colors.append(er[1])
153 |
154 | scale = 100
155 | figure, tax = ternary.figure(scale=scale)
156 | tax.boundary(linewidth=1.0)
157 | tax.set_title("Errors in Convex Hull Predictions.", fontsize=20)
158 | tax.gridlines(multiple=10, color="blue")
159 | tax.scatter(points, vmax=max(colors), colormap=plt.cm.viridis, colorbar=True, c=colors, cmap=plt.cm.viridis)
160 |
161 | tax.show()
162 |
163 |
164 | if __name__ == "__main__":
165 | conc_err_plot('sample_data/scatter_colorbar.txt')
166 |
--------------------------------------------------------------------------------
/examples/ternary_contours.py:
--------------------------------------------------------------------------------
1 | """ Compute ternary contours using matplotlib.pyplot.contour function """
2 | import numpy as np
3 | import matplotlib.pyplot as plt
4 | import ternary
5 | import math
6 | import itertools
7 |
8 |
9 | def shannon_entropy(p):
10 | """Computes the Shannon Entropy at a distribution in the simplex."""
11 | s = 0.
12 | for i in range(len(p)):
13 | try:
14 | s += p[i] * math.log(p[i])
15 | except ValueError:
16 | continue
17 | return -1. * s
18 |
19 | scale = 20
20 | level = [0.25, 0.5, 0.8, 0.9] # values for contours
21 |
22 | # === prepare coordinate list for contours
23 | x_range = np.arange(0, 1.01, 0.01) # ensure that grid spacing is small enough to get smooth contours
24 | coordinate_list = np.asarray(list(itertools.product(x_range, repeat=2)))
25 | coordinate_list = np.append(coordinate_list, (1 - coordinate_list[:, 0] - coordinate_list[:, 1]).reshape(-1, 1), axis=1)
26 |
27 | # === calculate data with coordinate list
28 | data_list = []
29 | for point in coordinate_list:
30 | data_list.append(shannon_entropy(point))
31 | data_list = np.asarray(data_list)
32 | data_list[np.sum(coordinate_list[:, 0:2], axis=1) > 1] = np.nan # remove data outside triangle
33 |
34 | # === reshape coordinates and data for use with pyplot contour function
35 | x = coordinate_list[:, 0].reshape(x_range.shape[0], -1)
36 | y = coordinate_list[:, 1].reshape(x_range.shape[0], -1)
37 |
38 | h = data_list.reshape(x_range.shape[0], -1)
39 |
40 | # === use pyplot to calculate contours
41 | contours = plt.contour(x, y, h, level) # this needs to be BEFORE figure definition
42 | plt.clf() # makes sure that contours are not plotted in carthesian plot
43 |
44 | fig, tax = ternary.figure(scale=scale)
45 |
46 | # === plot contour lines
47 | for ii, contour in enumerate(contours.allsegs):
48 | for jj, seg in enumerate(contour):
49 | tax.plot(seg[:, 0:2] * scale, color='r')
50 |
51 | # === plot regular data
52 | tax.heatmapf(shannon_entropy, boundary=True, style='hexagonal', colorbar=True)
53 |
54 | plt.show()
55 |
--------------------------------------------------------------------------------
/readme_images/16_80_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/16_80_1.png
--------------------------------------------------------------------------------
/readme_images/16_80_stationary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/16_80_stationary.png
--------------------------------------------------------------------------------
/readme_images/23_80_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/23_80_0.png
--------------------------------------------------------------------------------
/readme_images/24_80_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/24_80_1.png
--------------------------------------------------------------------------------
/readme_images/boundary_and_gridlines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/boundary_and_gridlines.png
--------------------------------------------------------------------------------
/readme_images/btweinstein_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/btweinstein_example.png
--------------------------------------------------------------------------------
/readme_images/btweinstein_example2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/btweinstein_example2.png
--------------------------------------------------------------------------------
/readme_images/colored_boundary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/colored_boundary.png
--------------------------------------------------------------------------------
/readme_images/colored_trajectory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/colored_trajectory.png
--------------------------------------------------------------------------------
/readme_images/heatmap-dual_vs_triangular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/heatmap-dual_vs_triangular.png
--------------------------------------------------------------------------------
/readme_images/heatmap-dualtriangular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/heatmap-dualtriangular.png
--------------------------------------------------------------------------------
/readme_images/heatmap-grids.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/heatmap-grids.png
--------------------------------------------------------------------------------
/readme_images/heatmap-triangular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/heatmap-triangular.png
--------------------------------------------------------------------------------
/readme_images/heatmap_rsp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/heatmap_rsp.png
--------------------------------------------------------------------------------
/readme_images/heatmap_shannon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/heatmap_shannon.png
--------------------------------------------------------------------------------
/readme_images/heatmap_styles.py:
--------------------------------------------------------------------------------
1 | from __future__ import division
2 |
3 | import matplotlib as mpl
4 | import matplotlib.pyplot as plt
5 | import numpy as np
6 |
7 | import ternary
8 |
9 | SQRT3OVER2 = np.sqrt(3) / 2
10 |
11 | def project(p):
12 | # project using the same transformation that was used for the triangles
13 | a, b, c = p
14 | x = a/2 + b
15 | y = SQRT3OVER2 * a
16 | return (x, y)
17 |
18 | def matplotlib_plot(scale, cmap, filename=None):
19 |
20 | points = list(ternary.helpers.simplex_iterator(scale))
21 | xs, ys = zip(*map(project, points))
22 | values = range(len(points))
23 |
24 | f, axes = plt.subplots(1,3, figsize=(8.5, 4.5))
25 |
26 | styles = ['triangular', 'dual-triangular', 'hexagonal']
27 | ticks_list = [range(scale + 1), range(scale + 2), range(scale + 1)]
28 | shift = True
29 | for ax, style, ticks in zip(axes, styles, ticks_list):
30 | ax.set_aspect('equal')
31 | ax.set_title(style)
32 | ternary.heatmap(dict(zip(points, values)),
33 | scale=scale, ax=ax,
34 | cmap=cmap, vmax=len(points) + 1,
35 | style=style, colorbar=False)
36 | if style == 'dual-triangular' and shift:
37 | xvals = np.array(xs) + .5
38 | yvals = np.array(ys) + 1/3
39 | else:
40 | xvals = xs
41 | yvals = ys
42 |
43 | ax.scatter(xvals, yvals, s=150, c='c', zorder=3)
44 | ax.set_xticks(ticks)
45 | ax.set_yticks(ticks)
46 | for x, y, value in zip(xvals, yvals, values):
47 | ax.text(x, y, str(value),
48 | fontsize=8,
49 | horizontalalignment='center',
50 | verticalalignment='center')
51 |
52 | # Colorbar
53 | f.tight_layout()
54 | cbax = f.add_axes([0.025, 0.1, 0.95, 0.10])
55 | norm = mpl.colors.Normalize(vmin=0, vmax=len(points))
56 | ticks = np.linspace(0, len(points), num=len(points) + 1)
57 | cb1 = mpl.colorbar.ColorbarBase(cbax, cmap=cmap,
58 | norm=norm,
59 | orientation='horizontal')
60 | cb1.set_ticks(ticks)
61 |
62 | if filename is not None:
63 | plt.savefig(filename)
64 |
65 | return ax
66 |
67 | if __name__ == '__main__':
68 | import subprocess
69 |
70 | scale = 3
71 | cmaps = [plt.cm.gray, plt.cm.cubehelix]
72 |
73 | basename = 'heatmap_styles_{}.pdf'
74 | filenames = [basename.format(cmap.name) for cmap in cmaps]
75 |
76 | cmd = 'convert -density 300 -trim {} -quality 100 {}'
77 | for cmap, pdf in zip(cmaps, filenames):
78 | png = pdf[:-3] + 'png'
79 | matplotlib_plot(scale, cmap, filename=pdf)
80 | subprocess.call(cmd.format(pdf, png), shell=True)
81 |
82 |
--------------------------------------------------------------------------------
/readme_images/heatmap_styles_cubehelix.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/heatmap_styles_cubehelix.pdf
--------------------------------------------------------------------------------
/readme_images/heatmap_styles_cubehelix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/heatmap_styles_cubehelix.png
--------------------------------------------------------------------------------
/readme_images/heatmap_styles_gray.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/heatmap_styles_gray.pdf
--------------------------------------------------------------------------------
/readme_images/heatmap_styles_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/heatmap_styles_gray.png
--------------------------------------------------------------------------------
/readme_images/orientations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/orientations.png
--------------------------------------------------------------------------------
/readme_images/rgba_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/rgba_example.png
--------------------------------------------------------------------------------
/readme_images/scatter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/scatter.png
--------------------------------------------------------------------------------
/readme_images/trajectory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/trajectory.png
--------------------------------------------------------------------------------
/readme_images/various_lines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcharper/python-ternary/9f946b69f266e61983f5be60793930fb1c380a6c/readme_images/various_lines.png
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | description_file = README.md
3 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 | from distutils.core import setup
3 |
4 | version = "1.0.8"
5 |
6 | with open('README.txt') as file:
7 | long_description = file.read()
8 |
9 | classifiers = [
10 | "Development Status :: 5 - Production/Stable",
11 | "Intended Audience :: Science/Research",
12 | "License :: OSI Approved :: MIT License",
13 | "Natural Language :: English",
14 | "Programming Language :: Python",
15 | "Programming Language :: Python :: 3.9",
16 | "Programming Language :: Python :: 3.10",
17 | "Programming Language :: Python :: 3.11",
18 | "Programming Language :: Python :: 3.12",
19 | "Topic :: Scientific/Engineering :: Visualization"
20 | ]
21 |
22 | setup(
23 | name="python-ternary",
24 | version=version,
25 | packages=['ternary'],
26 | install_requires=["matplotlib>=2"],
27 | author="Marc Harper and contributors",
28 | author_email="marc.harper@gmail.com",
29 | classifiers=classifiers,
30 | description="Make ternary plots in python with matplotlib",
31 | long_description=long_description,
32 | keywords="matplotlib ternary plotting",
33 | license="MIT",
34 | url="https://github.com/marcharper/python-ternary",
35 | download_url="https://github.com/marcharper/python-ternary/tarball/{}".format(version),
36 | )
37 |
--------------------------------------------------------------------------------
/ternary/__init__.py:
--------------------------------------------------------------------------------
1 | from matplotlib import pyplot as plt
2 |
3 | from .plotting import (
4 | clear_matplotlib_ticks,
5 | plot,
6 | resize_drawing_canvas,
7 | scatter,
8 | )
9 |
10 | from .lines import (
11 | boundary,
12 | gridlines,
13 | line,
14 | horizontal_line,
15 | left_parallel_line,
16 | right_parallel_line,
17 | )
18 |
19 | from .helpers import project_point
20 | from .colormapping import get_cmap
21 | from .heatmapping import heatmap, heatmapf, svg_heatmap
22 | from .ternary_axes_subplot import figure, TernaryAxesSubplot
23 |
24 | __version__ = "1.0.8"
25 |
--------------------------------------------------------------------------------
/ternary/colormapping.py:
--------------------------------------------------------------------------------
1 | import matplotlib
2 | from matplotlib import pyplot as plt
3 | from matplotlib.colors import rgb2hex
4 |
5 | ## Default colormap, other options here: http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps
6 | s = matplotlib.__version__.split('.')
7 | if int(s[0]) >= 2 or (int(s[0]) >= 1 and int(s[1]) >= 5):
8 | DEFAULT_COLOR_MAP_NAME = "viridis"
9 | else:
10 | DEFAULT_COLOR_MAP_NAME = "jet"
11 |
12 |
13 | ## Matplotlib Colormapping ##
14 |
15 | def get_cmap(cmap=None):
16 | """
17 | Loads a matplotlib colormap if specified or supplies the default.
18 |
19 | Parameters
20 | ----------
21 | cmap: string or matplotlib.colors.Colormap instance
22 | The name of the Matplotlib colormap to look up.
23 |
24 | Returns
25 | -------
26 | The desired Matplotlib colormap
27 |
28 | Raises
29 | ------
30 | ValueError if colormap name is not recognized by Matplotlib
31 | """
32 |
33 | if isinstance(cmap, matplotlib.colors.Colormap):
34 | return cmap
35 | if isinstance(cmap, str):
36 | cmap_name = cmap
37 | else:
38 | cmap_name = DEFAULT_COLOR_MAP_NAME
39 | return plt.get_cmap(cmap_name)
40 |
41 |
42 | def colormapper(value, lower=0, upper=1, cmap=None):
43 | """
44 | Maps values to colors by normalizing within [a,b], obtaining rgba from the
45 | given matplotlib color map for heatmap polygon coloring.
46 |
47 | Parameters
48 | ----------
49 | value: float
50 | The value to be colormapped
51 | lower: float
52 | Lower bound of colors
53 | upper: float
54 | Upper bound of colors
55 | cmap: String or matplotlib.colors.Colormap (optional)
56 | Colormap object to prevent repeated lookup
57 |
58 | Returns
59 | -------
60 | hex_, float
61 | The value mapped to an appropriate RGBA color value
62 | """
63 |
64 | cmap = get_cmap(cmap)
65 | if upper - lower == 0:
66 | rgba = cmap(0)
67 | else:
68 | rgba = cmap((value - lower) / float(upper - lower))
69 | hex_ = rgb2hex(rgba)
70 | return hex_
71 |
72 |
73 | def colorbar_hack(ax, vmin, vmax, cmap, scientific=False, cbarlabel=None, norm=None,
74 | **kwargs):
75 | """
76 | Colorbar hack to insert colorbar on ternary plot.
77 |
78 | Called by heatmap, not intended for direct usage.
79 |
80 | Parameters
81 | ----------
82 | vmin: float
83 | Minimum value to portray in colorbar
84 | vmax: float
85 | Maximum value to portray in colorbar
86 | cmap: Matplotlib colormap
87 | Matplotlib colormap to use
88 |
89 | """
90 | # http://stackoverflow.com/questions/8342549/matplotlib-add-colorbar-to-a-sequence-of-line-plots
91 | if norm is None:
92 | norm = plt.Normalize(vmin=vmin, vmax=vmax)
93 | sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
94 | sm._A = []
95 | cb = plt.colorbar(sm, ax=ax, **kwargs)
96 | if cbarlabel is not None:
97 | cb.set_label(cbarlabel)
98 | if scientific:
99 | cb.locator = matplotlib.ticker.LinearLocator(numticks=7)
100 | cb.formatter = matplotlib.ticker.ScalarFormatter()
101 | cb.formatter.set_powerlimits((0, 0))
102 | cb.update_ticks()
103 |
--------------------------------------------------------------------------------
/ternary/heatmapping.py:
--------------------------------------------------------------------------------
1 | """
2 | Various Heatmaps.
3 | """
4 |
5 | import functools
6 | import numpy as np
7 | from matplotlib import pyplot as plt
8 |
9 | from .helpers import unzip, normalize, simplex_iterator, permute_point, project_point
10 | from .colormapping import get_cmap, colormapper, colorbar_hack
11 |
12 | ### Heatmap Triangulation Coordinates
13 |
14 | ## Triangular Heatmaps
15 |
16 |
17 | def blend_value(data, i, j, k, keys=None):
18 | """Computes the average value of the three vertices of a triangle in the
19 | simplex triangulation, where two of the vertices are on the lower
20 | horizontal."""
21 |
22 | key_size = len(list(data.keys())[0])
23 | if not keys:
24 | keys = triangle_coordinates(i, j, k)
25 | # Reduce key from (i, j, k) to (i, j) if necessary
26 | keys = [tuple(key[:key_size]) for key in keys]
27 |
28 | # Sum over the values of the points to blend
29 | try:
30 | s = sum(data[key] for key in keys)
31 | value = s / 3.
32 | except KeyError:
33 | value = None
34 | return value
35 |
36 |
37 | def alt_blend_value(data, i, j, k):
38 | """Computes the average value of the three vertices of a triangle in the
39 | simplex triangulation, where two of the vertices are on the upper
40 | horizontal."""
41 |
42 | keys = alt_triangle_coordinates(i, j, k)
43 | return blend_value(data, i, j, k, keys=keys)
44 |
45 |
46 | def triangle_coordinates(i, j, k):
47 | """
48 | Computes coordinates of the constituent triangles of a triangulation for the
49 | simplex. These triangles are parallel to the lower axis on the lower side.
50 |
51 | Parameters
52 | ----------
53 | i,j,k: enumeration of the desired triangle
54 |
55 | Returns
56 | -------
57 | A numpy array of coordinates of the hexagon (unprojected)
58 | """
59 |
60 | return [(i, j, k), (i + 1, j, k - 1), (i, j + 1, k - 1)]
61 |
62 |
63 | def alt_triangle_coordinates(i, j, k):
64 | """
65 | Computes coordinates of the constituent triangles of a triangulation for the
66 | simplex. These triangles are parallel to the lower axis on the upper side.
67 |
68 | Parameters
69 | ----------
70 | i,j,k: enumeration of the desired triangle
71 |
72 | Returns
73 | -------
74 | A numpy array of coordinates of the hexagon (unprojected)
75 | """
76 |
77 | return [(i, j + 1, k - 1), (i + 1, j, k - 1), (i + 1, j + 1, k - 2)]
78 |
79 |
80 | ## Hexagonal Heatmaps ##
81 |
82 | def generate_hexagon_deltas():
83 | """
84 | Generates a dictionary of the necessary additive vectors to generate the
85 | hexagon points for the hexagonal heatmap.
86 | """
87 |
88 | zero = np.array([0, 0, 0])
89 | alpha = np.array([-1./3, 2./3, 0])
90 | deltaup = np.array([1./3, 1./3, 0])
91 | deltadown = np.array([2./3, -1./3, 0])
92 | i_vec = np.array([0, 1./2, -1./2])
93 | i_vec_down = np.array([1./2, -1./2, 0])
94 | deltaX_vec = np.array([1./2, 0, -1./2])
95 |
96 | d = dict()
97 | # Corner Points
98 | d["100"] = [zero, -deltaX_vec, -deltadown, -i_vec_down]
99 | d["010"] = [zero, i_vec_down, -alpha, -i_vec]
100 | d["001"] = [zero, i_vec, deltaup, deltaX_vec]
101 | # On the Edges
102 | d["011"] = [i_vec, deltaup, deltadown, -alpha, -i_vec]
103 | d["101"] = [-deltaX_vec, -deltadown, alpha, deltaup, deltaX_vec]
104 | d["110"] = [i_vec_down, -alpha, -deltaup, -deltadown, -i_vec_down]
105 | # Interior point
106 | d["111"] = [alpha, deltaup, deltadown, -alpha, -deltaup, -deltadown]
107 |
108 | return d
109 |
110 |
111 | hexagon_deltas = generate_hexagon_deltas()
112 |
113 |
114 | def hexagon_coordinates(i, j, k):
115 | """
116 | Computes coordinates of the constituent hexagons of a hexagonal heatmap.
117 |
118 | Parameters
119 | ----------
120 | i, j, k: enumeration of the desired hexagon
121 |
122 | Returns
123 | -------
124 | A numpy array of coordinates of the hexagon (unprojected)
125 | """
126 |
127 | signature = ""
128 | for x in [i, j, k]:
129 | if x == 0:
130 | signature += "0"
131 | else:
132 | signature += "1"
133 | deltas = hexagon_deltas[signature]
134 | center = np.array([i, j, k])
135 | return np.array([center + x for x in deltas])
136 |
137 |
138 | ## Heatmaps ##
139 |
140 | def polygon_generator(data, scale, style, permutation=None):
141 | """Generator for the vertices of the polygon to be colored and its color,
142 | depending on style. Called by heatmap."""
143 |
144 | # We'll project the coordinates inside this function to prevent
145 | # passing around permutation more than necessary
146 | project = functools.partial(project_point, permutation=permutation)
147 |
148 | if isinstance(data, dict):
149 | data_gen = data.items()
150 | else:
151 | # Only works with style == 'h'
152 | data_gen = data
153 |
154 | for key, value in data_gen:
155 | if value is None:
156 | continue
157 | i = key[0]
158 | j = key[1]
159 | k = scale - i - j
160 | if style == 'h':
161 | # Note here we permute first and then project normally, in
162 | # contrast to the cases below.
163 | i, j, k = list(permute_point([i, j, k], permutation=permutation))
164 | vertices = hexagon_coordinates(i, j, k)
165 | yield map(project_point, vertices), value
166 | elif style == 'd':
167 | # Upright triangles
168 | if (i <= scale) and (j <= scale) and (k >= 0):
169 | vertices = triangle_coordinates(i, j, k)
170 | yield map(project, vertices), value
171 | # Upside-down triangles
172 | if (i < scale) and (j < scale) and (k >= 1):
173 | vertices = alt_triangle_coordinates(i, j, k)
174 | value = blend_value(data, i, j, k)
175 | yield map(project, vertices), value
176 | elif style == 't':
177 | # Upright triangles
178 | if (i < scale) and (j < scale) and (k > 0):
179 | vertices = triangle_coordinates(i, j, k)
180 | value = blend_value(data, i, j, k)
181 | yield map(project, vertices), value
182 | # If not on the boundary add the upside-down triangle
183 | if (i < scale) and (j < scale) and (k > 1):
184 | vertices = alt_triangle_coordinates(i, j, k)
185 | value = alt_blend_value(data, i, j, k)
186 | yield map(project, vertices), value
187 |
188 |
189 | def heatmap(data, scale, vmin=None, vmax=None, cmap=None, ax=None,
190 | scientific=False, style='triangular', colorbar=True,
191 | permutation=None, use_rgba=False, cbarlabel=None, cb_kwargs=None):
192 | """
193 | Plots heatmap of given color values.
194 |
195 | Parameters
196 | ----------
197 | data: dictionary
198 | A dictionary mapping the i, j polygon to the heatmap color, where
199 | i + j + k = scale.
200 | scale: Integer
201 | The scale used to partition the simplex.
202 | vmin: float, None
203 | The minimum color value, used to normalize colors. Computed if absent.
204 | vmax: float, None
205 | The maximum color value, used to normalize colors. Computed if absent.
206 | cmap: String or matplotlib.colors.Colormap, None
207 | The name of the Matplotlib colormap to use.
208 | ax: Matplotlib AxesSubplot, None
209 | The subplot to draw on.
210 | scientific: Bool, False
211 | Whether to use scientific notation for colorbar numbers.
212 | style: String, "triangular"
213 | The style of the heatmap, "triangular", "dual-triangular" or "hexagonal"
214 | colorbar: bool, True
215 | Show colorbar.
216 | permutation: string, None
217 | A permutation of the coordinates
218 | use_rgba: bool, False
219 | Use rgba color values
220 | cbarlabel: string, None
221 | Text label for the colorbar
222 | cb_kwargs: dict
223 | dict of kwargs to pass to colorbar
224 |
225 | Returns
226 | -------
227 | ax: The matplotlib axis
228 | """
229 |
230 | if not ax:
231 | fig, ax = plt.subplots()
232 | # If use_rgba, make the RGBA values numpy arrays so that they can
233 | # be averaged.
234 | if use_rgba:
235 | for k, v in data.items():
236 | data[k] = np.array(v)
237 | else:
238 | cmap = get_cmap(cmap)
239 | if vmin is None:
240 | vmin = min(data.values())
241 | if vmax is None:
242 | vmax = max(data.values())
243 | style = style.lower()[0]
244 | if style not in ["t", "h", 'd']:
245 | raise ValueError("Heatmap style must be 'triangular', 'dual-triangular', or 'hexagonal'")
246 |
247 | vertices_values = polygon_generator(data, scale, style,
248 | permutation=permutation)
249 |
250 | # Draw the polygons and color them
251 | for vertices, value in vertices_values:
252 | if value is None:
253 | continue
254 | if not use_rgba:
255 | color = colormapper(value, vmin, vmax, cmap=cmap)
256 | else:
257 | color = value # rgba tuple (r,g,b,a) all in [0,1]
258 | # Matplotlib wants a list of xs and a list of ys
259 | xs, ys = unzip(vertices)
260 | ax.fill(xs, ys, facecolor=color, edgecolor=color)
261 |
262 | if not cb_kwargs:
263 | cb_kwargs = dict()
264 | if colorbar:
265 | colorbar_hack(ax, vmin, vmax, cmap, scientific=scientific,
266 | cbarlabel=cbarlabel, **cb_kwargs)
267 | return ax
268 |
269 |
270 | ## User Convenience Functions ##
271 |
272 |
273 | def heatmapf(func, scale=10, boundary=True, cmap=None, ax=None,
274 | scientific=False, style='triangular', colorbar=True,
275 | permutation=None, vmin=None, vmax=None, cbarlabel=None,
276 | cb_kwargs=None):
277 | """
278 | Computes func on heatmap partition coordinates and plots heatmap. In other
279 | words, computes the function on lattice points of the simplex (normalized
280 | points) and creates a heatmap from the values.
281 |
282 | Parameters
283 | ----------
284 | func: Function
285 | A function of 3-tuples to be heatmapped
286 | scale: Integer
287 | The scale used to partition the simplex
288 | boundary: Bool, True
289 | Include the boundary points or not
290 | cmap: String, None
291 | The name of the Matplotlib colormap to use
292 | ax: Matplotlib axis object, None
293 | The axis to draw the colormap on
294 | style: String, "triangular"
295 | The style of the heatmap, "triangular", "dual-triangular" or "hexagonal"
296 | scientific: Bool, False
297 | Whether to use scientific notation for colorbar numbers.
298 | colorbar: bool, True
299 | Show colorbar.
300 | permutation: string, None
301 | A permutation of the coordinates
302 | vmin: float
303 | The minimum color value, used to normalize colors.
304 | vmax: float
305 | The maximum color value, used to normalize colors.
306 | cb_kwargs: dict
307 | dict of kwargs to pass to colorbar
308 |
309 | Returns
310 | -------
311 | ax, The matplotlib axis
312 | """
313 |
314 | # Apply the function to a simplex partition
315 | data = dict()
316 | for i, j, k in simplex_iterator(scale=scale, boundary=boundary):
317 | data[(i, j)] = func(normalize([i, j, k]))
318 | # Pass everything to the heatmapper
319 | ax = heatmap(data, scale, cmap=cmap, ax=ax, style=style,
320 | scientific=scientific, colorbar=colorbar,
321 | permutation=permutation, vmin=vmin, vmax=vmax,
322 | cbarlabel=cbarlabel, cb_kwargs=cb_kwargs)
323 | return ax
324 |
325 |
326 | def svg_polygon(coordinates, color):
327 | """
328 | Create an svg triangle for the stationary heatmap.
329 |
330 | Parameters
331 | ----------
332 | coordinates: list
333 | The coordinates defining the polygon
334 | color: string
335 | RGB color value e.g. #26ffd1
336 |
337 | Returns
338 | -------
339 | string, the svg string for the polygon
340 | """
341 |
342 | coord_str = []
343 | for c in coordinates:
344 | coord_str.append(",".join(map(str, c)))
345 | coord_str = " ".join(coord_str)
346 | polygon = ' \n' % (coord_str, color, color)
347 | return polygon
348 |
349 |
350 | def svg_heatmap(data, scale, filename, vmax=None, vmin=None, style='h',
351 | permutation=None, cmap=None):
352 | """
353 | Create a heatmap in SVG format. Intended for use with very large datasets,
354 | which would require large amounts of RAM using matplotlib. You can convert
355 | the image to another format with e.g. ImageMagick:
356 |
357 | convert -density 1200 -resize -rotate 180 1000x1000 your.svg your.png
358 |
359 | Parameters
360 | ----------
361 |
362 | data: dictionary or k, v generator
363 | A dictionary mapping the i, j polygon to the heatmap color, where
364 | i + j + k = scale. If using a generator, style must be 'h'.
365 | scale: Integer
366 | The scale used to partition the simplex.
367 | filename: string
368 | The filename to write the SVG data to.
369 | vmin: float
370 | The minimum color value, used to normalize colors.
371 | vmax: float
372 | The maximum color value, used to normalize colors.
373 | cmap: String or matplotlib.colors.Colormap, None
374 | The name of the Matplotlib colormap to use.
375 | style: String, "h"
376 | The style of the heatmap, "triangular", "dual-triangular" or "hexagonal"
377 | permutation: string, None
378 | A permutation of the coordinates
379 | """
380 |
381 | style = style.lower()[0]
382 | if style not in ["t", "h", 'd']:
383 | raise ValueError("Heatmap style must be 'triangular', 'dual-triangular', or 'hexagonal'")
384 |
385 | if not isinstance(data, dict):
386 | if not style == 'h':
387 | raise ValueError("Data can only be given as a generator for hexagonal style heatmaps because of blending for adjacent polygons.")
388 | elif vmax is None or vmin is None:
389 | raise ValueError("vmax and vmin must be supplied for data given as a generator.")
390 |
391 | cmap = get_cmap(cmap)
392 |
393 | if vmin is None:
394 | vmin = min(data.values())
395 | if vmax is None:
396 | vmax = max(data.values())
397 |
398 | height = scale * np.sqrt(3) / 2 + 2
399 |
400 | output_file = open(filename, 'w')
401 | output_file.write('\n' % (height, scale))
402 |
403 | vertices_values = polygon_generator(data, scale, style,
404 | permutation=permutation)
405 |
406 | # Draw the polygons and color them
407 | for vertices, value in vertices_values:
408 | color = colormapper(value, vmin, vmax, cmap=cmap)
409 | output_file.write(svg_polygon(vertices, color))
410 |
411 | output_file.write(' \n')
412 |
413 |
414 | def background_color(ax, color, scale, zorder=-1000, alpha=None):
415 | """Draws a triangle behind the plot to serve as the background color."""
416 | vertices = [(scale, 0, 0), (0, scale, 0), (0, 0, scale)]
417 | vertices = map(project_point, vertices)
418 | xs, ys = unzip(vertices)
419 | poly = ax.fill(xs, ys, facecolor=color, edgecolor=color, zorder=zorder, alpha=alpha)
420 | return poly
421 |
--------------------------------------------------------------------------------
/ternary/helpers.py:
--------------------------------------------------------------------------------
1 | """
2 | Helper functions and utilities for projecting to the simplex and various tasks.
3 | """
4 |
5 | import numpy as np
6 |
7 |
8 | ### Constants ###
9 |
10 | SQRT3 = np.sqrt(3)
11 | SQRT3OVER2 = SQRT3 / 2.
12 |
13 | ### Auxilliary Functions ###
14 |
15 |
16 | def unzip(l):
17 | """[(a1, b1), ..., (an, bn)] ----> ([a1, ..., an], [b1, ..., bn])"""
18 | return list(zip(*l))
19 |
20 |
21 | def normalize(l):
22 | """
23 | Normalizes input list.
24 |
25 | Parameters
26 | ----------
27 | l: list
28 | The list to be normalized
29 |
30 | Returns
31 | -------
32 | The normalized list or numpy array
33 |
34 | Raises
35 | ------
36 | ValueError, if the list sums to zero
37 | """
38 |
39 | s = float(sum(l))
40 | if s == 0:
41 | raise ValueError("Cannot normalize list with sum 0")
42 | return [x / s for x in l]
43 |
44 |
45 | def simplex_iterator(scale, boundary=True):
46 | """
47 | Systematically iterates through a lattice of points on the 2-simplex.
48 |
49 | Parameters
50 | ----------
51 | scale: Int
52 | The normalized scale of the simplex, i.e. N such that points (x,y,z)
53 | satisify x + y + z == N
54 |
55 | boundary: bool, True
56 | Include the boundary points (tuples where at least one
57 | coordinate is zero)
58 |
59 | Yields
60 | ------
61 | 3-tuples, There are binom(n+2, 2) points (the triangular
62 | number for scale + 1, less 3*(scale+1) if boundary=False
63 | """
64 |
65 | start = 0
66 | if not boundary:
67 | start = 1
68 | for i in range(start, scale + (1 - start)):
69 | for j in range(start, scale + (1 - start) - i):
70 | k = scale - i - j
71 | yield (i, j, k)
72 |
73 |
74 | ## Ternary Projections ##
75 |
76 | def permute_point(p, permutation=None):
77 | """
78 | Permutes the point according to the permutation keyword argument. The
79 | default permutation is "012" which does not change the order of the
80 | coordinate. To rotate counterclockwise, use "120" and to rotate clockwise
81 | use "201"."""
82 | if not permutation:
83 | return p
84 | return [p[int(permutation[i])] for i in range(len(p))]
85 |
86 |
87 | def project_point(p, permutation=None):
88 | """
89 | Maps (x,y,z) coordinates to planar simplex.
90 |
91 | Parameters
92 | ----------
93 | p: 3-tuple
94 | The point to be projected p = (x, y, z)
95 | permutation: string, None, equivalent to "012"
96 | The order of the coordinates, counterclockwise from the origin
97 | """
98 | permuted = permute_point(p, permutation=permutation)
99 | a = permuted[0]
100 | b = permuted[1]
101 | x = a + b/2.
102 | y = SQRT3OVER2 * b
103 | return np.array([x, y])
104 |
105 |
106 | def planar_to_coordinates(p, scale):
107 | """
108 | Planar simplex (regular x,y) to maps (x,y,z) ternary coordinates. The order of the coordinates is counterclockwise
109 | from the origin.
110 |
111 | Parameters
112 | ----------
113 | p: 2-tuple
114 | The planar simplex (x, y) point to be transformed to maps (x,y,z) coordinates
115 |
116 | scale: Int
117 | The normalized scale of the simplex, i.e. N such that points (x,y,z)
118 | satisfy x + y + z == N
119 |
120 | """
121 | y = p[1] / SQRT3OVER2
122 | x = p[0] - y / 2.
123 | z = scale - x - y
124 | return np.array([x, y, z])
125 |
126 |
127 | def project_sequence(s, permutation=None):
128 | """
129 | Projects a point or sequence of points using `project_point` to lists xs, ys
130 | for plotting with Matplotlib.
131 |
132 | Parameters
133 | ----------
134 | s, Sequence-like
135 | The sequence of points (3-tuples) to be projected.
136 |
137 | Returns
138 | -------
139 | xs, ys: The sequence of projected points in coordinates as two lists
140 | """
141 |
142 | xs, ys = unzip([project_point(p, permutation=permutation) for p in s])
143 | return xs, ys
144 |
145 |
146 | # Convert coordinates for custom plots with limits
147 |
148 | def convert_coordinates(q, conversion, axisorder):
149 | """
150 | Convert a 3-tuple in data coordinates into to simplex data
151 | coordinates for plotting.
152 |
153 | Parameters
154 | ----------
155 | q: 3-tuple
156 | the point to be plotted in data coordinates
157 |
158 | conversion: dict
159 | keys = ['b','l','r']
160 | values = lambda function giving the conversion
161 | axisorder: String giving the order of the axes for the coordinate tuple
162 | e.g. 'blr' for bottom, left, right coordinates.
163 |
164 | Returns
165 | -------
166 | p: 3-tuple
167 | The point converted to simplex coordinates.
168 | """
169 | p = []
170 | for k in range(3):
171 | p.append(conversion[axisorder[k]](q[k]))
172 |
173 | return tuple(p)
174 |
175 |
176 | def get_conversion(scale, limits):
177 | """
178 | Get the conversion equations for each axis.
179 |
180 | limits: dict of min and max values for the axes in the order blr.
181 | """
182 | fb = float(scale) / float(limits['b'][1] - limits['b'][0])
183 | fl = float(scale) / float(limits['l'][1] - limits['l'][0])
184 | fr = float(scale) / float(limits['r'][1] - limits['r'][0])
185 |
186 | conversion = {"b": lambda x: (x - limits['b'][0]) * fb,
187 | "l": lambda x: (x - limits['l'][0]) * fl,
188 | "r": lambda x: (x - limits['r'][0]) * fr}
189 |
190 | return conversion
191 |
192 |
193 | def convert_coordinates_sequence(qs, scale, limits, axisorder):
194 | """
195 | Take a sequence of 3-tuples in data coordinates and convert them
196 | to simplex coordinates for plotting. This is needed for custom
197 | plots where the scale of the simplex axes is set within limits rather
198 | than being defined by the scale parameter.
199 |
200 | Parameters
201 | ----------
202 | qs, sequence of 3-tuples
203 | The points to be plotted in data coordinates.
204 |
205 | scale: int
206 | The scale parameter for the plot.
207 | limits: dict
208 | keys = ['b','l','r']
209 | values = min,max data values for this axis.
210 | axisorder: String giving the order of the axes for the coordinate tuple
211 | e.g. 'blr' for bottom, left, right coordinates.
212 |
213 | Returns
214 | -------
215 | s, list of 3-tuples
216 | the points converted to simplex coordinates
217 | """
218 | conversion = get_conversion(scale, limits)
219 |
220 | return [convert_coordinates(q, conversion, axisorder) for q in qs]
221 |
--------------------------------------------------------------------------------
/ternary/lines.py:
--------------------------------------------------------------------------------
1 | """
2 | Line plotting functions, draw boundary and gridlines.
3 | """
4 |
5 | from numpy import arange
6 | from matplotlib.lines import Line2D
7 |
8 | from .helpers import project_point
9 |
10 |
11 | ## Lines ##
12 |
13 | def line(ax, p1, p2, permutation=None, **kwargs):
14 | """
15 | Draws a line on `ax` from p1 to p2.
16 |
17 | Parameters
18 | ----------
19 | ax: Matplotlib AxesSubplot, None
20 | The subplot to draw on.
21 | p1: 2-tuple
22 | The (x,y) starting coordinates
23 | p2: 2-tuple
24 | The (x,y) ending coordinates
25 | kwargs:
26 | Any kwargs to pass through to Matplotlib.
27 | """
28 |
29 | pp1 = project_point(p1, permutation=permutation)
30 | pp2 = project_point(p2, permutation=permutation)
31 | ax.add_line(Line2D((pp1[0], pp2[0]), (pp1[1], pp2[1]), **kwargs))
32 |
33 |
34 | def horizontal_line(ax, scale, i, **kwargs):
35 | """
36 | Draws the i-th horizontal line parallel to the lower axis.
37 |
38 | Parameters
39 | ----------
40 | ax: Matplotlib AxesSubplot
41 | The subplot to draw on.
42 | scale: float, 1.0
43 | Simplex scale size.
44 | i: float
45 | The index of the line to draw
46 | kwargs: Dictionary
47 | Any kwargs to pass through to Matplotlib.
48 | """
49 |
50 | p1 = (0, i, scale - i)
51 | p2 = (scale - i, i, 0)
52 | line(ax, p1, p2, **kwargs)
53 |
54 |
55 | def left_parallel_line(ax, scale, i, **kwargs):
56 | """
57 | Draws the i-th line parallel to the left axis.
58 |
59 | Parameters
60 | ----------
61 | ax: Matplotlib AxesSubplot
62 | The subplot to draw on.
63 | scale: float
64 | Simplex scale size.
65 | i: float
66 | The index of the line to draw
67 | kwargs: Dictionary
68 | Any kwargs to pass through to Matplotlib.
69 | """
70 |
71 | p1 = (i, scale - i, 0)
72 | p2 = (i, 0, scale - i)
73 | line(ax, p1, p2, **kwargs)
74 |
75 |
76 | def right_parallel_line(ax, scale, i, **kwargs):
77 | """
78 | Draws the i-th line parallel to the right axis.
79 |
80 | Parameters
81 | ----------
82 | ax: Matplotlib AxesSubplot
83 | The subplot to draw on.
84 | scale: float
85 | Simplex scale size.
86 | i: float
87 | The index of the line to draw
88 | kwargs: Dictionary
89 | Any kwargs to pass through to Matplotlib.
90 | """
91 |
92 | p1 = (0, scale - i, i)
93 | p2 = (scale - i, 0, i)
94 | line(ax, p1, p2, **kwargs)
95 |
96 |
97 | ## Boundary, Gridlines ##
98 |
99 | def boundary(ax, scale, axes_colors=None, **kwargs):
100 | """
101 | Plots the boundary of the simplex. Creates and returns matplotlib axis if
102 | none given.
103 |
104 | Parameters
105 | ----------
106 | ax: Matplotlib AxesSubplot, None
107 | The subplot to draw on.
108 | scale: float
109 | Simplex scale size.
110 | kwargs:
111 | Any kwargs to pass through to matplotlib.
112 | axes_colors: dict
113 | Option for coloring boundaries different colors.
114 | e.g. {'l': 'g'} for coloring the left axis boundary green
115 | """
116 |
117 | # Set default color as black.
118 | if axes_colors is None:
119 | axes_colors = dict()
120 | for _axis in ['l', 'r', 'b']:
121 | if _axis not in axes_colors.keys():
122 | axes_colors[_axis] = 'black'
123 |
124 | horizontal_line(ax, scale, 0, color=axes_colors['b'], **kwargs)
125 | left_parallel_line(ax, scale, 0, color=axes_colors['l'], **kwargs)
126 | right_parallel_line(ax, scale, 0, color=axes_colors['r'], **kwargs)
127 | return ax
128 |
129 |
130 | def merge_dicts(base, updates):
131 | """
132 | Given two dicts, merge them into a new dict as a shallow copy.
133 |
134 | Parameters
135 | ----------
136 | base: dict
137 | The base dictionary.
138 | updates: dict
139 | Secondary dictionary whose values override the base.
140 | """
141 | if not base:
142 | base = dict()
143 | if not updates:
144 | updates = dict()
145 | z = base.copy()
146 | z.update(updates)
147 | return z
148 |
149 |
150 | def gridlines(ax, scale, multiple=None, horizontal_kwargs=None,
151 | left_kwargs=None, right_kwargs=None, **kwargs):
152 | """
153 | Plots grid lines excluding boundary.
154 |
155 | Parameters
156 | ----------
157 | ax: Matplotlib AxesSubplot, None
158 | The subplot to draw on.
159 | scale: float
160 | Simplex scale size.
161 | multiple: float, None
162 | Specifies which inner gridelines to draw. For example, if scale=30 and
163 | multiple=6, only 5 inner gridlines will be drawn.
164 | horizontal_kwargs: dict, None
165 | Any kwargs to pass through to matplotlib for horizontal gridlines
166 | left_kwargs: dict, None
167 | Any kwargs to pass through to matplotlib for left parallel gridlines
168 | right_kwargs: dict, None
169 | Any kwargs to pass through to matplotlib for right parallel gridlines
170 | kwargs:
171 | Any kwargs to pass through to matplotlib, if not using
172 | horizontal_kwargs, left_kwargs, or right_kwargs
173 | """
174 |
175 | if 'linewidth' not in kwargs:
176 | kwargs["linewidth"] = 0.5
177 | if 'linestyle' not in kwargs:
178 | kwargs["linestyle"] = ':'
179 | horizontal_kwargs = merge_dicts(kwargs, horizontal_kwargs)
180 | left_kwargs = merge_dicts(kwargs, left_kwargs)
181 | right_kwargs = merge_dicts(kwargs, right_kwargs)
182 | if not multiple:
183 | multiple = 1.
184 | ## Draw grid-lines
185 | # Parallel to horizontal axis
186 | for i in arange(0, scale, multiple):
187 | horizontal_line(ax, scale, i, **horizontal_kwargs)
188 | # Parallel to left and right axes
189 | for i in arange(0, scale + multiple, multiple):
190 | left_parallel_line(ax, scale, i, **left_kwargs)
191 | right_parallel_line(ax, scale, i, **right_kwargs)
192 | return ax
193 |
194 |
195 | def normalize_tick_formats(tick_formats):
196 | if type(tick_formats) == dict:
197 | return tick_formats
198 | if tick_formats is None:
199 | s = '%d'
200 | elif type(tick_formats) == str:
201 | s = tick_formats
202 | else:
203 | raise TypeError("tick_formats must be a dictionary of strings"
204 | " a string, or None.")
205 | return {'b': s, 'l': s, 'r': s}
206 |
207 |
208 | def ticks(ax, scale, ticks=None, locations=None, multiple=1, axis='b',
209 | offset=0.01, clockwise=False, axes_colors=None, fontsize=10,
210 | tick_formats=None, **kwargs):
211 | """
212 | Sets tick marks and labels.
213 |
214 | Parameters
215 | ----------
216 | ax: Matplotlib AxesSubplot, None
217 | The subplot to draw on.
218 | scale: float, 1.0
219 | Simplex scale size.
220 | ticks: list of strings, None
221 | The tick labels
222 | locations: list of points, None
223 | The locations of the ticks
224 | multiple: float, None
225 | Specifies which ticks gridelines to draw. For example, if scale=30 and
226 | multiple=6, only 5 ticks will be drawn.
227 | axis: str, 'b'
228 | The axis or axes to draw the ticks for. `axis` must be a substring of
229 | 'lrb' (as sets)
230 | offset: float, 0.01
231 | controls the length of the ticks
232 | clockwise: bool, False
233 | Draw ticks marks clockwise or counterclockwise
234 | axes_colors: Dict, None
235 | Option to color ticks differently for each axis, 'l', 'r', 'b'
236 | e.g. {'l': 'g', 'r':'b', 'b': 'y'}
237 | tick_formats: None, Dict, Str
238 | If None, all axes will be labelled with ints. If Dict, the keys are
239 | 'b', 'l' and 'r' and the values are format strings e.g. "%.3f" for
240 | a float with 3 decimal places or "%.3e" for scientific format with
241 | 3 decimal places or "%d" for ints. If tick_formats is a string, it
242 | is assumed that this is a format string to be applied to all axes.
243 | kwargs:
244 | Any kwargs to pass through to matplotlib.
245 |
246 | """
247 |
248 | axis = axis.lower()
249 | valid_axis_chars = set(['l', 'r', 'b'])
250 | axis_chars = set(axis)
251 | if not axis_chars.issubset(valid_axis_chars):
252 | raise ValueError("axis must be some combination of 'l', 'r', and 'b'")
253 |
254 | if ticks and not locations:
255 | num_ticks = len(ticks)
256 | if num_ticks != 0:
257 | multiple = scale / (num_ticks - 1)
258 | locations = arange(0, scale + multiple, multiple)
259 |
260 | if not ticks:
261 | locations = arange(0, scale + multiple, multiple)
262 | ticks = locations
263 |
264 | tick_formats = normalize_tick_formats(tick_formats)
265 |
266 | # Default color: black
267 | if axes_colors is None:
268 | axes_colors = dict()
269 | for _axis in valid_axis_chars:
270 | if _axis not in axes_colors:
271 | axes_colors[_axis] = 'black'
272 |
273 | offset *= scale
274 |
275 | if 'r' in axis:
276 | for index, i in enumerate(locations):
277 | loc1 = (scale - i, i, 0)
278 | if clockwise:
279 | # Right parallel
280 | loc2 = (scale - i, i + offset, 0)
281 | text_location = (scale - i, i + 2 * offset, 0)
282 | tick = ticks[-(index+1)]
283 | else:
284 | # Horizontal
285 | loc2 = (scale - i + offset, i, 0)
286 | text_location = (scale - i + 3.1 * offset, i - 0.5 * offset, 0)
287 | tick = ticks[index]
288 | line(ax, loc1, loc2, color=axes_colors['r'], **kwargs)
289 | x, y = project_point(text_location)
290 | if isinstance(tick, str):
291 | s = tick
292 | else:
293 | s = tick_formats['r'] % tick
294 | ax.text(x, y, s, horizontalalignment="center",
295 | color=axes_colors['r'], fontsize=fontsize)
296 |
297 | if 'l' in axis:
298 | for index, i in enumerate(locations):
299 | loc1 = (0, i, 0)
300 | if clockwise:
301 | # Horizontal
302 | loc2 = (-offset, i, 0)
303 | text_location = (-2 * offset, i - 0.5 * offset, 0)
304 | tick = ticks[index]
305 | else:
306 | # Right parallel
307 | loc2 = (-offset, i + offset, 0)
308 | text_location = (-2 * offset, i + 1.5 * offset, 0)
309 | tick = ticks[-(index+1)]
310 | line(ax, loc1, loc2, color=axes_colors['l'], **kwargs)
311 | x, y = project_point(text_location)
312 | if isinstance(tick, str):
313 | s = tick
314 | else:
315 | s = tick_formats['l'] % tick
316 | ax.text(x, y, s, horizontalalignment="center",
317 | color=axes_colors['l'], fontsize=fontsize)
318 |
319 | if 'b' in axis:
320 | for index, i in enumerate(locations):
321 | loc1 = (i, 0, 0)
322 | if clockwise:
323 | # Right parallel
324 | loc2 = (i + offset, -offset, 0)
325 | text_location = (i + 3 * offset, -3.5 * offset, 0)
326 | tick = ticks[-(index+1)]
327 | else:
328 | # Left parallel
329 | loc2 = (i, -offset, 0)
330 | text_location = (i + 0.5 * offset, -3.5 * offset, 0)
331 | tick = ticks[index]
332 | line(ax, loc1, loc2, color=axes_colors['b'], **kwargs)
333 | x, y = project_point(text_location)
334 | if isinstance(tick, str):
335 | s = tick
336 | else:
337 | s = tick_formats['b'] % tick
338 | ax.text(x, y, s, horizontalalignment="center",
339 | color=axes_colors['b'], fontsize=fontsize)
340 |
--------------------------------------------------------------------------------
/ternary/plotting.py:
--------------------------------------------------------------------------------
1 | """
2 | Plotting functions: scatter, plot (curves), axis labelling.
3 | """
4 |
5 | import matplotlib
6 | from matplotlib import pyplot as plt
7 | import numpy as np
8 |
9 | from .helpers import project_sequence
10 | from .colormapping import get_cmap, colorbar_hack
11 |
12 |
13 | ### Drawing Helpers ###
14 |
15 | def resize_drawing_canvas(ax, scale=1.):
16 | """
17 | Makes sure the drawing surface is large enough to display projected
18 | content.
19 |
20 | Parameters
21 | ----------
22 | ax: Matplotlib AxesSubplot, None
23 | The subplot to draw on.
24 | scale: float, 1.0
25 | Simplex scale size.
26 | """
27 | ax.set_ylim((-0.10 * scale, .90 * scale))
28 | ax.set_xlim((-0.05 * scale, 1.05 * scale))
29 |
30 |
31 | def clear_matplotlib_ticks(ax=None, axis="both"):
32 | """
33 | Clears the default matplotlib axes, or the one specified by the axis
34 | argument.
35 |
36 | Parameters
37 | ----------
38 | ax: Matplotlib AxesSubplot, None
39 | The subplot to draw on.
40 | axis: string, "both"
41 | The axis to clear: "x" or "horizontal", "y" or "vertical", or "both"
42 | """
43 | if not ax:
44 | return
45 | if axis.lower() in ["both", "x", "horizontal"]:
46 | ax.set_xticks([], minor=False)
47 | if axis.lower() in ["both", "y", "vertical"]:
48 | ax.set_yticks([], minor=False)
49 |
50 |
51 | ## Curve Plotting ##
52 |
53 | def plot(points, ax=None, permutation=None, **kwargs):
54 | """
55 | Analogous to maplotlib.plot. Plots trajectory points where each point is a
56 | tuple (x,y,z) satisfying x + y + z = scale (not checked). The tuples are
57 | projected and plotted as a curve.
58 |
59 | Parameters
60 | ----------
61 | points: List of 3-tuples
62 | The list of tuples to be plotted as a connected curve.
63 | ax: Matplotlib AxesSubplot, None
64 | The subplot to draw on.
65 | kwargs:
66 | Any kwargs to pass through to matplotlib.
67 | """
68 | if not ax:
69 | fig, ax = plt.subplots()
70 | xs, ys = project_sequence(points, permutation=permutation)
71 | ax.plot(xs, ys, **kwargs)
72 | return ax
73 |
74 |
75 | def plot_colored_trajectory(points, cmap=None, ax=None, permutation=None,
76 | **kwargs):
77 | """
78 | Plots trajectories with changing color, simlar to `plot`. Trajectory points
79 | are tuples (x,y,z) satisfying x + y + z = scale (not checked). The tuples are
80 | projected and plotted as a curve.
81 |
82 | Parameters
83 | ----------
84 | points: List of 3-tuples
85 | The list of tuples to be plotted as a connected curve.
86 | ax: Matplotlib AxesSubplot, None
87 | The subplot to draw on.
88 | cmap: String or matplotlib.colors.Colormap, None
89 | The name of the Matplotlib colormap to use.
90 | kwargs:
91 | Any kwargs to pass through to matplotlib.
92 | """
93 | if not ax:
94 | fig, ax = plt.subplots()
95 | cmap = get_cmap(cmap)
96 | xs, ys = project_sequence(points, permutation=permutation)
97 |
98 | # We want to color each segment independently...which is annoying.
99 | segments = []
100 | for i in range(len(xs) - 1):
101 | cur_line = []
102 | x_before = xs[i]
103 | y_before = ys[i]
104 | x_after = xs[i+1]
105 | y_after = ys[i+1]
106 |
107 | cur_line.append([x_before, y_before])
108 | cur_line.append([x_after, y_after])
109 | segments.append(cur_line)
110 | segments = np.array(segments)
111 |
112 | line_segments = matplotlib.collections.LineCollection(segments, cmap=cmap, **kwargs)
113 | line_segments.set_array(np.arange(len(segments)))
114 | ax.add_collection(line_segments)
115 |
116 | return ax
117 |
118 |
119 | def scatter(points, ax=None, permutation=None, colorbar=False, colormap=None,
120 | vmin=0, vmax=1, scientific=False, cbarlabel=None, cb_kwargs=None,
121 | **kwargs):
122 | """
123 | Plots trajectory points where each point satisfies x + y + z = scale.
124 | First argument is a list or numpy array of tuples of length 3.
125 |
126 | Parameters
127 | ----------
128 | points: List of 3-tuples
129 | The list of tuples to be scatter-plotted.
130 | ax: Matplotlib AxesSubplot, None
131 | The subplot to draw on.
132 | colorbar: bool, False
133 | Show colorbar.
134 | colormap: String or matplotlib.colors.Colormap, None
135 | The name of the Matplotlib colormap to use.
136 | vmin: int, 0
137 | Minimum value for colorbar.
138 | vmax: int, 1
139 | Maximum value for colorbar.
140 | cb_kwargs: dict
141 | Any additional kwargs to pass to colorbar
142 | kwargs:
143 | Any kwargs to pass through to matplotlib.
144 | """
145 | if not ax:
146 | fig, ax = plt.subplots()
147 | xs, ys = project_sequence(points, permutation=permutation)
148 | ax.scatter(xs, ys, vmin=vmin, vmax=vmax, cmap=colormap, **kwargs)
149 |
150 | if colorbar and (colormap != None):
151 | if cb_kwargs != None:
152 | colorbar_hack(ax, vmin, vmax, colormap, scientific=scientific,
153 | cbarlabel=cbarlabel, **cb_kwargs)
154 | else:
155 | colorbar_hack(ax, vmin, vmax, colormap, scientific=scientific,
156 | cbarlabel=cbarlabel)
157 |
158 | return ax
159 |
--------------------------------------------------------------------------------
/ternary/ternary_axes_subplot.py:
--------------------------------------------------------------------------------
1 | """
2 | Wrapper class for all ternary plotting functions.
3 | """
4 |
5 | from collections import namedtuple
6 | from functools import partial
7 |
8 | import numpy as np
9 | from matplotlib import pyplot as plt
10 |
11 | from . import heatmapping
12 | from . import lines
13 | from . import plotting
14 | from .helpers import project_point, convert_coordinates_sequence
15 |
16 |
17 | BackgroundParameters = namedtuple('BackgroundParameters', ['color', 'alpha', 'zorder'])
18 |
19 |
20 | def figure(ax=None, scale=None, permutation=None):
21 | """
22 | Wraps a Matplotlib AxesSubplot or generates a new one. Emulates matplotlib's
23 | > figure, ax = plt.subplots()
24 |
25 | Parameters
26 | ----------
27 | ax: AxesSubplot, None
28 | The matplotlib AxesSubplot to wrap
29 | scale: float, None
30 | The scale factor of the ternary plot
31 | """
32 |
33 | ternary_ax = TernaryAxesSubplot(ax=ax, scale=scale, permutation=permutation)
34 | return ternary_ax.get_figure(), ternary_ax
35 |
36 |
37 | def mpl_redraw_callback(event, tax):
38 | """
39 | Callback to properly rotate and redraw text labels when the plot is drawn
40 | or resized.
41 |
42 | Parameters
43 | ----------
44 | event: a matplotlib event
45 | either 'resize_event' or 'draw_event'
46 | tax: TernaryAxesSubplot
47 | the TernaryAxesSubplot
48 | """
49 | tax._redraw_labels()
50 |
51 |
52 | class TernaryAxesSubplot(object):
53 | """
54 | Wrapper for python-ternary and matplotlib figure. Parameters for member
55 | functions simply pass through to ternary's functions with the same names.
56 | This class manages the matplotlib axes, the scale, and the boundary scale
57 | to ease the use of ternary plotting functions.
58 | """
59 |
60 | def __init__(self, ax=None, scale=None, permutation=None):
61 | if not scale:
62 | scale = 1.0
63 | if ax:
64 | self.ax = ax
65 | else:
66 | _, self.ax = plt.subplots()
67 | self.set_scale(scale=scale)
68 | self._permutation = permutation
69 | self._boundary_scale = scale
70 | # Container for the axis labels supplied by the user
71 | self._labels = dict()
72 | self._corner_labels = dict()
73 | self._ticks = dict()
74 | # Container for the redrawing of labels
75 | self._to_remove = []
76 | self._connect_callbacks()
77 | # Background
78 | self._background_parameters = None
79 | # Cache for the background triangle object, so it can be removed and redrawn as needed.
80 | self._background_triangle = None
81 | self.set_background_color(color="whitesmoke", zorder=-1000, alpha=0.75)
82 |
83 | def _connect_callbacks(self):
84 | """Connect resize matplotlib callbacks."""
85 | figure = self.get_figure()
86 | callback = partial(mpl_redraw_callback, tax=self)
87 | event_names = ('resize_event', 'draw_event')
88 | for event_name in event_names:
89 | figure.canvas.mpl_connect(event_name, callback)
90 |
91 | def __repr__(self):
92 | return "TernaryAxesSubplot: %s" % self.ax.__hash__()
93 |
94 | def get_axes(self):
95 | """Returns the underlying matplotlib AxesSubplot object."""
96 | return self.ax
97 |
98 | def get_figure(self):
99 | """Return the underlying matplotlib figure object."""
100 | ax = self.get_axes()
101 | return ax.get_figure()
102 |
103 | def set_scale(self, scale=None):
104 | self._scale = scale
105 | self.resize_drawing_canvas()
106 |
107 | def get_scale(self):
108 | return self._scale
109 |
110 | def set_axis_limits(self, axis_limits=None):
111 | """
112 | Set min and max data limits for each of the three axes.
113 |
114 | axis_limits = dict
115 | keys are 'b','l' and 'r' for the three axes
116 | vals are lists of the min and max values for the axis in
117 | data units.
118 | """
119 | self._axis_limits = axis_limits
120 |
121 | def get_axis_limits(self):
122 | return self._axis_limits
123 |
124 | # Title and Axis Labels
125 |
126 | def set_title(self, title, **kwargs):
127 | """Sets the title on the underlying matplotlib AxesSubplot."""
128 | ax = self.get_axes()
129 | ax.set_title(title, **kwargs)
130 |
131 | def left_axis_label(self, label, position=None, rotation=60, offset=0.08,
132 | **kwargs):
133 | """
134 | Sets the label on the left axis.
135 |
136 | Parameters
137 | ----------
138 | label: String
139 | The axis label
140 | position: 3-Tuple of floats, None
141 | The position of the text label
142 | rotation: float, 60
143 | The angle of rotation of the label
144 | offset: float,
145 | Used to compute the distance of the label from the axis
146 | kwargs:
147 | Any kwargs to pass through to matplotlib.
148 | """
149 |
150 | if not position:
151 | position = (-offset, 3./5, 2./5)
152 | self._labels["left"] = (label, position, rotation, kwargs)
153 |
154 | def right_axis_label(self, label, position=None, rotation=-60, offset=0.08,
155 | **kwargs):
156 |
157 | """
158 | Sets the label on the right axis.
159 |
160 | Parameters
161 | ----------
162 | label: String
163 | The axis label
164 | position: 3-Tuple of floats, None
165 | The position of the text label
166 | rotation: float, -60
167 | The angle of rotation of the label
168 | offset: float,
169 | Used to compute the distance of the label from the axis
170 | kwargs:
171 | Any kwargs to pass through to matplotlib.
172 | """
173 |
174 | if not position:
175 | position = (2. / 5 + offset, 3. / 5, 0)
176 | self._labels["right"] = (label, position, rotation, kwargs)
177 |
178 | def bottom_axis_label(self, label, position=None, rotation=0, offset=0.02,
179 | **kwargs):
180 | """
181 | Sets the label on the bottom axis.
182 |
183 | Parameters
184 | ----------
185 | label: String
186 | The axis label
187 | position: 3-Tuple of floats, None
188 | The position of the text label
189 | rotation: float, 0
190 | The angle of rotation of the label
191 | offset: float,
192 | Used to compute the distance of the label from the axis
193 | kwargs:
194 | Any kwargs to pass through to matplotlib.
195 | """
196 |
197 | if not position:
198 | position = (0.5, -offset / 2., 0.5)
199 | self._labels["bottom"] = (label, position, rotation, kwargs)
200 |
201 | def right_corner_label(self, label, position=None, rotation=0, offset=0.08,
202 | **kwargs):
203 | """
204 | Sets the label on the right corner (complements left axis).
205 |
206 | Parameters
207 | ----------
208 | label: String
209 | The axis label
210 | position: 3-Tuple of floats, None
211 | The position of the text label
212 | rotation: float, 0
213 | The angle of rotation of the label
214 | offset: float,
215 | Used to compute the distance of the label from the axis
216 | kwargs:
217 | Any kwargs to pass through to matplotlib.
218 | """
219 |
220 | if not position:
221 | position = (1, offset / 2, 0)
222 | self._corner_labels["right"] = (label, position, rotation, kwargs)
223 |
224 | def left_corner_label(self, label, position=None, rotation=0, offset=0.08,
225 | **kwargs):
226 | """
227 | Sets the label on the left corner (complements right axis.)
228 |
229 | Parameters
230 | ----------
231 | label: string
232 | The axis label
233 | position: 3-Tuple of floats, None
234 | The position of the text label
235 | rotation: float, 0
236 | The angle of rotation of the label
237 | offset: float,
238 | Used to compute the distance of the label from the axis
239 | kwargs:
240 | Any kwargs to pass through to matplotlib.
241 | """
242 |
243 | if not position:
244 | position = (-offset / 2, offset / 2, 0)
245 | self._corner_labels["left"] = (label, position, rotation, kwargs)
246 |
247 | def top_corner_label(self, label, position=None, rotation=0, offset=0.2,
248 | **kwargs):
249 | """
250 | Sets the label on the bottom axis.
251 |
252 | Parameters
253 | ----------
254 | label: String
255 | The axis label
256 | position: 3-Tuple of floats, None
257 | The position of the text label
258 | rotation: float, 0
259 | The angle of rotation of the label
260 | offset: float,
261 | Used to compute the distance of the label from the axis
262 | kwargs:
263 | Any kwargs to pass through to matplotlib.
264 | """
265 |
266 | if not position:
267 | position = (-offset / 2, 1 + offset, 0)
268 | self._corner_labels["top"] = (label, position, rotation, kwargs)
269 |
270 | def annotate(self, text, position, **kwargs):
271 | ax = self.get_axes()
272 | p = project_point(position)
273 | ax.annotate(text, (p[0], p[1]), **kwargs)
274 |
275 | # Boundary and Gridlines
276 |
277 | def boundary(self, scale=None, axes_colors=None, **kwargs):
278 | # Sometimes you want to draw a bigger boundary
279 | if not scale:
280 | scale = self._boundary_scale # defaults to self._scale
281 | ax = self.get_axes()
282 | self.resize_drawing_canvas(scale)
283 | lines.boundary(scale=scale, ax=ax, axes_colors=axes_colors, **kwargs)
284 |
285 | def gridlines(self, multiple=None, horizontal_kwargs=None, left_kwargs=None,
286 | right_kwargs=None, **kwargs):
287 | ax = self.get_axes()
288 | scale = self.get_scale()
289 | lines.gridlines(scale=scale, multiple=multiple,
290 | ax=ax, horizontal_kwargs=horizontal_kwargs,
291 | left_kwargs=left_kwargs, right_kwargs=right_kwargs,
292 | **kwargs)
293 |
294 | # Various Lines
295 |
296 | def line(self, p1, p2, **kwargs):
297 | ax = self.get_axes()
298 | lines.line(ax, p1, p2, **kwargs)
299 |
300 | def horizontal_line(self, i, **kwargs):
301 | ax = self.get_axes()
302 | scale = self.get_scale()
303 | lines.horizontal_line(ax, scale, i, **kwargs)
304 |
305 | def left_parallel_line(self, i, **kwargs):
306 | ax = self.get_axes()
307 | scale = self.get_scale()
308 | lines.left_parallel_line(ax, scale, i, **kwargs)
309 |
310 | def right_parallel_line(self, i, **kwargs):
311 | ax = self.get_axes()
312 | scale = self.get_scale()
313 | lines.right_parallel_line(ax, scale, i, **kwargs)
314 |
315 | # Matplotlib passthroughs
316 |
317 | def close(self):
318 | fig = self.get_figure()
319 | plt.close(fig)
320 |
321 | def legend(self, *args, **kwargs):
322 | ax = self.get_axes()
323 | ax.legend(*args, **kwargs)
324 |
325 | def savefig(self, filename, **kwargs):
326 | self._redraw_labels()
327 | fig = self.get_figure()
328 | if 'dpi' not in kwargs:
329 | kwargs['dpi'] = 200
330 | fig.savefig(filename, **kwargs)
331 |
332 | def show(self, *args, **kwargs):
333 | self._redraw_labels()
334 | plt.show(*args, **kwargs)
335 |
336 | # Axis ticks
337 |
338 | def clear_matplotlib_ticks(self, axis="both"):
339 | """Clears the default matplotlib ticks."""
340 | ax = self.get_axes()
341 | plotting.clear_matplotlib_ticks(ax=ax, axis=axis)
342 |
343 | def get_ticks_from_axis_limits(self, multiple=1):
344 | """
345 | Taking self._axis_limits and self._boundary_scale get the scaled
346 | ticks for all three axes and store them in self._ticks under the
347 | keys 'b' for bottom, 'l' for left and 'r' for right axes.
348 | """
349 | for k in ['b', 'l', 'r']:
350 | self._ticks[k] = np.linspace(
351 | self._axis_limits[k][0],
352 | self._axis_limits[k][1],
353 | int(self._boundary_scale / float(multiple) + 1)
354 | ).tolist()
355 |
356 | def set_custom_ticks(self, locations=None, clockwise=False, multiple=1,
357 | axes_colors=None, tick_formats=None, **kwargs):
358 | """
359 | Having called get_ticks_from_axis_limits, set the custom ticks on the
360 | plot.
361 | """
362 | for k in ['b', 'l', 'r']:
363 | self.ticks(ticks=self._ticks[k], locations=locations,
364 | axis=k, clockwise=clockwise, multiple=multiple,
365 | axes_colors=axes_colors, tick_formats=tick_formats,
366 | **kwargs)
367 |
368 | def ticks(self, ticks=None, locations=None, multiple=1, axis='blr',
369 | clockwise=False, axes_colors=None, tick_formats=None, **kwargs):
370 | ax = self.get_axes()
371 | scale = self.get_scale()
372 | lines.ticks(ax, scale, ticks=ticks, locations=locations,
373 | multiple=multiple, clockwise=clockwise, axis=axis,
374 | axes_colors=axes_colors, tick_formats=tick_formats,
375 | **kwargs)
376 |
377 | # Redrawing and resizing
378 |
379 | def resize_drawing_canvas(self, scale=None):
380 | ax = self.get_axes()
381 | if not scale:
382 | scale = self.get_scale()
383 | plotting.resize_drawing_canvas(ax, scale=scale)
384 |
385 | def _redraw_labels(self):
386 | """Redraw axis labels, typically after draw or resize events."""
387 | ax = self.get_axes()
388 | # Remove any previous labels
389 | for mpl_object in self._to_remove:
390 | mpl_object.remove()
391 | self._to_remove = []
392 | # Redraw the labels with the appropriate angles
393 | label_data = list(self._labels.values())
394 | label_data.extend(self._corner_labels.values())
395 | for (label, position, rotation, kwargs) in label_data:
396 | transform = ax.transAxes
397 | x, y = project_point(position)
398 | # Calculate the new angle.
399 | position = np.array([x, y])
400 | new_rotation = ax.transData.transform_angles(
401 | np.array((rotation,)), position.reshape((1, 2)))[0]
402 | text = ax.text(x, y, label, rotation=new_rotation,
403 | transform=transform, horizontalalignment="center",
404 | **kwargs)
405 | text.set_rotation_mode("anchor")
406 | self._to_remove.append(text)
407 |
408 | def convert_coordinates(self, points, axisorder='blr'):
409 | """
410 | Convert data coordinates to simplex coordinates for plotting
411 | in the case that axis limits have been applied.
412 | """
413 | return convert_coordinates_sequence(points,self._boundary_scale,
414 | self._axis_limits, axisorder)
415 |
416 | # Various Plots
417 |
418 | def scatter(self, points, **kwargs):
419 | ax = self.get_axes()
420 | permutation = self._permutation
421 | plot_ = plotting.scatter(points, ax=ax, permutation=permutation,
422 | **kwargs)
423 | return plot_
424 |
425 | def plot(self, points, **kwargs):
426 | ax = self.get_axes()
427 | permutation = self._permutation
428 | plotting.plot(points, ax=ax, permutation=permutation,
429 | **kwargs)
430 |
431 | def plot_colored_trajectory(self, points, cmap=None, **kwargs):
432 | ax = self.get_axes()
433 | permutation = self._permutation
434 | plotting.plot_colored_trajectory(points, cmap=cmap, ax=ax,
435 | permutation=permutation, **kwargs)
436 |
437 | def heatmap(self, data, scale=None, cmap=None, scientific=False,
438 | style='triangular', colorbar=True, use_rgba=False,
439 | vmin=None, vmax=None, cbarlabel=None, cb_kwargs=None):
440 | permutation = self._permutation
441 | if not scale:
442 | scale = self.get_scale()
443 | if style.lower()[0] == 'd':
444 | self._boundary_scale = scale + 1
445 | ax = self.get_axes()
446 | heatmapping.heatmap(data, scale, cmap=cmap, style=style, ax=ax,
447 | scientific=scientific, colorbar=colorbar,
448 | permutation=permutation, use_rgba=use_rgba,
449 | vmin=vmin, vmax=vmax, cbarlabel=cbarlabel,
450 | cb_kwargs=cb_kwargs)
451 |
452 | def heatmapf(self, func, scale=None, cmap=None, boundary=True,
453 | style='triangular', colorbar=True, scientific=False,
454 | vmin=None, vmax=None, cbarlabel=None, cb_kwargs=None):
455 | if not scale:
456 | scale = self.get_scale()
457 | if style.lower()[0] == 'd':
458 | self._boundary_scale = scale + 1
459 | permutation = self._permutation
460 | ax = self.get_axes()
461 | heatmapping.heatmapf(func, scale, cmap=cmap, style=style,
462 | boundary=boundary, ax=ax, scientific=scientific,
463 | colorbar=colorbar, permutation=permutation,
464 | vmin=vmin, vmax=vmax, cbarlabel=cbarlabel,
465 | cb_kwargs=cb_kwargs)
466 |
467 | def set_background_color(self, color="whitesmoke", zorder=-1000, alpha=0.75):
468 | self._background_parameters = BackgroundParameters(color=color, alpha=alpha, zorder=zorder)
469 | self._draw_background()
470 |
471 | def _draw_background(self):
472 | color, alpha, zorder = self._background_parameters
473 | scale = self.get_scale()
474 | ax = self.get_axes()
475 |
476 | # Remove any existing background
477 | if self._background_triangle:
478 | self._background_triangle.remove()
479 |
480 | # Draw the background
481 | self._background_triangle = heatmapping.background_color(ax, color, scale, alpha=alpha, zorder=zorder)[0]
482 |
--------------------------------------------------------------------------------
/tests/test_heatmapping.py:
--------------------------------------------------------------------------------
1 |
2 | import unittest
3 |
4 | from numpy.testing import assert_array_almost_equal
5 |
6 | from ternary.heatmapping import triangle_coordinates, alt_triangle_coordinates, hexagon_coordinates
7 | from ternary.helpers import SQRT3OVER2
8 |
9 | class FunctionCases(unittest.TestCase):
10 |
11 | def test_coordinates(self):
12 | # Should be an equalilateral triangle
13 | coords = triangle_coordinates(1, 1, 1)
14 | expected = [(1, 1, 1), (2, 1, 0), (1, 2, 0)]
15 | self.assertEqual(coords, expected)
16 |
17 | coords = alt_triangle_coordinates(2, 2, 2)
18 | expected = [(2, 3, 1), (3, 2, 1), (3, 3, 0)]
19 | self.assertEqual(coords, expected)
20 |
21 | coords = hexagon_coordinates(1, 1, 1)
22 | expected = [(2./3, 5./3, 1.0), (4./3, 4./3, 1.0), (5./3, 2./3, 1.0),
23 | (4./3, 1./3, 1.0), (2./3, 2./3, 1.), (1./3, 4./3, 1.0)]
24 | assert_array_almost_equal(coords, expected)
25 |
26 |
27 | if __name__ == "__main__":
28 | unittest.main()
29 |
--------------------------------------------------------------------------------
/tests/test_helpers.py:
--------------------------------------------------------------------------------
1 | import random
2 | import unittest
3 |
4 | from numpy.testing import assert_array_equal, assert_array_almost_equal
5 |
6 | from ternary.helpers import normalize, project_point, planar_to_coordinates, simplex_iterator, SQRT3OVER2
7 |
8 |
9 | class FunctionCases(unittest.TestCase):
10 |
11 | def test_normalize(self):
12 | l = [1, 2, 3]
13 | normalized = normalize(l)
14 | expected = [1./6, 2./6, 3./6]
15 | self.assertEqual(normalized, expected)
16 | # Test Exception
17 | self.assertRaises(ValueError, normalize, [0, 0, 0])
18 |
19 | def test_simplex_iterator(self):
20 | scale = 0
21 | expected = [(0, 0, 0)]
22 | points = list(simplex_iterator(scale=scale))
23 | self.assertEqual(points, expected)
24 |
25 | scale = 1
26 | expected = [(0, 0, 1), (0, 1, 0), (1, 0, 0)]
27 | points = list(simplex_iterator(scale=scale))
28 | self.assertEqual(points, expected)
29 |
30 | scale = 2
31 | expected = [(0, 0, 2), (0, 1, 1), (0, 2, 0), (1, 0, 1), (1, 1, 0), (2, 0, 0)]
32 | points = list(simplex_iterator(scale=scale))
33 | self.assertEqual(points, expected)
34 |
35 | scale = 3
36 | expected = [(0, 0, 3), (0, 1, 2), (0, 2, 1), (0, 3, 0), (1, 0, 2), (1, 1, 1), (1, 2, 0), (2, 0, 1), (2, 1, 0),
37 | (3, 0, 0)]
38 | points = list(simplex_iterator(scale=scale))
39 | self.assertEqual(points, expected)
40 |
41 | def test_simplex_iterator_without_boundary(self):
42 | scale = 0
43 | expected = []
44 | points = list(simplex_iterator(scale=scale, boundary=False))
45 | self.assertEqual(points, expected)
46 |
47 | scale = 1
48 | expected = []
49 | points = list(simplex_iterator(scale=scale, boundary=False))
50 | self.assertEqual(points, expected)
51 |
52 | scale = 2
53 | expected = []
54 | points = list(simplex_iterator(scale=scale, boundary=False))
55 | self.assertEqual(points, expected)
56 |
57 | scale = 3
58 | expected = [(1, 1, 1)]
59 | points = list(simplex_iterator(scale=scale, boundary=False))
60 | self.assertEqual(points, expected)
61 |
62 | @staticmethod
63 | def test_project_point():
64 | point = (0, 0, 0)
65 | projected = project_point(point)
66 | expected = (0.0, 0.0)
67 | assert_array_equal(projected, expected)
68 |
69 | point = (1, 0, 0)
70 | projected = project_point(point)
71 | expected = (1.0, 0.0)
72 | assert_array_equal(projected, expected)
73 |
74 | point = (0, 1, 0)
75 | projected = project_point(point)
76 | expected = (0.5, SQRT3OVER2)
77 | assert_array_equal(projected, expected)
78 |
79 | point = (0, 0, 1)
80 | projected = project_point(point)
81 | expected = (0, 0)
82 | assert_array_equal(projected, expected)
83 |
84 | point = (1, 1, 1)
85 | projected = project_point(point)
86 | expected = (1.5, SQRT3OVER2)
87 | assert_array_equal(projected, expected)
88 |
89 | @staticmethod
90 | def test_planar_to_coordinates():
91 | projected = (0.0, 0.0)
92 | point = planar_to_coordinates(projected, scale=100)
93 | expected = (0.0, 0.0, 100.0)
94 | assert_array_equal(point, expected)
95 |
96 | projected = (100.0, 0.0)
97 | point = planar_to_coordinates(projected, scale=100)
98 | expected = (100.0, 0.0, 0.0)
99 | assert_array_equal(point, expected)
100 |
101 | projected = (40.0, 0)
102 | point = planar_to_coordinates(projected, scale=100)
103 | expected = (40.0, 0.0, 60.0)
104 | assert_array_equal(point, expected)
105 |
106 | projected = (10.0, SQRT3OVER2)
107 | point = planar_to_coordinates(projected, scale=100)
108 | expected = (9.5, 1.0, 89.5)
109 | assert_array_equal(point, expected)
110 |
111 | projected = (10.0, SQRT3OVER2)
112 | point = planar_to_coordinates(projected, scale=100)
113 | expected = (9.5, 1.0, 89.5)
114 | assert_array_equal(point, expected)
115 |
116 | @staticmethod
117 | def test_coordinate_maps():
118 | """Test that the coordinate projection functions are in fact inverses."""
119 | def random_point(scale=1):
120 | x = random.random() * scale
121 | y = random.random() * (scale - x)
122 | z = scale - x - y
123 | return x, y, z
124 |
125 | for _ in range(20):
126 | scale = random.randint(1, 100)
127 | p = random_point(scale=scale)
128 | projected = project_point(p)
129 | p2 = planar_to_coordinates(projected, scale=scale)
130 | assert_array_almost_equal(p, p2)
131 |
132 |
133 | if __name__ == "__main__":
134 | unittest.main()
135 |
--------------------------------------------------------------------------------