emdbva 0.0.1.dev135__tar.gz → 0.0.1.dev137__tar.gz

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.
Files changed (48) hide show
  1. {emdbva-0.0.1.dev135/emdbva.egg-info → emdbva-0.0.1.dev137}/PKG-INFO +1 -1
  2. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137/emdbva.egg-info}/PKG-INFO +1 -1
  3. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/emdbva.egg-info/SOURCES.txt +1 -0
  4. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/mainva.py +1 -0
  5. emdbva-0.0.1.dev137/va/metrics/map_data_validation.py +59 -0
  6. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/projections.py +41 -5
  7. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/validationanalysis.py +43 -0
  8. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/version.py +1 -1
  9. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/LICENSE +0 -0
  10. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/MANIFEST.in +0 -0
  11. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/README.rst +0 -0
  12. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/emdbva.egg-info/dependency_links.txt +0 -0
  13. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/emdbva.egg-info/entry_points.txt +0 -0
  14. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/emdbva.egg-info/requires.txt +0 -0
  15. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/emdbva.egg-info/top_level.txt +0 -0
  16. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/setup.cfg +0 -0
  17. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/setup.py +0 -0
  18. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/__init__.py +0 -0
  19. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/__init__.py +0 -0
  20. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/bars.py +0 -0
  21. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/connected_percentage.py +0 -0
  22. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/contour_level_predicator.py +0 -0
  23. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/emda_mmcc.py +0 -0
  24. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/emringer.py +0 -0
  25. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/inclusion.py +0 -0
  26. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/overlap_percentage.py +0 -0
  27. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/phaserandomization.py +0 -0
  28. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/phenix_cc.py +0 -0
  29. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/phenix_mm.py +0 -0
  30. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/qscore.py +0 -0
  31. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/residue_locres.py +0 -0
  32. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/resmap.py +0 -0
  33. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/smoc.py +0 -0
  34. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/strudel.py +0 -0
  35. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/surfaces.py +0 -0
  36. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/metrics/threedfsc.py +0 -0
  37. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/preparation.py +0 -0
  38. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/qscores.csv +0 -0
  39. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/utils/Checker.py +0 -0
  40. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/utils/ChimeraxViews.py +0 -0
  41. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/utils/MapProcessor.py +0 -0
  42. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/utils/Model.py +0 -0
  43. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/utils/__init__.py +0 -0
  44. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/utils/cl_weights.pth +0 -0
  45. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/utils/log_utils.py +0 -0
  46. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/utils/misc.py +0 -0
  47. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/utils/rescolor.py +0 -0
  48. {emdbva-0.0.1.dev135 → emdbva-0.0.1.dev137}/va/utils/stars.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: emdbva
3
- Version: 0.0.1.dev135
3
+ Version: 0.0.1.dev137
4
4
  Summary: CryoEM validation toolkit
5
5
  Home-page: https://test.pypi.org/project/va/
6
6
  Author: Zhe Wang
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: emdbva
3
- Version: 0.0.1.dev135
3
+ Version: 0.0.1.dev137
4
4
  Summary: CryoEM validation toolkit
5
5
  Home-page: https://test.pypi.org/project/va/
6
6
  Author: Zhe Wang
@@ -21,6 +21,7 @@ va/metrics/contour_level_predicator.py
21
21
  va/metrics/emda_mmcc.py
22
22
  va/metrics/emringer.py
23
23
  va/metrics/inclusion.py
24
+ va/metrics/map_data_validation.py
24
25
  va/metrics/overlap_percentage.py
25
26
  va/metrics/phaserandomization.py
26
27
  va/metrics/phenix_cc.py
@@ -58,6 +58,7 @@ def allruns(validationobj, runs):
58
58
 
59
59
  # Projections
60
60
  if 'projection' in runs:
61
+ validationobj.map_data_validation()
61
62
  validationobj.new_projection()
62
63
  validationobj.relion_mask_evaluation()
63
64
 
@@ -0,0 +1,59 @@
1
+ import io
2
+ import os
3
+ from collections import OrderedDict
4
+ from pathlib import Path
5
+ import mrcfile
6
+
7
+
8
+ def _normalise_map_input(map_input):
9
+ if hasattr(map_input, "fullname"):
10
+ return map_input.fullname
11
+ if hasattr(map_input, "filename"):
12
+ return map_input.filename
13
+ return str(map_input)
14
+
15
+
16
+ def validate_single_map(map_input):
17
+ map_path = Path(_normalise_map_input(map_input))
18
+ messages = io.StringIO()
19
+
20
+ result = OrderedDict([
21
+ ("file", str(map_path)),
22
+ ("exists", map_path.exists()),
23
+ ("valid", False),
24
+ ("messages", ""),
25
+ ("error", None),
26
+ ])
27
+
28
+ if not map_path.exists():
29
+ result["error"] = "File does not exist"
30
+ return result
31
+
32
+ try:
33
+ valid = mrcfile.validate(str(map_path), print_file=messages)
34
+ result["valid"] = bool(valid)
35
+ result["messages"] = messages.getvalue().strip()
36
+ except Exception as exc:
37
+ result["error"] = str(exc)
38
+ result["messages"] = messages.getvalue().strip()
39
+
40
+ return result
41
+
42
+
43
+ def run_map_data_validation(map_inputs):
44
+ map_results = OrderedDict()
45
+
46
+ for map_input in map_inputs:
47
+ if map_input is None:
48
+ continue
49
+
50
+ map_path = _normalise_map_input(map_input)
51
+ map_name = os.path.basename(map_path)
52
+
53
+ map_results[map_name] = validate_single_map(map_input)
54
+
55
+ return OrderedDict([
56
+ ("data_validation", OrderedDict([
57
+ ("map_data_validation", map_results)
58
+ ]))
59
+ ])
@@ -183,7 +183,10 @@ class Projections:
183
183
  def _green_percentage(self, image_obj):
184
184
  """
185
185
  image_obj can be a file path, PIL Image, or numpy array.
186
- Returns green percentage as a float.
186
+ Returns a dictionary with:
187
+ - percentage: total green percentage in the whole image
188
+ - diff_vertical: left-half green percentage minus right-half green percentage
189
+ - diff_horizontal: top-half green percentage minus bottom-half green percentage
187
190
  """
188
191
  if isinstance(image_obj, str):
189
192
  img = Image.open(image_obj).convert("RGB")
@@ -193,10 +196,43 @@ class Projections:
193
196
  img = Image.fromarray(image_obj).convert("RGB")
194
197
 
195
198
  img_array = np.array(img)
196
- green_pixels = np.sum(np.all(img_array == [0, 138, 0], axis=-1))
197
- total_pixels = img_array.shape[0] * img_array.shape[1]
198
- proportion_green = (green_pixels / total_pixels) * 100 if total_pixels else 0.0
199
- return round(proportion_green, 2)
199
+ green_mask = np.all(img_array == [0, 138, 0], axis=-1)
200
+ height, width = green_mask.shape
201
+ total_pixels = height * width
202
+ if total_pixels == 0:
203
+ return {
204
+ 'percentage': 0.0,
205
+ 'diff_vertical': 0.0,
206
+ 'diff_horizontal': 0.0,
207
+ }
208
+
209
+ green_pixels = np.sum(green_mask)
210
+ proportion_green = (green_pixels / total_pixels) * 100
211
+
212
+ mid_vertical = width // 2
213
+ left_total = height * mid_vertical
214
+ right_total = height * (width - mid_vertical)
215
+ green_pixels_left_half = np.sum(green_mask[:, :mid_vertical])
216
+ green_pixels_right_half = np.sum(green_mask[:, mid_vertical:])
217
+ proportion_green_left_half = (green_pixels_left_half / left_total) * 100 if left_total else 0.0
218
+ proportion_green_right_half = (green_pixels_right_half / right_total) * 100 if right_total else 0.0
219
+ diff_vertical = proportion_green_left_half - proportion_green_right_half
220
+
221
+ mid_horizontal = height // 2
222
+ top_total = mid_horizontal * width
223
+ bottom_total = (height - mid_horizontal) * width
224
+ green_pixels_top_half = np.sum(green_mask[:mid_horizontal, :])
225
+ green_pixels_bottom_half = np.sum(green_mask[mid_horizontal:, :])
226
+ proportion_green_top_half = (green_pixels_top_half / top_total) * 100 if top_total else 0.0
227
+ proportion_green_bottom_half = (green_pixels_bottom_half / bottom_total) * 100 if bottom_total else 0.0
228
+ diff_horizontal = proportion_green_top_half - proportion_green_bottom_half
229
+
230
+ return {
231
+ 'percentage': round(proportion_green, 2),
232
+ 'diff_vertical': round(diff_vertical, 2),
233
+ 'diff_horizontal': round(diff_horizontal, 2),
234
+ }
235
+
200
236
 
201
237
  def orthogonal_projections(self, mapin=None, workdir=None, type=None, label=''):
202
238
  map, workdir = self.mapincheck(mapin, workdir)
@@ -77,6 +77,7 @@ from va.metrics.qscore import *
77
77
  from va.metrics.inclusion import *
78
78
  from va.metrics.connected_percentage import *
79
79
  from va.metrics.overlap_percentage import *
80
+ from metrics.map_data_validation import run_map_data_validation
80
81
  import va
81
82
 
82
83
  try:
@@ -1158,6 +1159,48 @@ class ValidationAnalysis:
1158
1159
  viewer.new_surface_view_chimerax(primary_input_map, primary_input_contour, 'mask', '',
1159
1160
  mask_name, mask_contour)
1160
1161
 
1162
+ @profile_peak_memory()
1163
+ def map_data_validation(self):
1164
+ """
1165
+ Validate map/header data using mrcfile.validate().
1166
+
1167
+ Output JSON structure:
1168
+ data_validation -> map_data_validation -> mapname -> validation results
1169
+ """
1170
+
1171
+ start = timeit.default_timer()
1172
+ map_inputs = []
1173
+
1174
+ for attr in ("map", "rawmap", "hmodd", "hmeven"):
1175
+ try:
1176
+ value = getattr(self, attr, None)
1177
+ if value is not None:
1178
+ map_inputs.append(value)
1179
+ except AttributeError:
1180
+ pass
1181
+
1182
+ try:
1183
+ result_dict = run_map_data_validation(map_inputs)
1184
+
1185
+ out_json = os.path.join(
1186
+ self.workdir,
1187
+ f"{self.mapname}_map_data_validation.json"
1188
+ )
1189
+
1190
+ with codecs.open(out_json, "w", encoding="utf-8") as f:
1191
+ json.dump(result_dict, f)
1192
+
1193
+ print("Map data validation results were collected.")
1194
+
1195
+ except:
1196
+ err = "Map data validation error: {}.".format(sys.exc_info()[1])
1197
+ sys.stderr.write(err + "\n")
1198
+
1199
+ end = timeit.default_timer()
1200
+ print("Map data validation time: %s" % (end - start))
1201
+ print("------------------------------------")
1202
+
1203
+ return None
1161
1204
 
1162
1205
  # Surface Chimera way
1163
1206
  # def new_surface_view_chimerax(self, input_map, input_contour, type='surface', raw='', mask_map=None,
@@ -18,5 +18,5 @@ under the License.
18
18
 
19
19
  """
20
20
 
21
- __version__ = '0.0.1.dev135'
21
+ __version__ = '0.0.1.dev137'
22
22
  __em_statistics_version__ = '202505.v01'
File without changes
File without changes
File without changes
File without changes
File without changes