solvation-analysis 0.3.1__py3-none-any.whl → 0.3.3a0__py3-none-any.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.

Potentially problematic release.


This version of solvation-analysis might be problematic. Click here for more details.

@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2023-04-02T09:17:27-0700",
11
+ "date": "2023-04-09T10:45:35-0700",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "c09a1c9f46d8a554e287169d59e0de008b70606b",
15
- "version": "v0.3.1"
14
+ "full-revisionid": "7133ecc6ffd3dfca4e85abd2eeb6ec850fabb41d",
15
+ "version": "v0.3.3-alpha"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -44,6 +44,10 @@ class Coordination:
44
44
  The number of frames in solvation_data.
45
45
  n_solutes : int
46
46
  The number of solutes in solvation_data.
47
+ solvent_counts: Dict[str, int]
48
+ A dictionary of the number of residues for each solvent.
49
+ atom_group : MDAnalysis.core.groups.AtomGroup
50
+ The atom group of all atoms in the universe.
47
51
 
48
52
  Examples
49
53
  --------
@@ -58,13 +62,15 @@ class Coordination:
58
62
 
59
63
  """
60
64
 
61
- def __init__(self, solvation_data, n_frames, n_solutes, atom_group):
65
+ def __init__(self, solvation_data, n_frames, n_solutes, solvent_counts, atom_group):
62
66
  self.solvation_data = solvation_data
63
67
  self.n_frames = n_frames
64
68
  self.n_solutes = n_solutes
65
69
  self._cn_dict, self._cn_dict_by_frame = self._mean_cn()
66
70
  self.atom_group = atom_group
67
71
  self._coordinating_atoms = self._calculate_coordinating_atoms()
72
+ self.solvent_counts = solvent_counts
73
+ self._coordination_vs_random = self._calculate_coordination_vs_random()
68
74
 
69
75
  @staticmethod
70
76
  def from_solute(solute):
@@ -84,6 +90,7 @@ class Coordination:
84
90
  solute.solvation_data,
85
91
  solute.n_frames,
86
92
  solute.n_solutes,
93
+ solute.solvent_counts,
87
94
  solute.u.atoms,
88
95
  )
89
96
 
@@ -116,13 +123,32 @@ class Coordination:
116
123
  type_fractions = type_counts[SOLVENT_ATOM_IX] / solvent_counts_list
117
124
  type_fractions.name = FRACTION
118
125
  # change index type
119
- type_fractions = (type_fractions
120
- .reset_index(ATOM_TYPE)
121
- .astype({ATOM_TYPE: str})
122
- .set_index(ATOM_TYPE, append=True)
123
- )
126
+ type_fractions = (
127
+ type_fractions
128
+ .reset_index(ATOM_TYPE)
129
+ .astype({ATOM_TYPE: str})
130
+ .set_index(ATOM_TYPE, append=True)
131
+ )
124
132
  return type_fractions[type_fractions[FRACTION] > tol]
125
133
 
134
+ def _calculate_coordination_vs_random(self):
135
+ """
136
+ Calculate the coordination number relative to random coordination.
137
+
138
+ Values higher than 1 imply a higher coordination than expected from
139
+ random distribution of solvents. Values lower than 1 imply a lower
140
+ coordination than expected from random distribution of solvents.
141
+ """
142
+ average_shell_size = sum(self.coordination_numbers.values())
143
+ total_solvents = sum(self.solvent_counts.values())
144
+ coordination_vs_random = {}
145
+ for solvent, cn in self.coordination_numbers.items():
146
+ count = self.solvent_counts[solvent]
147
+ random = count * average_shell_size / total_solvents
148
+ vs_random = cn / random
149
+ coordination_vs_random[solvent] = vs_random
150
+ return coordination_vs_random
151
+
126
152
  @property
127
153
  def coordination_numbers(self):
128
154
  """
@@ -145,3 +171,13 @@ class Coordination:
145
171
  """
146
172
  return self._coordinating_atoms
147
173
 
174
+ @property
175
+ def coordination_vs_random(self):
176
+ """
177
+ Coordination number relative to random coordination.
178
+
179
+ Values higher than 1 imply a higher coordination than expected from
180
+ random distribution of solvents. Values lower than 1 imply a lower
181
+ coordination than expected from random distribution of solvents.
182
+ """
183
+ return self._coordination_vs_random
@@ -90,6 +90,91 @@ def plot_shell_composition_by_size(speciation):
90
90
  return fig
91
91
 
92
92
 
93
+ def plot_co_occurrence(speciation, colorscale=None):
94
+ """
95
+ Plot the co-occurrence matrix of the solute using Plotly.
96
+
97
+ Co-occurrence represents the extent to which solvents occur with eachother
98
+ relative to random. Values higher than 1 mean that solvents occur together
99
+ more often than random and values lower than 1 mean solvents occur together
100
+ less often than random. "Random" is calculated based on the total number of
101
+ solvents participating in solvation, it ignores solvents in the diluent.
102
+
103
+ Args
104
+ ----
105
+ speciation: Speciation | Solution
106
+ colorscale : any valid argument to Plotly colorscale.
107
+
108
+ Returns
109
+ -------
110
+ fig : plotly.graph_objs.Figure
111
+ """
112
+ if isinstance(speciation, Solute):
113
+ if not hasattr(speciation, "speciation"):
114
+ raise ValueError(f"Solute speciation analysis class must be instantiated.")
115
+ speciation = speciation.speciation
116
+
117
+ solvent_names = speciation.speciation_data.columns.values
118
+
119
+ if colorscale:
120
+ colorscale = colorscale
121
+ else:
122
+ min_val = speciation.solvent_co_occurrence.min().min()
123
+ max_val = speciation.solvent_co_occurrence.max().max()
124
+ range_val = max_val - min_val
125
+
126
+ colorscale = [
127
+ [0, 'rgb(67,147,195)'],
128
+ [(1 - min_val) / range_val, "white"],
129
+ [1, 'rgb(214,96,77)']
130
+ ]
131
+
132
+ # Create a heatmap trace with text annotations
133
+ trace = go.Heatmap(
134
+ x=solvent_names,
135
+ y=solvent_names[::-1], # Reverse the order of the y-axis labels
136
+ z=speciation.solvent_co_occurrence.values, # Keep the data in the original order
137
+ text=speciation.solvent_co_occurrence.round(2).to_numpy(dtype=str),
138
+ # Keep the text annotations in the original order
139
+ hoverinfo="none",
140
+ colorscale=colorscale
141
+ )
142
+
143
+ # Update layout to display tick labels and text annotations
144
+ layout = go.Layout(
145
+ title="Solvent Co-Occurrence Matrix",
146
+ xaxis=dict(
147
+ tickmode='array',
148
+ tickvals=list(range(len(solvent_names))),
149
+ ticktext=solvent_names,
150
+ tickangle=-30,
151
+ side='top'
152
+ ),
153
+ yaxis=dict(
154
+ tickmode='array',
155
+ tickvals=list(range(len(solvent_names))),
156
+ ticktext=solvent_names,
157
+ autorange='reversed'
158
+ ),
159
+ margin=dict(l=60, r=60, b=60, t=100, pad=4),
160
+ annotations=[
161
+ dict(
162
+ x=i,
163
+ y=j,
164
+ text=str(round(speciation.solvent_co_occurrence.iloc[j, i], 2)),
165
+ font=dict(size=14, color="black"),
166
+ showarrow=False
167
+ )
168
+ for i in range(len(solvent_names))
169
+ for j in range(len(solvent_names))
170
+ ],
171
+ )
172
+
173
+ # Create and return the Figure object
174
+ fig = go.Figure(data=[trace], layout=layout)
175
+ return fig
176
+
177
+
93
178
  def compare_solvent_dicts(
94
179
  property_dict,
95
180
  rename_solvent_dict,
@@ -20,8 +20,6 @@ solvation data a non-issue.
20
20
  """
21
21
 
22
22
  import pandas as pd
23
- import numpy as np
24
- import matplotlib.pyplot as plt
25
23
 
26
24
  from solvation_analysis._column_names import *
27
25
 
@@ -193,46 +191,6 @@ class Speciation:
193
191
  correlation = actual_df / expected_df
194
192
  return correlation
195
193
 
196
- def plot_co_occurrence(self):
197
- """
198
- Plot the co-occurrence matrix of the solute.
199
-
200
- Co-occurrence as a heatmap with numerical values in addition to colors.
201
-
202
- Returns
203
- -------
204
- fig : matplotlib.Figure
205
- ax : matplotlib.Axes
206
-
207
- """
208
- # TODO: rewrite in plotly and move this to the plotting module
209
- solvent_names = self.speciation_data.columns.values
210
- fig, ax = plt.subplots()
211
- im = ax.imshow(self.solvent_co_occurrence)
212
- # We want to show all ticks...
213
- ax.set_xticks(np.arange(len(solvent_names)))
214
- ax.set_yticks(np.arange(len(solvent_names)))
215
- # ... and label them with the respective list entries
216
- ax.set_xticklabels(solvent_names, fontsize=14)
217
- ax.set_yticklabels(solvent_names, fontsize=14)
218
- # Let the horizontal axes labeling appear on top.
219
- ax.tick_params(top=True, bottom=False,
220
- labeltop=True, labelbottom=False, )
221
- # Rotate the tick labels and set their alignment.
222
- plt.setp(ax.get_xticklabels(), rotation=-30, ha="right",
223
- rotation_mode="anchor")
224
- # Loop over data dimensions and create text annotations.
225
- for i in range(len(solvent_names)):
226
- for j in range(len(solvent_names)):
227
- ax.text(j, i, round(self.solvent_co_occurrence.iloc[i, j], 2),
228
- horizontalalignment="center",
229
- verticalalignment="center",
230
- color="black",
231
- fontsize=14,
232
- )
233
- fig.tight_layout()
234
- return fig, ax
235
-
236
194
  @property
237
195
  def speciation_data(self):
238
196
  """
@@ -18,8 +18,7 @@ def test_coordination_from_solute(run_solute):
18
18
  ],
19
19
  )
20
20
  def test_coordination(name, cn, solvation_data, run_solute):
21
- atoms = run_solute.u.atoms
22
- coordination = Coordination(solvation_data, 10, 49, atoms)
21
+ coordination = Coordination.from_solute(run_solute)
23
22
  np.testing.assert_allclose(cn, coordination.coordination_numbers[name], atol=0.05)
24
23
  assert len(coordination.coordination_numbers_by_frame) == 3
25
24
 
@@ -33,21 +32,21 @@ def test_coordination(name, cn, solvation_data, run_solute):
33
32
  ],
34
33
  )
35
34
  def test_coordinating_atoms(name, atom_type, fraction, solvation_data, run_solute):
36
- atoms = run_solute.u.atoms
37
- coordination = Coordination(solvation_data, 10, 49, atoms)
35
+ coordination = Coordination.from_solute(run_solute)
38
36
  calculated_fraction = coordination._coordinating_atoms.loc[(name, atom_type)]
39
37
  np.testing.assert_allclose(fraction, calculated_fraction, atol=0.05)
40
38
 
41
39
 
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
40
+ @pytest.mark.parametrize(
41
+ "name, coord",
42
+ [
43
+ ("fec", 0.15),
44
+ ("bn", 1.64),
45
+ ("pf6", 0.38),
46
+ ],
47
+ )
48
+ def test_coordination_relative_to_random(name, coord, solvation_data, run_solute):
49
+ atoms = run_solute.u.atoms
50
+ coordination = Coordination(solvation_data, 10, 49, run_solute.solvent_counts, atoms)
51
+ np.testing.assert_allclose(coord, coordination.coordination_vs_random[name], atol=0.05)
52
+ assert len(coordination.coordination_numbers_by_frame) == 3
@@ -2,6 +2,7 @@ import pytest
2
2
  from solvation_analysis.plotting import (
3
3
  plot_network_size_histogram,
4
4
  plot_shell_composition_by_size,
5
+ plot_co_occurrence,
5
6
  _compare_function_generator,
6
7
  compare_free_solvents,
7
8
  compare_pairing,
@@ -13,6 +14,7 @@ from solvation_analysis.plotting import (
13
14
 
14
15
  from solvation_analysis.networking import Networking
15
16
  from solvation_analysis.residence import Residence
17
+ from solvation_analysis.speciation import Speciation
16
18
 
17
19
 
18
20
  def test_plot_network_size_histogram(run_solute):
@@ -311,3 +313,10 @@ def test_compare_generic(eax_solutes):
311
313
  assert len(fig.data) == 4
312
314
  for bar in fig.data:
313
315
  assert set(bar.x) == {"pf6", "fec", "EAx"}
316
+ # fig.show()
317
+
318
+
319
+ def test_plot_co_occurrence(solvation_data):
320
+ speciation = Speciation(solvation_data, 10, 49)
321
+ fig = plot_co_occurrence(speciation)
322
+ # fig.show()
@@ -52,9 +52,3 @@ def test_speciation_correlation(solvent_one, solvent_two, correlation, solvation
52
52
  df = speciation.solvent_co_occurrence
53
53
  np.testing.assert_allclose(df[solvent_one][solvent_two], correlation, atol=0.05)
54
54
 
55
-
56
- def test_plot_correlation(solvation_data):
57
- speciation = Speciation(solvation_data, 10, 49)
58
- fig, ax = speciation.plot_co_occurrence()
59
- # fig.show()
60
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: solvation-analysis
3
- Version: 0.3.1
3
+ Version: 0.3.3a0
4
4
  Summary: A toolkit to analyze solvation structure in molecular dynamics trajectories.
5
5
  Author: Orion Cohen
6
6
  Author-email: Orion Cohen <orioncohen@berkeley.edu>
@@ -606,7 +606,6 @@ Requires-Dist: numpy (>=1.20.0)
606
606
  Requires-Dist: pandas
607
607
  Requires-Dist: mdanalysis (>=2.0.0)
608
608
  Requires-Dist: pytest
609
- Requires-Dist: pathlib
610
609
  Requires-Dist: matplotlib
611
610
  Requires-Dist: scipy
612
611
  Requires-Dist: statsmodels
@@ -1,27 +1,27 @@
1
1
  solvation_analysis/__init__.py,sha256=nilCtSfGTLm40kUA9syYdl9pGF4XWpNJ2lV3rFyZI2w,335
2
2
  solvation_analysis/_column_names.py,sha256=wK9GN1_Pzve4cI3o86R7NQGdSLfhENXct0J036nS2c8,728
3
3
  solvation_analysis/_utils.py,sha256=XkdmglL0JjXsyAS-owZU_Vo1rCSdRD0Hz3P8rfWQ3po,8016
4
- solvation_analysis/_version.py,sha256=rI_DvDURrbONosJPmRe6D_Okkn51y9hPH5XcU99fRnk,498
5
- solvation_analysis/coordination.py,sha256=md0_XupQ2VPk8Y4n144IflTen2tc9aWX5xBmTcwCMbA,4984
4
+ solvation_analysis/_version.py,sha256=CeTQhwfxdqvxY5Pzehas2dwwJRCXrUik12wq6ckZpSA,504
5
+ solvation_analysis/coordination.py,sha256=AE628q-dsHTzVXnsip953CHf-clqJnHPYQurPhyck3w,6570
6
6
  solvation_analysis/networking.py,sha256=PjN_bUGenxYs2dAcjGvnQb4C6dCU2rz4C2AyjhCTtuk,10777
7
7
  solvation_analysis/pairing.py,sha256=vAvhj4aPAnDACwEUOi-PS8TC-EiVzeSceOyycpDa7qQ,5709
8
- solvation_analysis/plotting.py,sha256=hlRg3TMKZSg5XYAz9teCXOuQBx2g3uj1vRjGUcIq76Q,10881
8
+ solvation_analysis/plotting.py,sha256=YtzU3TlQcsOlB0qASUAxviZ4s2g9ZPcP5xml7C9NRiY,13759
9
9
  solvation_analysis/rdf_parser.py,sha256=FS8lnoucmngDBgSuakLGiMGb1HDAh1ONvQbTqQRsXWo,11231
10
10
  solvation_analysis/residence.py,sha256=VaHAImFwc9tI-9PWLYwmVdeHjzqKEppeUyWpmgFr14Q,10944
11
11
  solvation_analysis/solute.py,sha256=-RyExdqJ65GcpOM_kiFqgmFwHWZ026b94gj3fymZU0E,38245
12
- solvation_analysis/speciation.py,sha256=L8UPeCJfGu1yI5xYG8R0FPSoXDOLYNftgbh0A86hhfA,10663
12
+ solvation_analysis/speciation.py,sha256=rLZCSXGbZ6-P80N-MopLN79_eGnl1feJDFrlv7MxjZk,8970
13
13
  solvation_analysis/tests/__init__.py,sha256=tlIleLX_7zJFwQuwnqP9fJ0nQXdD1uA-l8uX8w4KUKM,112
14
14
  solvation_analysis/tests/conftest.py,sha256=2cMepIZ0rLza_wnaXpu-mH_Ld2fqxq7tKoQXdm-Cj1Y,9536
15
15
  solvation_analysis/tests/datafiles.py,sha256=4vOiZsRWtIpWhq8aEyfMpR8JQWPwkppqNwbTjx2sCVc,2601
16
- solvation_analysis/tests/test_coordination.py,sha256=zl2FvFnEXmKZnkE8CFBKGipiDXj6yeVq-HY9IQ7nsO0,1196
16
+ solvation_analysis/tests/test_coordination.py,sha256=hrqV5y7yLDi3ysEbL7oNGCDbdVJ26brzDhGAuNAAwO8,1596
17
17
  solvation_analysis/tests/test_networking.py,sha256=AcHm1A_ZeIsBSqnl1KV9IzJc3EwkP4pfFRdNyBQnM0k,867
18
18
  solvation_analysis/tests/test_pairing.py,sha256=D9haGZGkswmrevOa_GPGXd0KqmusAGjzUcJCYdeKTPY,1516
19
- solvation_analysis/tests/test_plotting.py,sha256=vui1yoDgDaTcHjaycFyDvol9X85AdQwuzK27l7Z_13k,9786
19
+ solvation_analysis/tests/test_plotting.py,sha256=AshDnsmn3W1Y_AkEnQVGTrNu9oWfWic2k3QxbB4fLqk,10037
20
20
  solvation_analysis/tests/test_rdf_parser.py,sha256=2at9a-f43TEWBJKdIR4MCkw6cVt5QEU6kMHx7meDBtE,6317
21
21
  solvation_analysis/tests/test_residence.py,sha256=t44krzWcaVhg-uGLmnbFIIZIMSg5INBGd1gk77tSHKI,961
22
22
  solvation_analysis/tests/test_selection.py,sha256=VpeRDONNYtVEfcnXGV9UAXnpKSm2XQJoppdP03Dafkc,4012
23
23
  solvation_analysis/tests/test_solute.py,sha256=SR2vTc2KdxaP0TF_xVNijl-pcl-LdFlHa6r9wKxrTFM,12563
24
- solvation_analysis/tests/test_speciation.py,sha256=T7ZmMkprhdgseIwoEaq7i1VB6vlJVc9YXve0td9QkaI,1732
24
+ solvation_analysis/tests/test_speciation.py,sha256=LsY1XlTip_W_yZ6Xh937t-sTPhhuMip2rCftvDa0sQM,1572
25
25
  solvation_analysis/tests/data/.DS_Store,sha256=reUv274-_DxmgXdgxkidZh_Eg5vy4GGjtYVNIO9iZIA,8196
26
26
  solvation_analysis/tests/data/README.md,sha256=vh4ZQXmH6EsL3sQybINpMXIIL8GqXIN4kk3Dq3AfiUg,2848
27
27
  solvation_analysis/tests/data/bn_fec_data/bn_fec.data,sha256=he2A8xzbatbOxbyas_bWaOmE0XJBePKj9HMpOu1wppY,1418421
@@ -109,8 +109,8 @@ solvation_analysis/tests/data/rdf_vs_li_hard/rdf_pf6_all_bins.npz,sha256=Z1knlSh
109
109
  solvation_analysis/tests/data/rdf_vs_li_hard/rdf_pf6_all_data.npz,sha256=yKRJ2BGnvWAfRnP9HLdK1USv1RPcwTW54Vk_Z8EqomA,864
110
110
  solvation_analysis/tests/data/rdf_vs_li_hard/rdf_universe_all_bins.npz,sha256=Z1knlShdL77EiFMvmh4FXzlkTCM2ziZKUuqYgtg_tZw,864
111
111
  solvation_analysis/tests/data/rdf_vs_li_hard/rdf_universe_all_data.npz,sha256=di1BmbLd0oca23XY5sW_M60Xi3Q8leIhHtJ61wDTTGs,864
112
- solvation_analysis-0.3.1.dist-info/LICENSE,sha256=-mQWu786dxXc5-JBLEYYgWZ2BTFaAueDVwUpzSRfbxI,34684
113
- solvation_analysis-0.3.1.dist-info/METADATA,sha256=2o_cfq6TDjc-8-J8Fz0AHx6ei65j5_l21uGTRiswWvE,45010
114
- solvation_analysis-0.3.1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
115
- solvation_analysis-0.3.1.dist-info/top_level.txt,sha256=M6YFLMMaJsIEeRqw1v_9jvSq7oXa8GWU5x6nNNc6zbU,19
116
- solvation_analysis-0.3.1.dist-info/RECORD,,
112
+ solvation_analysis-0.3.3a0.dist-info/LICENSE,sha256=-mQWu786dxXc5-JBLEYYgWZ2BTFaAueDVwUpzSRfbxI,34684
113
+ solvation_analysis-0.3.3a0.dist-info/METADATA,sha256=i5xRZTAAJuAlGJM8o7eFMyqUHwQfUprCYJKN2EoPsok,44989
114
+ solvation_analysis-0.3.3a0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
115
+ solvation_analysis-0.3.3a0.dist-info/top_level.txt,sha256=M6YFLMMaJsIEeRqw1v_9jvSq7oXa8GWU5x6nNNc6zbU,19
116
+ solvation_analysis-0.3.3a0.dist-info/RECORD,,