pychnosz 1.1.4__cp311-cp311-win_amd64.whl
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.
- pychnosz/__init__.py +129 -0
- pychnosz/biomolecules/__init__.py +29 -0
- pychnosz/biomolecules/ionize_aa.py +197 -0
- pychnosz/biomolecules/proteins.py +595 -0
- pychnosz/core/__init__.py +46 -0
- pychnosz/core/affinity.py +1256 -0
- pychnosz/core/animation.py +593 -0
- pychnosz/core/balance.py +334 -0
- pychnosz/core/basis.py +716 -0
- pychnosz/core/diagram.py +3336 -0
- pychnosz/core/equilibrate.py +813 -0
- pychnosz/core/equilibrium.py +554 -0
- pychnosz/core/info.py +821 -0
- pychnosz/core/retrieve.py +364 -0
- pychnosz/core/speciation.py +580 -0
- pychnosz/core/species.py +599 -0
- pychnosz/core/subcrt.py +1700 -0
- pychnosz/core/thermo.py +593 -0
- pychnosz/core/unicurve.py +1226 -0
- pychnosz/data/__init__.py +11 -0
- pychnosz/data/add_obigt.py +327 -0
- pychnosz/data/extdata/Berman/BDat17_2017.csv +2 -0
- pychnosz/data/extdata/Berman/Ber88_1988.csv +68 -0
- pychnosz/data/extdata/Berman/Ber90_1990.csv +5 -0
- pychnosz/data/extdata/Berman/DS10_2010.csv +6 -0
- pychnosz/data/extdata/Berman/FDM+14_2014.csv +2 -0
- pychnosz/data/extdata/Berman/Got04_2004.csv +5 -0
- pychnosz/data/extdata/Berman/JUN92_1992.csv +3 -0
- pychnosz/data/extdata/Berman/SHD91_1991.csv +12 -0
- pychnosz/data/extdata/Berman/VGT92_1992.csv +2 -0
- pychnosz/data/extdata/Berman/VPT01_2001.csv +3 -0
- pychnosz/data/extdata/Berman/VPV05_2005.csv +2 -0
- pychnosz/data/extdata/Berman/ZS92_1992.csv +11 -0
- pychnosz/data/extdata/Berman/sympy.R +99 -0
- pychnosz/data/extdata/Berman/testing/BA96.bib +12 -0
- pychnosz/data/extdata/Berman/testing/BA96_Berman.csv +21 -0
- pychnosz/data/extdata/Berman/testing/BA96_OBIGT.csv +21 -0
- pychnosz/data/extdata/Berman/testing/BA96_refs.csv +6 -0
- pychnosz/data/extdata/OBIGT/AD.csv +25 -0
- pychnosz/data/extdata/OBIGT/Berman_cr.csv +93 -0
- pychnosz/data/extdata/OBIGT/DEW.csv +211 -0
- pychnosz/data/extdata/OBIGT/H2O_aq.csv +4 -0
- pychnosz/data/extdata/OBIGT/SLOP98.csv +411 -0
- pychnosz/data/extdata/OBIGT/SUPCRT92.csv +178 -0
- pychnosz/data/extdata/OBIGT/inorganic_aq.csv +729 -0
- pychnosz/data/extdata/OBIGT/inorganic_cr.csv +273 -0
- pychnosz/data/extdata/OBIGT/inorganic_gas.csv +20 -0
- pychnosz/data/extdata/OBIGT/organic_aq.csv +1104 -0
- pychnosz/data/extdata/OBIGT/organic_cr.csv +481 -0
- pychnosz/data/extdata/OBIGT/organic_gas.csv +268 -0
- pychnosz/data/extdata/OBIGT/organic_liq.csv +533 -0
- pychnosz/data/extdata/OBIGT/testing/GEMSFIT.csv +43 -0
- pychnosz/data/extdata/OBIGT/testing/IGEM.csv +17 -0
- pychnosz/data/extdata/OBIGT/testing/Sandia.csv +8 -0
- pychnosz/data/extdata/OBIGT/testing/SiO2.csv +4 -0
- pychnosz/data/extdata/misc/AD03_Fig1a.csv +69 -0
- pychnosz/data/extdata/misc/AD03_Fig1b.csv +43 -0
- pychnosz/data/extdata/misc/AD03_Fig1c.csv +89 -0
- pychnosz/data/extdata/misc/AD03_Fig1d.csv +30 -0
- pychnosz/data/extdata/misc/BZA10.csv +5 -0
- pychnosz/data/extdata/misc/HW97_Cp.csv +90 -0
- pychnosz/data/extdata/misc/HWM96_V.csv +229 -0
- pychnosz/data/extdata/misc/LA19_test.csv +7 -0
- pychnosz/data/extdata/misc/Mer75_Table4.csv +42 -0
- pychnosz/data/extdata/misc/OBIGT_check.csv +423 -0
- pychnosz/data/extdata/misc/PM90.csv +7 -0
- pychnosz/data/extdata/misc/RH95.csv +23 -0
- pychnosz/data/extdata/misc/RH98_Table15.csv +17 -0
- pychnosz/data/extdata/misc/SC10_Rainbow.csv +19 -0
- pychnosz/data/extdata/misc/SK95.csv +55 -0
- pychnosz/data/extdata/misc/SOJSH.csv +61 -0
- pychnosz/data/extdata/misc/SS98_Fig5a.csv +81 -0
- pychnosz/data/extdata/misc/SS98_Fig5b.csv +84 -0
- pychnosz/data/extdata/misc/TKSS14_Fig2.csv +25 -0
- pychnosz/data/extdata/misc/bluered.txt +1000 -0
- pychnosz/data/extdata/protein/Cas/Cas_aa.csv +177 -0
- pychnosz/data/extdata/protein/Cas/Cas_uniprot.csv +186 -0
- pychnosz/data/extdata/protein/Cas/download.R +34 -0
- pychnosz/data/extdata/protein/Cas/mkaa.R +34 -0
- pychnosz/data/extdata/protein/POLG.csv +12 -0
- pychnosz/data/extdata/protein/TBD+05.csv +393 -0
- pychnosz/data/extdata/protein/TBD+05_aa.csv +393 -0
- pychnosz/data/extdata/protein/rubisco.csv +28 -0
- pychnosz/data/extdata/protein/rubisco.fasta +239 -0
- pychnosz/data/extdata/protein/rubisco_aa.csv +28 -0
- pychnosz/data/extdata/src/H2O92D.f.orig +3457 -0
- pychnosz/data/extdata/src/README.txt +5 -0
- pychnosz/data/extdata/taxonomy/names.dmp +215 -0
- pychnosz/data/extdata/taxonomy/nodes.dmp +63 -0
- pychnosz/data/extdata/thermo/Bdot_acirc.csv +60 -0
- pychnosz/data/extdata/thermo/buffer.csv +40 -0
- pychnosz/data/extdata/thermo/element.csv +135 -0
- pychnosz/data/extdata/thermo/groups.csv +6 -0
- pychnosz/data/extdata/thermo/opt.csv +2 -0
- pychnosz/data/extdata/thermo/protein.csv +506 -0
- pychnosz/data/extdata/thermo/refs.csv +343 -0
- pychnosz/data/extdata/thermo/stoich.csv.xz +0 -0
- pychnosz/data/loader.py +431 -0
- pychnosz/data/mod_obigt.py +322 -0
- pychnosz/data/obigt.py +471 -0
- pychnosz/data/worm.py +228 -0
- pychnosz/fortran/__init__.py +16 -0
- pychnosz/fortran/h2o92.dll +0 -0
- pychnosz/fortran/h2o92_interface.py +527 -0
- pychnosz/geochemistry/__init__.py +21 -0
- pychnosz/geochemistry/minerals.py +514 -0
- pychnosz/geochemistry/redox.py +500 -0
- pychnosz/models/__init__.py +47 -0
- pychnosz/models/archer_wang.py +165 -0
- pychnosz/models/berman.py +309 -0
- pychnosz/models/cgl.py +381 -0
- pychnosz/models/dew.py +997 -0
- pychnosz/models/hkf.py +523 -0
- pychnosz/models/hkf_helpers.py +222 -0
- pychnosz/models/iapws95.py +1113 -0
- pychnosz/models/supcrt92_fortran.py +238 -0
- pychnosz/models/water.py +480 -0
- pychnosz/utils/__init__.py +27 -0
- pychnosz/utils/expression.py +1074 -0
- pychnosz/utils/formula.py +830 -0
- pychnosz/utils/formula_ox.py +227 -0
- pychnosz/utils/reset.py +33 -0
- pychnosz/utils/units.py +259 -0
- pychnosz-1.1.4.dist-info/METADATA +197 -0
- pychnosz-1.1.4.dist-info/RECORD +128 -0
- pychnosz-1.1.4.dist-info/WHEEL +5 -0
- pychnosz-1.1.4.dist-info/licenses/LICENSE.txt +19 -0
- pychnosz-1.1.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
import plotly.express as px
|
|
2
|
+
import plotly.graph_objects as go
|
|
3
|
+
import copy
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import statistics
|
|
7
|
+
|
|
8
|
+
# Import chnosz functions
|
|
9
|
+
from .basis import basis
|
|
10
|
+
from .species import species
|
|
11
|
+
from .affinity import affinity
|
|
12
|
+
from .equilibrate import equilibrate
|
|
13
|
+
from .diagram import diagram, diagram_interactive
|
|
14
|
+
from .info import info
|
|
15
|
+
|
|
16
|
+
# Import chemlabel for formatting chemical formulas
|
|
17
|
+
try:
|
|
18
|
+
from WORMutils import chemlabel
|
|
19
|
+
except ImportError:
|
|
20
|
+
# Fallback: simple identity function if WORMutils is not available
|
|
21
|
+
def chemlabel(s):
|
|
22
|
+
"""Simple fallback for chemical label formatting."""
|
|
23
|
+
return str(s)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def __seq(start, end, by=None, length_out=None):
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
Mimic the seq() function in base R.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
len_provided = True if (length_out is not None) else False
|
|
33
|
+
by_provided = True if (by is not None) else False
|
|
34
|
+
if (not by_provided) & (not len_provided):
|
|
35
|
+
raise ValueError('At least by or n_points must be provided')
|
|
36
|
+
width = end - start
|
|
37
|
+
eps = pow(10.0, -14)
|
|
38
|
+
if by_provided:
|
|
39
|
+
if (abs(by) < eps):
|
|
40
|
+
raise ValueError('by must be non-zero.')
|
|
41
|
+
absby = abs(by)
|
|
42
|
+
if absby - width < eps:
|
|
43
|
+
length_out = int(width / absby)
|
|
44
|
+
else:
|
|
45
|
+
# by is too great, we assume by is actually length_out
|
|
46
|
+
length_out = int(by)
|
|
47
|
+
by = width / (by - 1)
|
|
48
|
+
else:
|
|
49
|
+
length_out = int(length_out)
|
|
50
|
+
by = width / (length_out - 1)
|
|
51
|
+
out = [float(start)]*length_out
|
|
52
|
+
for i in range(1, length_out):
|
|
53
|
+
out[i] += by * i
|
|
54
|
+
if abs(start + by * length_out - end) < eps:
|
|
55
|
+
out.append(end)
|
|
56
|
+
return out
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def animation(basis_args={}, species_args={}, affinity_args={},
|
|
60
|
+
equilibrate_args=None, diagram_args={},
|
|
61
|
+
anim_var="T", anim_range=[0, 350, 8], xlab=None, ylab=None,
|
|
62
|
+
save_as="newanimationframe", save_format="png", height=300,
|
|
63
|
+
width=400, save_scale=1,
|
|
64
|
+
messages=False):
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
Produce an animated interactive affinity, activity, or predominance diagram.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
basis_args : dict
|
|
72
|
+
Dictionary of options for defining basis species (see `basis`) in the
|
|
73
|
+
animated diagram.
|
|
74
|
+
Example: basis_args={'species':['CO2', 'O2', 'H2O', 'H+']}
|
|
75
|
+
|
|
76
|
+
species_args : dict
|
|
77
|
+
Dictionary of options for defining species (see `species`) in the
|
|
78
|
+
animated diagram, or a list of dicts.
|
|
79
|
+
Example 1: species_args={'species':['CO2', 'HCO3-', 'CO3-2']}
|
|
80
|
+
Example 2: species_args=[
|
|
81
|
+
{'species':['CO2', 'HCO3-', 'CO3-2'], 'state':[-4]},
|
|
82
|
+
{'species':['graphite'], state:[0], 'add':True}]
|
|
83
|
+
|
|
84
|
+
affinity_args : dict
|
|
85
|
+
Dictionary of options for defining the affinity calculation (see
|
|
86
|
+
`affinity`).
|
|
87
|
+
Example: affinity_args={"pH":[2, 12, 100]}
|
|
88
|
+
Example: affinity_args={"pH":[2, 12, 100], "P":[2000, 4000, 100]}
|
|
89
|
+
|
|
90
|
+
equilibrate_args : dict or None, default None
|
|
91
|
+
Dictionary of options for defining equilibration calculation
|
|
92
|
+
(see `equilibrate`). If None, plots output from `affinity`.
|
|
93
|
+
Example: equilibrate_args={"balance":1}
|
|
94
|
+
|
|
95
|
+
diagram_args : dict
|
|
96
|
+
Dictionary of options for diagramming (see `diagram`). Diagram option
|
|
97
|
+
`interactive` is set to True.
|
|
98
|
+
Example: diagram_args={"alpha":True}
|
|
99
|
+
|
|
100
|
+
anim_var : str, default "T"
|
|
101
|
+
Variable that changes with each frame of animation.
|
|
102
|
+
|
|
103
|
+
anim_range : list of numeric, default [0, 350, 8]
|
|
104
|
+
The first two numbers in the list are the starting and ending
|
|
105
|
+
values for `anim_var`. The third number in the list is the desired
|
|
106
|
+
number of animation frames.
|
|
107
|
+
|
|
108
|
+
xlab, ylab : str, optional
|
|
109
|
+
Custom names for the X and Y axes.
|
|
110
|
+
|
|
111
|
+
messages : bool, default True
|
|
112
|
+
Display messages from CHNOSZ?
|
|
113
|
+
|
|
114
|
+
Returns
|
|
115
|
+
-------
|
|
116
|
+
An interactive animated plot.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
# cap number of frames in animation. Remove limitation after more testing.
|
|
120
|
+
if isinstance(anim_range, list):
|
|
121
|
+
if len(anim_range) == 3:
|
|
122
|
+
if anim_range[2] > 30:
|
|
123
|
+
raise Exception("anim_range is limited to 30 frames.")
|
|
124
|
+
else:
|
|
125
|
+
raise Exception("anim_range must be a list with three values: starting "
|
|
126
|
+
"value of anim_var, stopping value, and number of "
|
|
127
|
+
"frames in the animation")
|
|
128
|
+
else:
|
|
129
|
+
raise Exception("anim_range must be a list with three values: starting "
|
|
130
|
+
"value of anim_var, stopping value, and number of "
|
|
131
|
+
"frames in the animation")
|
|
132
|
+
|
|
133
|
+
if isinstance(basis_args, dict):
|
|
134
|
+
if "species" not in basis_args.keys():
|
|
135
|
+
raise Exception("basis_args needs to contain a list of species for 'species'. "
|
|
136
|
+
"Example: basis_args={'species':['CO2', 'O2', 'H2O', 'H+']}")
|
|
137
|
+
else:
|
|
138
|
+
raise Exception("basis_args needs to be a Python dictionary with a key "
|
|
139
|
+
"called 'species' (additional keys are optional). "
|
|
140
|
+
"Example: basis_args={'species':['CO2', 'O2', 'H2O', 'H+']}")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# Add messages parameter to basis_args if not already present
|
|
144
|
+
if "messages" not in basis_args.keys():
|
|
145
|
+
basis_args["messages"] = messages
|
|
146
|
+
|
|
147
|
+
basis_out = basis(**basis_args)
|
|
148
|
+
basis_sp = list(basis_out.index)
|
|
149
|
+
basis_state = list(basis_out["state"])
|
|
150
|
+
|
|
151
|
+
if isinstance(species_args, dict):
|
|
152
|
+
if "species" not in species_args.keys():
|
|
153
|
+
raise Exception("species_args needs to contain a list of species for 'species'. "
|
|
154
|
+
"Example: species_args={'species':['CO2', 'HCO3-', 'CO3-2']}")
|
|
155
|
+
species_args_list = [species_args]
|
|
156
|
+
elif isinstance(species_args, list):
|
|
157
|
+
species_args_list = species_args
|
|
158
|
+
for species_args in species_args_list:
|
|
159
|
+
if "species" not in species_args.keys():
|
|
160
|
+
raise Exception("species_args needs to contain a list of species for 'species'. "
|
|
161
|
+
"Example: species_args={'species':['CO2', 'HCO3-', 'CO3-2']}")
|
|
162
|
+
else:
|
|
163
|
+
raise Exception("species_args needs to be either a Python dictionary with a key "
|
|
164
|
+
"called 'species' (additional keys are optional). "
|
|
165
|
+
"Example: species_args={'species':['CO2', 'HCO3-', 'CO3-2']}"
|
|
166
|
+
"or else species_args needs to be a list of Python dictionaries."
|
|
167
|
+
"Example: species_args=[{'species':['CO2', 'HCO3-', 'CO3-2'], 'state':[-4]},"
|
|
168
|
+
"{'species':['graphite'], state:[0], 'add':True}]")
|
|
169
|
+
|
|
170
|
+
# There may be multiple arguments passed to species, especially in cases
|
|
171
|
+
# where add=True. Loop through all the arguments to apply them.
|
|
172
|
+
for species_args in species_args_list:
|
|
173
|
+
if "logact" in species_args.keys():
|
|
174
|
+
mod_species_logact = copy.copy(species_args['logact'])
|
|
175
|
+
del species_args['logact']
|
|
176
|
+
else:
|
|
177
|
+
mod_species_logact = []
|
|
178
|
+
|
|
179
|
+
# Add messages parameter to species_args if not already present
|
|
180
|
+
if "messages" not in species_args.keys():
|
|
181
|
+
species_args["messages"] = messages
|
|
182
|
+
|
|
183
|
+
species_out = species(**species_args)
|
|
184
|
+
|
|
185
|
+
if len(mod_species_logact)>0:
|
|
186
|
+
for i in range(0, len(mod_species_logact)) :
|
|
187
|
+
species_out = species(species_args["species"][i], mod_species_logact[i], messages=messages)
|
|
188
|
+
|
|
189
|
+
sp = list(species_out["name"])
|
|
190
|
+
|
|
191
|
+
if isinstance(sp[0], (int, np.integer)):
|
|
192
|
+
sp = [info(s, messages=messages)["name"].values[0] for s in sp]
|
|
193
|
+
|
|
194
|
+
dfs = []
|
|
195
|
+
dmaps = []
|
|
196
|
+
dmaps_names = []
|
|
197
|
+
|
|
198
|
+
if len(anim_range) == 2:
|
|
199
|
+
anim_res = 8
|
|
200
|
+
anim_range = anim_range + [anim_res]
|
|
201
|
+
elif len(anim_range) == 3:
|
|
202
|
+
anim_res = anim_range[2]
|
|
203
|
+
anim_range = [anim_range[0], anim_range[1]]
|
|
204
|
+
|
|
205
|
+
zvals = __seq(anim_range[0], anim_range[1], length_out=anim_res)
|
|
206
|
+
|
|
207
|
+
if "messages" not in affinity_args.keys():
|
|
208
|
+
affinity_args["messages"] = messages
|
|
209
|
+
if "messages" not in diagram_args.keys():
|
|
210
|
+
diagram_args["messages"] = messages
|
|
211
|
+
if "plot_it" not in diagram_args.keys():
|
|
212
|
+
diagram_args["plot_it"] = False
|
|
213
|
+
diagram_args["interactive"] = True
|
|
214
|
+
if "format_names" not in diagram_args.keys():
|
|
215
|
+
format_names=True
|
|
216
|
+
format_x_names=True
|
|
217
|
+
format_y_names=True
|
|
218
|
+
|
|
219
|
+
for z in zvals:
|
|
220
|
+
|
|
221
|
+
if anim_var in basis_out.index:
|
|
222
|
+
basis_out = basis(anim_var, z, messages=messages)
|
|
223
|
+
elif anim_var in list(species_out["name"]):
|
|
224
|
+
species_out = species(anim_var, -z, messages=messages)
|
|
225
|
+
elif anim_var == "pH":
|
|
226
|
+
basis_out = basis("H+", -z, messages=messages)
|
|
227
|
+
else:
|
|
228
|
+
affinity_args[anim_var] = z
|
|
229
|
+
|
|
230
|
+
aeout = affinity(**affinity_args)
|
|
231
|
+
|
|
232
|
+
if equilibrate_args != None:
|
|
233
|
+
equilibrate_args["aout"] = aeout
|
|
234
|
+
if "messages" not in equilibrate_args.keys():
|
|
235
|
+
equilibrate_args["messages"] = messages
|
|
236
|
+
aeout = equilibrate(**equilibrate_args)
|
|
237
|
+
|
|
238
|
+
# Get affinity arguments from the result dictionary
|
|
239
|
+
aeout_args = aeout.get("args", {})
|
|
240
|
+
xvar = list(aeout_args.keys())[0]
|
|
241
|
+
xrange = list(aeout_args[xvar])
|
|
242
|
+
|
|
243
|
+
res_default = 256 # default affinity resolution
|
|
244
|
+
if len(xrange) == 3:
|
|
245
|
+
xres = int(xrange[2])
|
|
246
|
+
else:
|
|
247
|
+
xres = res_default
|
|
248
|
+
|
|
249
|
+
diagram_args["eout"] = aeout
|
|
250
|
+
|
|
251
|
+
# Use diagram_interactive since interactive=True is set
|
|
252
|
+
# Remove 'interactive' key as diagram_interactive doesn't need it
|
|
253
|
+
diagram_args_copy = diagram_args.copy()
|
|
254
|
+
diagram_args_copy.pop('interactive', None)
|
|
255
|
+
df, fig = diagram_interactive(**diagram_args_copy)
|
|
256
|
+
|
|
257
|
+
# Check if this is a predominance plot (2D) or affinity/activity plot (1D)
|
|
258
|
+
if 'pred' not in df.columns:
|
|
259
|
+
# affinity/activity plot (1D) - melt to long format for animation
|
|
260
|
+
is_predom_plot = False
|
|
261
|
+
id_vars = [xvar] # Keep the x-variable as identifier
|
|
262
|
+
value_vars = [col for col in df.columns if col != xvar] # All species columns
|
|
263
|
+
df_melted = df.melt(id_vars=id_vars, value_vars=value_vars,
|
|
264
|
+
var_name='variable', value_name='value')
|
|
265
|
+
df_melted[anim_var] = z
|
|
266
|
+
dfs.append(df_melted)
|
|
267
|
+
else:
|
|
268
|
+
# predominance plot (2D) - keep original format with pred and prednames
|
|
269
|
+
is_predom_plot = True
|
|
270
|
+
df[anim_var] = z
|
|
271
|
+
dfs.append(df)
|
|
272
|
+
yvar = list(aeout_args.keys())[1]
|
|
273
|
+
yrange = list(aeout_args[yvar])
|
|
274
|
+
if len(yrange) == 3:
|
|
275
|
+
yres = int(yrange[2])
|
|
276
|
+
else:
|
|
277
|
+
yres = res_default
|
|
278
|
+
|
|
279
|
+
data = np.array(df.pred)
|
|
280
|
+
shape = (xres, yres)
|
|
281
|
+
dmap = data.reshape(shape)
|
|
282
|
+
dmaps.append(dmap)
|
|
283
|
+
|
|
284
|
+
data = np.array(df.prednames)
|
|
285
|
+
shape = (xres, yres)
|
|
286
|
+
dmap_names = data.reshape(shape)
|
|
287
|
+
dmaps_names.append(dmap_names)
|
|
288
|
+
|
|
289
|
+
xvals = __seq(xrange[0], xrange[1], length_out=xres)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
unit_dict = {"P":"bar", "T":"°C", "pH":"", "Eh":"volts", "IS":"mol/kg"}
|
|
293
|
+
|
|
294
|
+
if any([anim_var in basis_out.index, anim_var in list(species_out["name"])]) and anim_var not in unit_dict.keys():
|
|
295
|
+
unit_dict[anim_var] = "logact "+anim_var
|
|
296
|
+
|
|
297
|
+
for i,s in enumerate(basis_sp):
|
|
298
|
+
if basis_state[i] in ["aq", "liq", "cr"]:
|
|
299
|
+
if format_names:
|
|
300
|
+
unit_dict[s] = "log <i>a</i><sub>{}</sub>".format(chemlabel(s))
|
|
301
|
+
else:
|
|
302
|
+
unit_dict[s] = "log <i>a</i><sub>{}</sub>".format(s)
|
|
303
|
+
else:
|
|
304
|
+
if format_names:
|
|
305
|
+
unit_dict[s] = "log <i>f</i><sub>{}</sub>".format(chemlabel(s))
|
|
306
|
+
else:
|
|
307
|
+
unit_dict[s] = "log <i>f</i><sub>{}</sub>".format(s)
|
|
308
|
+
|
|
309
|
+
xlab = xvar+", "+unit_dict[xvar]
|
|
310
|
+
|
|
311
|
+
if xvar in basis_sp:
|
|
312
|
+
xlab = unit_dict[xvar]
|
|
313
|
+
if xvar == "pH":
|
|
314
|
+
xlab = "pH"
|
|
315
|
+
|
|
316
|
+
if is_predom_plot:
|
|
317
|
+
ylab = yvar+", "+unit_dict[yvar]
|
|
318
|
+
if yvar in basis_sp:
|
|
319
|
+
ylab = unit_dict[yvar]
|
|
320
|
+
if yvar == "pH":
|
|
321
|
+
yvar = "pH"
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
if not is_predom_plot:
|
|
325
|
+
|
|
326
|
+
if 'loga.equil' not in aeout.keys():
|
|
327
|
+
yvar = "A/(2.303RT)"
|
|
328
|
+
else:
|
|
329
|
+
yvar = "log a"
|
|
330
|
+
if "alpha" in diagram_args.keys():
|
|
331
|
+
if diagram_args["alpha"]:
|
|
332
|
+
yvar = "alpha"
|
|
333
|
+
|
|
334
|
+
df_c = pd.concat(dfs)
|
|
335
|
+
|
|
336
|
+
if "fill" in diagram_args.keys():
|
|
337
|
+
if isinstance(diagram_args["fill"], list):
|
|
338
|
+
colormap = {key:col for key,col in zip(list(dict.fromkeys(df_c["variable"])), diagram_args["fill"])}
|
|
339
|
+
else:
|
|
340
|
+
colormap = diagram_args["fill"]
|
|
341
|
+
|
|
342
|
+
# with color mapping
|
|
343
|
+
fig = px.line(df_c, x=xvar, y="value", color='variable', template="simple_white",
|
|
344
|
+
width=500, height=400, animation_frame=anim_var,
|
|
345
|
+
color_discrete_map = colormap,
|
|
346
|
+
labels=dict(value=yvar, x=xvar),
|
|
347
|
+
)
|
|
348
|
+
else:
|
|
349
|
+
# without color mapping
|
|
350
|
+
fig = px.line(df_c, x=xvar, y="value", color='variable', template="simple_white",
|
|
351
|
+
width=500, height=400, animation_frame=anim_var,
|
|
352
|
+
labels=dict(value=yvar, x=xvar),
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
if "annotation" in diagram_args.keys():
|
|
356
|
+
if "annotation_coords" not in diagram_args.keys():
|
|
357
|
+
diagram_args["annotation_coords"] = [0, 0]
|
|
358
|
+
fig.add_annotation(x=diagram_args["annotation_coords"][0],
|
|
359
|
+
y=diagram_args["annotation_coords"][1],
|
|
360
|
+
xref="paper",
|
|
361
|
+
yref="paper",
|
|
362
|
+
align='left',
|
|
363
|
+
text=diagram_args["annotation"],
|
|
364
|
+
bgcolor="rgba(255, 255, 255, 0.5)",
|
|
365
|
+
showarrow=False)
|
|
366
|
+
|
|
367
|
+
if 'main' in diagram_args.keys():
|
|
368
|
+
fig.update_layout(title={'text':diagram_args["main"], 'x':0.5, 'xanchor':'center'})
|
|
369
|
+
|
|
370
|
+
if isinstance(xlab, str):
|
|
371
|
+
fig.update_layout(xaxis_title=xlab)
|
|
372
|
+
if isinstance(ylab, str):
|
|
373
|
+
fig.update_layout(yaxis_title=ylab)
|
|
374
|
+
|
|
375
|
+
if 'fill' in diagram_args.keys():
|
|
376
|
+
if isinstance(diagram_args["fill"], list):
|
|
377
|
+
for i,v in enumerate(diagram_args["fill"]):
|
|
378
|
+
fig['data'][i]['line']['color']=v
|
|
379
|
+
|
|
380
|
+
fig.update_layout(legend_title=None)
|
|
381
|
+
|
|
382
|
+
config = {'displaylogo': False,
|
|
383
|
+
'modeBarButtonsToRemove': ['resetScale2d', 'toggleSpikelines'],
|
|
384
|
+
'toImageButtonOptions': {
|
|
385
|
+
'format': save_format, # one of png, svg, jpeg, webp
|
|
386
|
+
'filename': save_as,
|
|
387
|
+
'height': height,
|
|
388
|
+
'width': width,
|
|
389
|
+
'scale': save_scale,
|
|
390
|
+
},
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
fig.show(config=config)
|
|
394
|
+
return
|
|
395
|
+
|
|
396
|
+
else:
|
|
397
|
+
yvals = __seq(yrange[0], yrange[1], length_out=yres)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
frames = []
|
|
402
|
+
slider_steps = []
|
|
403
|
+
annotations = []
|
|
404
|
+
cst_data = []
|
|
405
|
+
heatmaps = []
|
|
406
|
+
|
|
407
|
+
# i is a frame in the animation
|
|
408
|
+
for i in range(0, len(zvals)):
|
|
409
|
+
|
|
410
|
+
annotations_i = []
|
|
411
|
+
for s in sp:
|
|
412
|
+
if s in set(dfs[i]["prednames"]):
|
|
413
|
+
# if an annotation should appear, create one for this frame
|
|
414
|
+
df_s = dfs[i].loc[dfs[i]["prednames"]==s,]
|
|
415
|
+
namex = df_s[xvar].mean()
|
|
416
|
+
namey = df_s[yvar].mean()
|
|
417
|
+
a = go.layout.Annotation(
|
|
418
|
+
x=namex,
|
|
419
|
+
y=namey,
|
|
420
|
+
xref="x",
|
|
421
|
+
yref="y",
|
|
422
|
+
text=chemlabel(s),
|
|
423
|
+
bgcolor="rgba(255, 255, 255, 0.5)",
|
|
424
|
+
showarrow=False,
|
|
425
|
+
)
|
|
426
|
+
else:
|
|
427
|
+
# if an annotation shouldn't appear, make an invisible annotation
|
|
428
|
+
# (workaround for a plotly bug where annotations won't clear in an animation)
|
|
429
|
+
namex = statistics.mean(xvals)
|
|
430
|
+
namey = statistics.mean(yvals)
|
|
431
|
+
a = go.layout.Annotation(
|
|
432
|
+
x=namex,
|
|
433
|
+
y=namey,
|
|
434
|
+
xref="x",
|
|
435
|
+
yref="y",
|
|
436
|
+
text="",
|
|
437
|
+
bgcolor="rgba(255, 255, 255, 0)",
|
|
438
|
+
showarrow=False,
|
|
439
|
+
)
|
|
440
|
+
annotations_i.append(a)
|
|
441
|
+
|
|
442
|
+
# allows adding a custom annotation; append to frame
|
|
443
|
+
if "annotation" in diagram_args.keys():
|
|
444
|
+
if "annotation_coords" not in diagram_args.keys():
|
|
445
|
+
diagram_args["annotation_coords"] = [0, 0]
|
|
446
|
+
custom_annotation = go.layout.Annotation(
|
|
447
|
+
x=diagram_args["annotation_coords"][0],
|
|
448
|
+
y=diagram_args["annotation_coords"][1],
|
|
449
|
+
xref="paper",
|
|
450
|
+
yref="paper",
|
|
451
|
+
align='left',
|
|
452
|
+
text=diagram_args["annotation"],
|
|
453
|
+
bgcolor="rgba(255, 255, 255, 0.5)",
|
|
454
|
+
showarrow=False,
|
|
455
|
+
)
|
|
456
|
+
annotations_i.append(custom_annotation)
|
|
457
|
+
|
|
458
|
+
annotations.append(annotations_i)
|
|
459
|
+
|
|
460
|
+
if 'ylab' in diagram_args.keys():
|
|
461
|
+
ylab = diagram_args["ylab"]
|
|
462
|
+
hover_ylab = ylab+': %{y} '
|
|
463
|
+
else:
|
|
464
|
+
ylab = chemlabel(ylab)
|
|
465
|
+
hover_ylab = yvar+': %{y} '+unit_dict[yvar]
|
|
466
|
+
|
|
467
|
+
if 'xlab' in diagram_args.keys():
|
|
468
|
+
xlab = diagram_args["xlab"]
|
|
469
|
+
hover_xlab = xlab+': %{x} '
|
|
470
|
+
else:
|
|
471
|
+
xlab = chemlabel(xlab)
|
|
472
|
+
hover_xlab = xvar+': %{x} '+unit_dict[xvar]
|
|
473
|
+
|
|
474
|
+
heatmaps_i = go.Heatmap(z=dmaps[i], x=xvals, y=yvals, zmin=0, zmax=len(sp)-1,
|
|
475
|
+
customdata=dmaps_names[i],
|
|
476
|
+
hovertemplate=hover_xlab+'<br>'+hover_ylab+'<br>Region: %{customdata}<extra></extra>')
|
|
477
|
+
|
|
478
|
+
heatmaps.append(heatmaps_i)
|
|
479
|
+
|
|
480
|
+
frame = go.Frame(data=[heatmaps_i],
|
|
481
|
+
name=str(i),
|
|
482
|
+
layout=go.Layout(annotations=annotations_i))
|
|
483
|
+
|
|
484
|
+
frames.append(frame)
|
|
485
|
+
|
|
486
|
+
slider_step = dict(
|
|
487
|
+
method='animate',
|
|
488
|
+
label=zvals[i],
|
|
489
|
+
value=i,
|
|
490
|
+
args=[
|
|
491
|
+
[i],
|
|
492
|
+
dict(
|
|
493
|
+
frame=dict(duration=300, redraw=True),
|
|
494
|
+
mode='immediate',
|
|
495
|
+
transition=dict(duration=0)
|
|
496
|
+
)
|
|
497
|
+
]
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
slider_steps.append(slider_step)
|
|
501
|
+
|
|
502
|
+
fig = go.Figure(
|
|
503
|
+
data = heatmaps[0],
|
|
504
|
+
layout=go.Layout(
|
|
505
|
+
# title="Frame 0",
|
|
506
|
+
title_x=0.5,
|
|
507
|
+
width=500, height=500,
|
|
508
|
+
annotations=annotations[0],
|
|
509
|
+
sliders=[dict(
|
|
510
|
+
active=0,
|
|
511
|
+
yanchor='top',
|
|
512
|
+
xanchor='left',
|
|
513
|
+
currentvalue=dict(
|
|
514
|
+
font=dict(size=12),
|
|
515
|
+
prefix='{}: '.format(anim_var),
|
|
516
|
+
suffix=' '+unit_dict[anim_var],
|
|
517
|
+
visible=True,
|
|
518
|
+
xanchor='right'
|
|
519
|
+
),
|
|
520
|
+
transition=dict(duration=0, easing='cubic-in-out'),
|
|
521
|
+
pad=dict(b=10, t=50),
|
|
522
|
+
len=0.9,
|
|
523
|
+
x=0.1,
|
|
524
|
+
y=0,
|
|
525
|
+
steps=slider_steps
|
|
526
|
+
)],
|
|
527
|
+
updatemenus=[dict(
|
|
528
|
+
type="buttons",
|
|
529
|
+
buttons=[dict(label="Play",
|
|
530
|
+
method="animate",
|
|
531
|
+
args=[None, {"fromcurrent":True}]),
|
|
532
|
+
dict(label="Pause",
|
|
533
|
+
method="animate",
|
|
534
|
+
args=[[None],
|
|
535
|
+
{"frame": {"duration": 0, "redraw": True},
|
|
536
|
+
"mode": "immediate",
|
|
537
|
+
"transition": {"duration": 0}}],
|
|
538
|
+
)],
|
|
539
|
+
direction="left",
|
|
540
|
+
pad={"r": 10, "t": 87},
|
|
541
|
+
showactive=False,
|
|
542
|
+
x=0.1,
|
|
543
|
+
xanchor="right",
|
|
544
|
+
y=0,
|
|
545
|
+
yanchor="top",
|
|
546
|
+
)]
|
|
547
|
+
),
|
|
548
|
+
frames=frames
|
|
549
|
+
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
if 'fill' in diagram_args.keys():
|
|
554
|
+
if isinstance(diagram_args["fill"], list):
|
|
555
|
+
colorscale_temp = []
|
|
556
|
+
for i,v in enumerate(diagram_args["fill"]):
|
|
557
|
+
colorscale_temp.append([i, v])
|
|
558
|
+
colorscale = colorscale_temp
|
|
559
|
+
elif isinstance(diagram_args["fill"], str):
|
|
560
|
+
colorscale = diagram_args["fill"]
|
|
561
|
+
else:
|
|
562
|
+
colorscale = "viridis"
|
|
563
|
+
|
|
564
|
+
fig.update_traces(dict(showscale=False,
|
|
565
|
+
colorscale=colorscale),
|
|
566
|
+
selector={'type':'heatmap'})
|
|
567
|
+
|
|
568
|
+
fig.update_layout(
|
|
569
|
+
xaxis_title=xlab,
|
|
570
|
+
yaxis_title=ylab,
|
|
571
|
+
xaxis={"range":[list(dfs[0][xvar])[0], list(dfs[0][xvar])[-1]]},
|
|
572
|
+
yaxis={"range":[list(dfs[0][yvar])[0], list(dfs[0][yvar])[-1]]},
|
|
573
|
+
margin={"t": 60, "r":60},
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
if 'main' in diagram_args.keys():
|
|
577
|
+
fig.update_layout(title={'text':diagram_args['main'], 'x':0.5, 'xanchor':'center'})
|
|
578
|
+
|
|
579
|
+
config = {'displaylogo': False,
|
|
580
|
+
'modeBarButtonsToRemove': ['zoom2d', 'pan2d', 'zoomIn2d', 'zoomOut2d',
|
|
581
|
+
'autoScale2d', 'toggleSpikelines',
|
|
582
|
+
'hoverClosestCartesian', 'hoverCompareCartesian'],
|
|
583
|
+
'toImageButtonOptions': {
|
|
584
|
+
'format': save_format, # one of png, svg, jpeg, webp
|
|
585
|
+
'filename': save_as,
|
|
586
|
+
'height': height,
|
|
587
|
+
'width': width,
|
|
588
|
+
'scale': save_scale,
|
|
589
|
+
},
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
fig.show(config=config)
|