pyrolite 0.0.14__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__init__.py +10 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/_version.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/alteration.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/classification.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/compositions.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/geochem.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/melts.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/norm.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/normalisation.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/plot.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/_version.py +21 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/alteration.py +66 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/classification.py +222 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__init__.py +9 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/aggregate.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/codata.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/impute.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/renorm.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/aggregate.py +391 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/codata.py +266 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/impute.py +82 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/renorm.py +40 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/compositions.py +524 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_CFB_Dataset_List.csv +42 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_Convergent_Dataset_List.csv +42 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OBFB_Dataset_List.csv +5 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OIB_Dataset_List.csv +49 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OceanicPlateau_Dataset_List.csv +18 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/contents.json +1 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/__pycache__/env.cpython-35.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/__pycache__/env.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/env.py +1063 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Ba.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Bs.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.F.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O3.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Pc.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Ph.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.R.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S3.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.T1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.T2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U3.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.modelfields +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.nan.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.none.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/aphanitic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/gabbroic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/peralkalinity.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/phaneritic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/ultramafic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/CH_PalmeONeill2014.csv +95 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DDMM_WorkmanHart2005.csv +105 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DMM_WorkmanHart2005.csv +105 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DM_SaltersStrake2004.csv +95 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/EDMM_WorkmanHart2005.csv +105 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/PM_PalmeONeill2014.csv +95 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/timescale/geotimescale_spans.csv +180 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/geochem.py +821 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/melts.py +92 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__init__.py +10 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/db.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/ions.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/mineral.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/sites.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/db.py +88 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/ions.py +78 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/mineral.py +587 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/sites.py +134 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/norm.py +224 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/normalisation.py +204 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/plot.py +514 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__init__.py +13 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/database.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/env.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/general.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/georoc.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/math.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/melts.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/multip.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/multiprocessing.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/pd.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/plot.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/skl.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/spatial.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/text.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/time.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/wfs.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/database.py +88 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/env.py +81 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/general.py +266 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/georoc.py +444 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/math.py +371 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/melts.py +397 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/multip.py +29 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/multiprocessing.py +29 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/pd.py +214 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/plot.py +345 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/skl.py +847 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/spatial.py +91 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/text.py +207 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/time.py +224 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/wfs.py +10 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/PKG-INFO +61 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/SOURCES.txt +83 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/dependency_links.txt +1 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/requires.txt +47 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from copy import copy
|
|
3
|
+
from types import MethodType
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
from scipy import interpolate
|
|
8
|
+
from scipy.stats.kde import gaussian_kde
|
|
9
|
+
from scipy.spatial import ConvexHull
|
|
10
|
+
import matplotlib.pyplot as plt
|
|
11
|
+
import matplotlib.colors as colors
|
|
12
|
+
import matplotlib.lines as mlines
|
|
13
|
+
import matplotlib.patches as patches
|
|
14
|
+
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
|
15
|
+
import matplotlib.axes as matax
|
|
16
|
+
from matplotlib.transforms import Bbox
|
|
17
|
+
import logging
|
|
18
|
+
|
|
19
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
20
|
+
logger = logging.getLogger()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def add_legend_items(ax):
|
|
24
|
+
|
|
25
|
+
handles_original = []
|
|
26
|
+
handles_original += ax.lines + ax.patches + ax.collections + ax.containers
|
|
27
|
+
# support parasite axes:
|
|
28
|
+
if hasattr(ax, "parasites"):
|
|
29
|
+
for axx in ax.parasites:
|
|
30
|
+
handles_original += (
|
|
31
|
+
axx.lines + axx.patches + axx.collections + axx.containers
|
|
32
|
+
)
|
|
33
|
+
handles, labels = [], []
|
|
34
|
+
for handle in handles_original:
|
|
35
|
+
label = handle.get_label()
|
|
36
|
+
if label and not label.startswith("_"):
|
|
37
|
+
handles.append(handle)
|
|
38
|
+
labels.append(label)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def modify_legend_handles(ax, **kwargs):
|
|
42
|
+
"""
|
|
43
|
+
Modify the handles of a legend based for a single axis.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
ax: matplotlib.axes.Axes
|
|
48
|
+
Axis for which to obtain modifed legend handles.
|
|
49
|
+
kwargs:
|
|
50
|
+
Keyword arguments to be passed to the handles.
|
|
51
|
+
|
|
52
|
+
Returns
|
|
53
|
+
-------
|
|
54
|
+
tuple
|
|
55
|
+
Handles, labels to be passed to a legend call.
|
|
56
|
+
"""
|
|
57
|
+
hndls, labls = ax.get_legend_handles_labels()
|
|
58
|
+
_hndls = []
|
|
59
|
+
for h in hndls:
|
|
60
|
+
_h = copy(h)
|
|
61
|
+
print(_h, dir(_h))
|
|
62
|
+
_h.update(kwargs)
|
|
63
|
+
_hndls.append(_h)
|
|
64
|
+
return _hndls, labls
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def add_colorbar(mappable, **kwargs):
|
|
68
|
+
"""
|
|
69
|
+
Adds a colorbar to a given mappable object.
|
|
70
|
+
|
|
71
|
+
Source: http://joseph-long.com/writing/colorbars/
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
mappable :
|
|
76
|
+
The Image, ContourSet, etc. to which the colorbar applies.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
----------
|
|
80
|
+
colorbar: matplotlib.colorbar.Colorbar
|
|
81
|
+
"""
|
|
82
|
+
ax = kwargs.get("ax", None)
|
|
83
|
+
if hasattr(mappable, "axes"):
|
|
84
|
+
ax = ax or mappable.axes
|
|
85
|
+
elif hasattr(mappable, "ax"):
|
|
86
|
+
ax = ax or mappable.ax
|
|
87
|
+
|
|
88
|
+
position = kwargs.pop("position", "right")
|
|
89
|
+
size = kwargs.pop("size", "5%")
|
|
90
|
+
pad = kwargs.pop("pad", 0.05)
|
|
91
|
+
|
|
92
|
+
fig = ax.figure
|
|
93
|
+
divider = make_axes_locatable(ax)
|
|
94
|
+
cax = divider.append_axes(position, size=size, pad=pad)
|
|
95
|
+
return fig.colorbar(mappable, cax=cax, **kwargs)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def ABC_to_tern_xy(ABC):
|
|
99
|
+
(A, B, C) = ABC
|
|
100
|
+
T = A + B + C
|
|
101
|
+
A_n, B_n, C_n = np.divide(A, T), np.divide(B, T), np.divide(C, T)
|
|
102
|
+
xdata = 100.0 * (
|
|
103
|
+
(C_n / np.sin(np.pi / 3) + A_n / np.tan(np.pi / 3.0)) * np.sin(np.pi / 3.0)
|
|
104
|
+
)
|
|
105
|
+
ydata = 100.0 * (2.0 / (3.0 ** 0.5)) * A_n * np.sin(np.pi / 3.0)
|
|
106
|
+
return xdata, ydata
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def tern_heatmapcoords(data, scale=10, bins=10):
|
|
110
|
+
# this appears to cause problems for ternary density diagrams
|
|
111
|
+
x, y = ABC_to_tern_xy(data)
|
|
112
|
+
xydata = np.vstack((x, y))
|
|
113
|
+
k = gaussian_kde(xydata)
|
|
114
|
+
|
|
115
|
+
tridata = dict()
|
|
116
|
+
step = scale // bins
|
|
117
|
+
for i in np.arange(0, scale + 1, step):
|
|
118
|
+
for j in np.arange(0, scale + 1 - i, step):
|
|
119
|
+
datacoord = i, j
|
|
120
|
+
# datacoord = i+0.5*step, j+0.5*step
|
|
121
|
+
tridata[(i, j)] = np.float(k(np.vstack(datacoord)))
|
|
122
|
+
|
|
123
|
+
return tridata
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def proxy_rect(**kwargs):
|
|
127
|
+
"""
|
|
128
|
+
Generates a legend proxy for a filled region.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
----------
|
|
132
|
+
rect: matplotlib.patches.Rectangle
|
|
133
|
+
"""
|
|
134
|
+
return patches.Rectangle((0, 0), 1, 1, **kwargs)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def proxy_line(**kwargs):
|
|
138
|
+
"""
|
|
139
|
+
Generates a legend proxy for a line region.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
----------
|
|
143
|
+
line: matplotlib.lines.Line2D
|
|
144
|
+
"""
|
|
145
|
+
return mlines.Line2D(range(1), range(1), **kwargs)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def draw_vector(v0, v1, ax=None, **kwargs):
|
|
149
|
+
"""
|
|
150
|
+
Plots an arrow represnting the direction and magnitue of a principal
|
|
151
|
+
component on a biaxial plot.
|
|
152
|
+
|
|
153
|
+
Todo: update for ternary plots.
|
|
154
|
+
|
|
155
|
+
Modified after Jake VanderPlas' Python Data Science Handbook
|
|
156
|
+
https://jakevdp.github.io/PythonDataScienceHandbook/ \
|
|
157
|
+
05.09-principal-component-analysis.html
|
|
158
|
+
"""
|
|
159
|
+
ax = ax
|
|
160
|
+
arrowprops = dict(arrowstyle="->", linewidth=2, shrinkA=0, shrinkB=0)
|
|
161
|
+
arrowprops.update(kwargs)
|
|
162
|
+
ax.annotate("", v1, v0, arrowprops=arrowprops)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def vector_to_line(
|
|
166
|
+
mu: np.array, vector: np.array, variance: float, spans: int = 4, expand: int = 10
|
|
167
|
+
):
|
|
168
|
+
"""
|
|
169
|
+
Creates an array of points representing a line along a vector - typically
|
|
170
|
+
for principal component analysis.
|
|
171
|
+
|
|
172
|
+
Modified after Jake VanderPlas' Python Data Science Handbook
|
|
173
|
+
https://jakevdp.github.io/PythonDataScienceHandbook/05.09-principal-component-analysis.html
|
|
174
|
+
"""
|
|
175
|
+
length = np.sqrt(variance)
|
|
176
|
+
parts = np.linspace(-spans, spans, expand * 2 * spans + 1)
|
|
177
|
+
line = length * np.dot(parts[:, np.newaxis], vector[np.newaxis, :]) + mu
|
|
178
|
+
line = length * parts.reshape(parts.shape[0], 1) * vector + mu
|
|
179
|
+
return line
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def plot_2dhull(ax, data, splines=False, s=0, **plotkwargs):
|
|
183
|
+
"""
|
|
184
|
+
Plots a 2D convex hull around an array of xy data points.
|
|
185
|
+
"""
|
|
186
|
+
chull = ConvexHull(data, incremental=True)
|
|
187
|
+
x, y = data[chull.vertices].T
|
|
188
|
+
if not splines:
|
|
189
|
+
lines = ax.plot(np.append(x, [x[0]]), np.append(y, [y[0]]), **plotkwargs)
|
|
190
|
+
else:
|
|
191
|
+
# https://stackoverflow.com/questions/33962717/interpolating-a-closed-curve-using-scipy
|
|
192
|
+
tck, u = interpolate.splprep([x, y], per=True, s=s)
|
|
193
|
+
xi, yi = interpolate.splev(np.linspace(0, 1, 1000), tck)
|
|
194
|
+
lines = ax.plot(xi, yi, **plotkwargs)
|
|
195
|
+
return lines
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def nan_scatter(xdata, ydata, ax=None, axes_width=0.2, **kwargs):
|
|
199
|
+
"""
|
|
200
|
+
Scatter plot with additional marginal axes to plot data for which data is partially
|
|
201
|
+
missing. Additional keyword arguments are passed to matplotlib.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
-----------
|
|
205
|
+
xdata : np.ndarray | pd.Series
|
|
206
|
+
X data
|
|
207
|
+
ydata: np.ndarray | pd.Series
|
|
208
|
+
Y data
|
|
209
|
+
ax : matplotlib.axes.Axes
|
|
210
|
+
Axes on which to plot.
|
|
211
|
+
axes_width : float
|
|
212
|
+
Width of the marginal axes.
|
|
213
|
+
"""
|
|
214
|
+
if ax is None:
|
|
215
|
+
fig, ax = plt.subplots(1)
|
|
216
|
+
|
|
217
|
+
ax.scatter(xdata, ydata, **kwargs)
|
|
218
|
+
|
|
219
|
+
if hasattr(ax, "divider"): # Don't rebuild axes
|
|
220
|
+
div = ax.divider
|
|
221
|
+
nanaxx = div.nanaxx
|
|
222
|
+
nanaxy = div.nanaxy
|
|
223
|
+
else: # Build axes
|
|
224
|
+
ax.yaxis.set_tick_params(labelleft=False, left=False)
|
|
225
|
+
ax.xaxis.set_tick_params(labelbottom=False, bottom=False)
|
|
226
|
+
ax.spines["top"].set_visible(False)
|
|
227
|
+
ax.spines["right"].set_visible(False)
|
|
228
|
+
|
|
229
|
+
div = make_axes_locatable(ax)
|
|
230
|
+
ax.divider = div
|
|
231
|
+
|
|
232
|
+
nanaxx = div.append_axes("bottom", axes_width, pad=0, sharex=ax)
|
|
233
|
+
div.nanaxx = nanaxx
|
|
234
|
+
nanaxx.invert_yaxis()
|
|
235
|
+
nanaxx.yaxis.set_visible(False)
|
|
236
|
+
nanaxx.spines["left"].set_visible(False)
|
|
237
|
+
nanaxx.spines["right"].set_visible(False)
|
|
238
|
+
nanaxx.set_facecolor("none")
|
|
239
|
+
|
|
240
|
+
nanaxy = div.append_axes("left", axes_width, pad=0, sharey=ax)
|
|
241
|
+
div.nanaxy = nanaxy
|
|
242
|
+
nanaxy.invert_xaxis()
|
|
243
|
+
nanaxy.xaxis.set_visible(False)
|
|
244
|
+
nanaxy.spines["top"].set_visible(False)
|
|
245
|
+
nanaxy.spines["bottom"].set_visible(False)
|
|
246
|
+
nanaxy.set_facecolor("none")
|
|
247
|
+
|
|
248
|
+
nanxdata = xdata[(np.isnan(ydata) & np.isfinite(xdata))]
|
|
249
|
+
nanydata = ydata[(np.isnan(xdata) & np.isfinite(ydata))]
|
|
250
|
+
|
|
251
|
+
yminmax = np.nanmin(ydata), np.nanmax(ydata)
|
|
252
|
+
no_ybins = 50
|
|
253
|
+
ybinwidth = (np.nanmax(ydata) - np.nanmin(ydata)) / no_ybins
|
|
254
|
+
ybins = np.linspace(np.nanmin(ydata), np.nanmax(ydata) + ybinwidth, no_ybins)
|
|
255
|
+
|
|
256
|
+
nanaxy.hist(nanydata, bins=ybins, orientation="horizontal", **kwargs)
|
|
257
|
+
nanaxy.scatter(
|
|
258
|
+
10 * np.ones_like(nanydata) + 5 * np.random.randn(len(nanydata)),
|
|
259
|
+
nanydata,
|
|
260
|
+
zorder=-1,
|
|
261
|
+
**kwargs
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
xminmax = np.nanmin(xdata), np.nanmax(xdata)
|
|
265
|
+
no_xbins = 50
|
|
266
|
+
xbinwidth = (np.nanmax(xdata) - np.nanmin(xdata)) / no_xbins
|
|
267
|
+
xbins = np.linspace(np.nanmin(xdata), np.nanmax(xdata) + xbinwidth, no_xbins)
|
|
268
|
+
|
|
269
|
+
nanaxx.hist(nanxdata, bins=xbins, **kwargs)
|
|
270
|
+
nanaxx.scatter(
|
|
271
|
+
nanxdata,
|
|
272
|
+
10 * np.ones_like(nanxdata) + 5 * np.random.randn(len(nanxdata)),
|
|
273
|
+
zorder=-1,
|
|
274
|
+
**kwargs
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
return ax
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def save_figure(
|
|
281
|
+
figure, save_at="", name="fig", save_fmts=["png"], output=False, **kwargs
|
|
282
|
+
):
|
|
283
|
+
"""
|
|
284
|
+
Save a figure at a specified location in a number of formats.
|
|
285
|
+
"""
|
|
286
|
+
default_config = dict(dpi=600, bbox_inches="tight", transparent=True)
|
|
287
|
+
config = default_config.copy()
|
|
288
|
+
config.update(kwargs)
|
|
289
|
+
for fmt in save_fmts:
|
|
290
|
+
out_filename = os.path.join(save_at, name + "." + fmt)
|
|
291
|
+
if output:
|
|
292
|
+
print("Saving " + out_filename)
|
|
293
|
+
figure.savefig(out_filename, format=fmt, **config)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def save_axes(ax, save_at="", name="fig", save_fmts=["png"], pad=0.0, **kwargs):
|
|
297
|
+
"""
|
|
298
|
+
Save either a single or multiple axes (from a single figure) based on their
|
|
299
|
+
extent. Uses the save_figure procedure to save at a specific location using
|
|
300
|
+
a number of formats.
|
|
301
|
+
"""
|
|
302
|
+
# Check if axes is a single axis or list of axes
|
|
303
|
+
|
|
304
|
+
if isinstance(ax, matax.Axes):
|
|
305
|
+
extent = get_full_extent(ax, pad=pad)
|
|
306
|
+
figure = ax.figure
|
|
307
|
+
else:
|
|
308
|
+
extent_items = []
|
|
309
|
+
for a in ax:
|
|
310
|
+
extent_items.append(get_full_extent(a, pad=pad))
|
|
311
|
+
figure = axes[0].figure
|
|
312
|
+
extent = Bbox.union([item for item in extent_items])
|
|
313
|
+
save_figure(
|
|
314
|
+
figure,
|
|
315
|
+
bbox_inches=extent,
|
|
316
|
+
save_at=save_at,
|
|
317
|
+
name=name,
|
|
318
|
+
save_fmts=save_fmts,
|
|
319
|
+
**kwargs
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def get_full_extent(ax, pad=0.0):
|
|
324
|
+
"""Get the full extent of an axes, including axes labels, tick labels, and
|
|
325
|
+
titles. Text objects are first drawn to define the extents."""
|
|
326
|
+
fig = ax.figure
|
|
327
|
+
fig.canvas.draw()
|
|
328
|
+
renderer = fig.canvas.renderer
|
|
329
|
+
|
|
330
|
+
items = [ax]
|
|
331
|
+
|
|
332
|
+
if len(ax.get_title()):
|
|
333
|
+
items += [ax.title]
|
|
334
|
+
|
|
335
|
+
for a in [ax.xaxis, ax.yaxis]:
|
|
336
|
+
if len(a.get_label_text()):
|
|
337
|
+
items += [a.label]
|
|
338
|
+
|
|
339
|
+
for t_lb in [ax.get_xticklabels(), ax.get_yticklabels()]:
|
|
340
|
+
if np.array([len(i.get_text()) > 0 for i in t_lb]).any():
|
|
341
|
+
items += t_lb
|
|
342
|
+
|
|
343
|
+
bbox = Bbox.union([item.get_window_extent(renderer) for item in items])
|
|
344
|
+
full_extent = bbox.expanded(1.0 + pad, 1.0 + pad)
|
|
345
|
+
return full_extent.transformed(ax.figure.dpi_scale_trans.inverted())
|