pypsbuilder 2.6.2__tar.gz → 2.6.4__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 (113) hide show
  1. pypsbuilder-2.6.4/.zenodo.json +20 -0
  2. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/CHANGELOG.md +10 -0
  3. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/PKG-INFO +6 -1
  4. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/README.md +5 -0
  5. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/codecov.yml +1 -1
  6. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.tcapi.TC34API.rst +9 -11
  7. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.tcapi.TC35API.rst +9 -11
  8. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/__init__.py +1 -1
  9. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/psclasses.py +111 -8
  10. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/psexplorer.py +107 -88
  11. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/tcapi.py +536 -491
  12. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/tests/test_pclasses.py +12 -12
  13. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/.github/dependabot.yml +0 -0
  14. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/.github/workflows/release.yml +0 -0
  15. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/.github/workflows/testing.yml +0 -0
  16. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/.github/workflows/testrelease.yml +0 -0
  17. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/.gitignore +0 -0
  18. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/.pre-commit-config.yaml +0 -0
  19. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/.readthedocs.yaml +0 -0
  20. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/AUTHORS.md +0 -0
  21. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/CONTRIBUTING.md +0 -0
  22. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/LICENSE +0 -0
  23. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/_static/theme_overrides.css +0 -0
  24. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psclasses.Dogmin.rst +0 -0
  25. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psclasses.InvPoint.rst +0 -0
  26. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psclasses.PTsection.rst +0 -0
  27. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psclasses.PXsection.rst +0 -0
  28. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psclasses.TCResult.rst +0 -0
  29. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psclasses.TCResultSet.rst +0 -0
  30. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psclasses.TXsection.rst +0 -0
  31. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psclasses.UniLine.rst +0 -0
  32. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psexplorer.PTPS.rst +0 -0
  33. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psexplorer.PXPS.rst +0 -0
  34. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api/pypsbuilder.psexplorer.TXPS.rst +0 -0
  35. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/api.rst +0 -0
  36. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/authors.rst +0 -0
  37. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/command-line.rst +0 -0
  38. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/conf.py +0 -0
  39. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/create_environment.png +0 -0
  40. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/crossing.png +0 -0
  41. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/delta.png +0 -0
  42. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/install_locally.png +0 -0
  43. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/invsearch.png +0 -0
  44. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/isopleths_1.png +0 -0
  45. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/isopleths_2.png +0 -0
  46. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/modes.png +0 -0
  47. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psbuilder_areas.png +0 -0
  48. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psbuilder_dogmin.png +0 -0
  49. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psbuilder_finished.png +0 -0
  50. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psbuilder_highlight.png +0 -0
  51. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psbuilder_init.png +0 -0
  52. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psbuilder_inv.png +0 -0
  53. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psbuilder_modes.png +0 -0
  54. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psbuilder_uni.png +0 -0
  55. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psiso_alm.png +0 -0
  56. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psiso_labelkey.png +0 -0
  57. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psiso_mode.png +0 -0
  58. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psiso_other.png +0 -0
  59. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/psshow_out.png +0 -0
  60. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/ptpath.png +0 -0
  61. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/show_data.png +0 -0
  62. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/show_grid.png +0 -0
  63. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/show_label.png +0 -0
  64. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/show_out.png +0 -0
  65. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/show_plain.png +0 -0
  66. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/images/status.png +0 -0
  67. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/index.rst +0 -0
  68. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/psbuilders-tutorial.rst +0 -0
  69. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/psexplorer-tutorial.rst +0 -0
  70. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/docs/readme.rst +0 -0
  71. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/environment.yml +0 -0
  72. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/avgpelite/tc-avgpelite.txt +0 -0
  73. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/avgpelite/tc-ds62.txt +0 -0
  74. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/avgpelite/tc-mp50MnNCKFMASHTO.txt +0 -0
  75. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/avgpelite/tc-prefs.txt +0 -0
  76. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/avgpelite_34/tc-6axmn.txt +0 -0
  77. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/avgpelite_34/tc-avgpelite.txt +0 -0
  78. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/avgpelite_34/tc-ds62.txt +0 -0
  79. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/avgpelite_34/tc-prefs.txt +0 -0
  80. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/inv1-ic.txt +0 -0
  81. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/inv1-log.txt +0 -0
  82. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/inv2-ic.txt +0 -0
  83. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/inv2-log.txt +0 -0
  84. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/inv3-ic.txt +0 -0
  85. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/inv3-log.txt +0 -0
  86. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/uni1-ic.txt +0 -0
  87. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/uni1-log.txt +0 -0
  88. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/uni2-ic.txt +0 -0
  89. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/uni2-log.txt +0 -0
  90. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/uni3-ic.txt +0 -0
  91. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/examples/outputs/uni3-log.txt +0 -0
  92. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/notebooks/pypsbuilder.ipynb +0 -0
  93. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pyproject.toml +0 -0
  94. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/images/ptbuilder.png +0 -0
  95. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/images/pxbuilder.png +0 -0
  96. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/images/pypsbuilder.png +0 -0
  97. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/images/txbuilder.png +0 -0
  98. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/psbuilders.py +0 -0
  99. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/tcinit.py +0 -0
  100. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/tests/__init__.py +0 -0
  101. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui/addinv.ui +0 -0
  102. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui/adduni.ui +0 -0
  103. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui/compile_ui.sh +0 -0
  104. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui/ptbuilder.ui +0 -0
  105. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui/pxbuilder.ui +0 -0
  106. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui/txbuilder.ui +0 -0
  107. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui/uniguess.ui +0 -0
  108. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui_addinv.py +0 -0
  109. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui_adduni.py +0 -0
  110. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui_ptbuilder.py +0 -0
  111. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui_pxbuilder.py +0 -0
  112. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui_txbuilder.py +0 -0
  113. {pypsbuilder-2.6.2 → pypsbuilder-2.6.4}/pypsbuilder/ui_uniguess.py +0 -0
@@ -0,0 +1,20 @@
1
+ {
2
+ "creators": [
3
+ {
4
+ "name": "Lexa, Ondrej",
5
+ "orcid": "0000-0002-1825-0097",
6
+ "affiliation": "IPSG, Charles University, Prague, Czech Republic",
7
+ "type": "ProjectLeader"
8
+ }
9
+ ],
10
+ "title": "pypsbuilder - THERMOCALC front-end for constructing and visualizations of P-T, T-X and P-X pseudosections",
11
+ "access_right": "open",
12
+ "keywords": [
13
+ "metamorphic petrology",
14
+ "python",
15
+ "pseudosections"
16
+ ],
17
+ "license": "mit",
18
+ "upload_type": "software",
19
+ "language": "eng"
20
+ }
@@ -1,6 +1,16 @@
1
1
  # Changelog
2
2
  All notable pypsbuilder changes.
3
3
 
4
+ ## [2.6.4] - 2025-08-03
5
+ ### Fixed
6
+ - TC 3.51 compatibility added
7
+ ### Added
8
+ - `sys` could be used as phase to access G H S V rho variables
9
+
10
+ ## [2.6.3] - 2025-04-03
11
+ ### Fixed
12
+ - fixed multipolygon bug when subsections are merged
13
+
4
14
  ## [2.6.2] - 2025-02-11
5
15
  ### Fixed
6
16
  - f-string py3.10 bugfix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypsbuilder
3
- Version: 2.6.2
3
+ Version: 2.6.4
4
4
  Summary: THERMOCALC front-end for constructing and analyzing PT pseudosections
5
5
  Project-URL: Homepage, https://github.com/ondrolexa/pypsbuilder
6
6
  Project-URL: Documentation, https://pypsbuilder.readthedocs.io
@@ -95,6 +95,11 @@ for Windows use Command Prompt or PowerShell:
95
95
  python -m venv .venv
96
96
  .venv\Scripts\activate
97
97
 
98
+ or, if you will got error *'python' is not recognized as an internal or external command*, try:
99
+
100
+ py -m venv .venv
101
+ .venv\Scripts\activate
102
+
98
103
  > [!NOTE]
99
104
  > On Microsoft Windows, it may be required to set the execution policy in PowerShell for the user.
100
105
  > You can do this by issuing the following PowerShell command:
@@ -19,6 +19,11 @@ for Windows use Command Prompt or PowerShell:
19
19
  python -m venv .venv
20
20
  .venv\Scripts\activate
21
21
 
22
+ or, if you will got error *'python' is not recognized as an internal or external command*, try:
23
+
24
+ py -m venv .venv
25
+ .venv\Scripts\activate
26
+
22
27
  > [!NOTE]
23
28
  > On Microsoft Windows, it may be required to set the execution policy in PowerShell for the user.
24
29
  > You can do this by issuing the following PowerShell command:
@@ -1,5 +1,5 @@
1
1
  codecov:
2
- require_ci_to_pass: yes
2
+ require_ci_to_pass: true
3
3
 
4
4
  coverage:
5
5
  precision: 2
@@ -5,14 +5,14 @@
5
5
 
6
6
  .. autoclass:: TC34API
7
7
 
8
-
8
+
9
9
  .. automethod:: __init__
10
10
 
11
-
11
+
12
12
  .. rubric:: Methods
13
13
 
14
14
  .. autosummary::
15
-
15
+
16
16
  ~TC34API.__init__
17
17
  ~TC34API.calc_assemblage
18
18
  ~TC34API.calc_p
@@ -31,15 +31,15 @@
31
31
  ~TC34API.rundr
32
32
  ~TC34API.runtc
33
33
  ~TC34API.update_scriptfile
34
-
35
-
36
34
 
37
-
38
-
35
+
36
+
37
+
38
+
39
39
  .. rubric:: Attributes
40
40
 
41
41
  .. autosummary::
42
-
42
+
43
43
  ~TC34API.axfile
44
44
  ~TC34API.csvfile
45
45
  ~TC34API.dataset
@@ -52,7 +52,5 @@
52
52
  ~TC34API.ofile
53
53
  ~TC34API.prefsfile
54
54
  ~TC34API.scriptfile
55
- ~TC34API.tcnewversion
55
+ ~TC34API.tcversionfloat
56
56
  ~TC34API.tcversion
57
-
58
-
@@ -5,14 +5,14 @@
5
5
 
6
6
  .. autoclass:: TC35API
7
7
 
8
-
8
+
9
9
  .. automethod:: __init__
10
10
 
11
-
11
+
12
12
  .. rubric:: Methods
13
13
 
14
14
  .. autosummary::
15
-
15
+
16
16
  ~TC35API.__init__
17
17
  ~TC35API.calc_assemblage
18
18
  ~TC35API.calc_p
@@ -30,15 +30,15 @@
30
30
  ~TC35API.rundr
31
31
  ~TC35API.runtc
32
32
  ~TC35API.update_scriptfile
33
-
34
-
35
33
 
36
-
37
-
34
+
35
+
36
+
37
+
38
38
  .. rubric:: Attributes
39
39
 
40
40
  .. autosummary::
41
-
41
+
42
42
  ~TC35API.axfile
43
43
  ~TC35API.csvfile
44
44
  ~TC35API.dataset
@@ -51,7 +51,5 @@
51
51
  ~TC35API.ofile
52
52
  ~TC35API.prefsfile
53
53
  ~TC35API.scriptfile
54
- ~TC35API.tcnewversion
54
+ ~TC35API.tcversionfloat
55
55
  ~TC35API.tcversion
56
-
57
-
@@ -22,7 +22,7 @@ __all__ = (
22
22
  "get_tcapi",
23
23
  )
24
24
 
25
- __version__ = "2.6.2"
25
+ __version__ = "2.6.4"
26
26
  __author__ = "Ondrej Lexa"
27
27
  __copyright__ = "© Ondrej Lexa 2016-2025"
28
28
  __email__ = "lexa.ondrej@gmail.com"
@@ -451,7 +451,7 @@ class TCResult:
451
451
  )
452
452
  # bulk composition
453
453
  bulk_vals = {}
454
- oxhead, vals = bulk.split("\n")[1:] # skip oxide compositions row
454
+ oxhead, vals = bulk.split("\n")[1:3] # skip oxide compositions row
455
455
  for ox, val in zip(oxhead.split(), vals.split()[1:]):
456
456
  bulk_vals[ox] = float(val)
457
457
  data["bulk"] = bulk_vals
@@ -525,6 +525,109 @@ class TCResult:
525
525
  # Finally
526
526
  return cls(T, p, variance=variance, c=c, data=data, ptguess=ptguess)
527
527
 
528
+ @classmethod
529
+ def from_block351(cls, block, ptguess):
530
+ info, ax, sf, rbi, mode, factor, td, *mems, pems = block.split("\n\n")
531
+ bulk = "\n".join(rbi.split("\n")[:3])
532
+ rbi = "\n".join(rbi.split("\n")[3:])
533
+ # heading
534
+ data = {phase: {} for phase in info.split("{")[0].split()}
535
+ p, T = (float(v.strip()) for v in info.split("{")[1].split("}")[0].split(","))
536
+ # var or ovar?
537
+ variance = int(info.split("var = ")[1].split(" ")[0].replace(";", ""))
538
+ # a-x variables
539
+ for head, vals in zip(ax.split("\n")[::2], ax.split("\n")[1::2]):
540
+ phase, *names = head.split()
541
+ data[phase].update(
542
+ {
543
+ name.replace("({})".format(phase), ""): float(val)
544
+ for name, val in zip(names, vals.split())
545
+ }
546
+ )
547
+ # site fractions
548
+ for head, vals in zip(
549
+ sf.split("\n")[1::2], sf.split("\n")[2::2]
550
+ ): # skip site fractions row
551
+ phase, *names = head.split()
552
+ data[phase].update(
553
+ {name: float(val) for name, val in zip(names, vals.split())}
554
+ )
555
+ # bulk composition
556
+ bulk_vals = {}
557
+ oxhead, vals = bulk.split("\n")[1:3] # skip oxide compositions row
558
+ for ox, val in zip(oxhead.split(), vals.split()[1:]):
559
+ bulk_vals[ox] = float(val)
560
+ data["bulk"] = bulk_vals
561
+ # x for TX and pX
562
+ if "step" in vals:
563
+ c = float(vals.split("step")[1].split(", x =")[1])
564
+ else:
565
+ c = 0
566
+ # rbi
567
+ for row in rbi.split("\n"):
568
+ phase, *vals = row.split()
569
+ data[phase].update(
570
+ {ox: float(val) for ox, val in zip(oxhead.split(), vals)}
571
+ )
572
+ # modes (zero mode is empty field in tc350 !!!)
573
+ head, vals = mode.split("\n")
574
+ phases = head.split()[1:]
575
+ # fixed width parsing !!!
576
+ valsf = [
577
+ (
578
+ float(vals[6:][9 * i : 9 * (i + 1)].strip())
579
+ if vals[6:][9 * i : 9 * (i + 1)].strip() != ""
580
+ else 0.0
581
+ )
582
+ for i in range(len(phases))
583
+ ]
584
+ for phase, val in zip(phases, valsf):
585
+ data[phase].update({"mode": float(val)})
586
+ # factors
587
+ head, vals = factor.split("\n")
588
+ phases = head.split()[1:]
589
+ valsf = [
590
+ (
591
+ float(vals[6:][9 * i : 9 * (i + 1)].strip())
592
+ if vals[6:][9 * i : 9 * (i + 1)].strip() != ""
593
+ else 0.0
594
+ )
595
+ for i in range(len(phases))
596
+ ]
597
+ for phase, val in zip(phases, valsf):
598
+ data[phase].update({"factor": float(val)})
599
+ # thermodynamic state
600
+ head, *rows = td.split("\n")
601
+ for row in rows[:-1]:
602
+ phase, *vals = row.split()
603
+ data[phase].update(
604
+ {name: float(val) for name, val in zip(head.split(), vals)}
605
+ )
606
+ # bulk thermodynamics
607
+ sys = {}
608
+ for name, val in zip(head.split(), rows[-1].split()[1:]):
609
+ sys[name] = float(val)
610
+ data["sys"] = sys
611
+ # model end-members
612
+ if len(mems) > 0:
613
+ _, mem0 = mems[0].split("\n", maxsplit=1)
614
+ head = ["ideal", "gamma", "activity", "prop", "mu", "RTlna"]
615
+ mems[0] = mem0
616
+ for mem in mems:
617
+ ems = mem.split("\n")
618
+ phase, ems0 = ems[0].split(maxsplit=1)
619
+ ems[0] = ems0
620
+ for row in ems:
621
+ em, *vals = row.split()
622
+ phase_em = "{}({})".format(phase, em)
623
+ data[phase_em] = {name: float(val) for name, val in zip(head, vals)}
624
+ # pure end-members
625
+ for row in pems.split("\n")[:-1]:
626
+ pem, val = row.split()
627
+ data[pem].update({"mu": float(val)})
628
+ # Finally
629
+ return cls(T, p, variance=variance, c=c, data=data, ptguess=ptguess)
630
+
528
631
  def __repr__(self):
529
632
  return "p:{:g} T:{:g} V:{} c:{:g}, Phases: {}".format(
530
633
  self.p, self.T, self.variance, self.c, " ".join(self.phases)
@@ -815,20 +918,20 @@ class SectionBase:
815
918
  def splitme(edges):
816
919
  """Recursive boundary splitter"""
817
920
  for idx, edge in enumerate(edges):
818
- for _, l in lns:
819
- if edge.intersects(l):
820
- m = linemerge([edge, l])
921
+ for _, ln in lns:
922
+ if edge.intersects(ln):
923
+ m = linemerge([edge, ln])
821
924
  if m.geom_type == "MultiLineString":
822
- p = edge.intersection(l)
925
+ p = edge.intersection(ln)
823
926
  if (
824
927
  p.geom_type == "LineString"
825
928
  ): # seems to occur whe duplicate points are on line
826
929
  p = MultiPoint(p.coords)
827
930
  if p.geom_type == "MultiPoint":
828
- pts = [l.interpolate(l.project(pt)) for pt in p.geoms]
931
+ pts = [ln.interpolate(ln.project(pt)) for pt in p.geoms]
829
932
  pts = sorted(pts, key=lambda pt: edge.project(pt))
830
933
  else:
831
- pts = [l.interpolate(l.project(p))]
934
+ pts = [ln.interpolate(ln.project(p))]
832
935
  edges.pop(idx)
833
936
  pts = (
834
937
  [Point(edge.coords[0])] + pts + [Point(edge.coords[-1])]
@@ -858,7 +961,7 @@ class SectionBase:
858
961
  while do:
859
962
  edges, do = splitme(edges)
860
963
  # polygonize
861
- polys = list(polygonize(edges + [l for _, l in lns]))
964
+ polys = list(polygonize(edges + [ln for _, ln in lns]))
862
965
  # create shapes
863
966
  shapes = {}
864
967
  unilists = {}
@@ -245,7 +245,7 @@ class PS:
245
245
  for comp in (
246
246
  set(self.all_data_keys.keys())
247
247
  .difference(self.phases)
248
- .difference(set(["bulk", "sys"]))
248
+ .difference({'sys'})
249
249
  ):
250
250
  k, v = comp.split(")")[0].split("(")
251
251
  if k in em:
@@ -434,6 +434,7 @@ class PS:
434
434
  # if len(res) > 0:
435
435
  # for k in res[0]['data'].keys():
436
436
  # data[k] = list(res[0]['data'][k].keys())
437
+ data['sys'] = ['G', 'H', 'S', 'V', 'rho']
437
438
  self.all_data_keys = data
438
439
 
439
440
  def collect_inv_data(self, key, phase, expr):
@@ -612,7 +613,7 @@ class PS:
612
613
  mn, mx = sys.float_info.max, -sys.float_info.max
613
614
  recs = OrderedDict()
614
615
  for key in self:
615
- if phase.split("(")[0] in key:
616
+ if phase.split("(")[0] in key or phase == "sys":
616
617
  d = self.collect_data(key, phase, expr, which=which)
617
618
  z = d["data"]
618
619
  if z:
@@ -700,13 +701,18 @@ class PS:
700
701
  show = False
701
702
  ax = fig.add_subplot()
702
703
  for k, shape in self.shapes.items():
703
- patch = PolygonPatch(
704
- shape, fc=pscmap(norm(self.variance[k])), ec="none"
705
- )
706
- ax.add_patch(patch)
707
- if show_vertices:
708
- x, y = zip(*patch.get_path().vertices)
709
- ax.plot(x, y, "k.", ms=3)
704
+ if shape.geom_type == "MultiPolygon":
705
+ shapelist = list(shape.geoms)
706
+ else:
707
+ shapelist = [shape]
708
+ for shape in shapelist:
709
+ patch = PolygonPatch(
710
+ shape, fc=pscmap(norm(self.variance[k])), ec="none"
711
+ )
712
+ ax.add_patch(patch)
713
+ if show_vertices:
714
+ x, y = zip(*patch.get_path().vertices)
715
+ ax.plot(x, y, "k.", ms=3)
710
716
  ax.autoscale_view()
711
717
  self.add_overlay(ax, label=label, skiplabels=skiplabels, fontsize=labelfs)
712
718
  if out:
@@ -831,27 +837,42 @@ class PS:
831
837
  def add_overlay(self, ax, fc="none", ec="k", label=False, skiplabels=0, fontsize=6):
832
838
  area = (self.xrange[1] - self.xrange[0]) * (self.yrange[1] - self.yrange[0])
833
839
  for k, shape in self.shapes.items():
834
- ax.add_patch(PolygonPatch(shape, ec=ec, fc=fc, lw=0.5))
835
- if label and (100 * shape.area / area > skiplabels):
836
- # multiline for long labels
837
- tl = sorted(list(k.difference(self.tc.excess)))
838
- extra = self.tc.excess.difference(self.tc.excess.intersection(k))
839
- # if excess in scriptfile is not accurate
840
- if extra:
841
- tl += ["-{}".format(pp) for pp in extra]
842
- wp = len(tl) // 4 + int(len(tl) % 4 > 1)
843
- txt = "\n".join(
844
- [
845
- " ".join([self.abbr.get(sa, sa) for sa in s])
846
- for s in [
847
- tl[i * len(tl) // wp : (i + 1) * len(tl) // wp]
848
- for i in range(wp)
840
+ if shape.geom_type == "MultiPolygon":
841
+ shapelist = list(shape.geoms)
842
+ else:
843
+ shapelist = [shape]
844
+ for shape in shapelist:
845
+ ax.add_patch(PolygonPatch(shape, ec=ec, fc=fc, lw=0.5))
846
+ if label and (100 * shape.area / area > skiplabels):
847
+ # multiline for long labels
848
+ tl = sorted(list(k.difference(self.tc.excess)))
849
+ extra = self.tc.excess.difference(self.tc.excess.intersection(k))
850
+ # if excess in scriptfile is not accurate
851
+ if extra:
852
+ tl += ["-{}".format(pp) for pp in extra]
853
+ wp = len(tl) // 4 + int(len(tl) % 4 > 1)
854
+ txt = "\n".join(
855
+ [
856
+ " ".join([self.abbr.get(sa, sa) for sa in s])
857
+ for s in [
858
+ tl[i * len(tl) // wp : (i + 1) * len(tl) // wp]
859
+ for i in range(wp)
860
+ ]
849
861
  ]
850
- ]
851
- )
852
- if shape.geom_type == "MultiPolygon":
853
- for part in shape:
854
- xy = part.representative_point().coords[0]
862
+ )
863
+ if shape.geom_type == "MultiPolygon":
864
+ for part in shape:
865
+ xy = part.representative_point().coords[0]
866
+ ax.annotate(
867
+ text=txt,
868
+ xy=xy,
869
+ weight="bold",
870
+ fontsize=fontsize,
871
+ ha="center",
872
+ va="center",
873
+ )
874
+ else:
875
+ xy = shape.representative_point().coords[0]
855
876
  ax.annotate(
856
877
  text=txt,
857
878
  xy=xy,
@@ -860,16 +881,6 @@ class PS:
860
881
  ha="center",
861
882
  va="center",
862
883
  )
863
- else:
864
- xy = shape.representative_point().coords[0]
865
- ax.annotate(
866
- text=txt,
867
- xy=xy,
868
- weight="bold",
869
- fontsize=fontsize,
870
- ha="center",
871
- va="center",
872
- )
873
884
 
874
885
  def show_data(self, key, phase, expr=None, which=7):
875
886
  """Convinient function to show values of expression
@@ -1325,6 +1336,7 @@ class PS:
1325
1336
  Default False.
1326
1337
  labelkeys (frozenset or list): Keys of divariant fields where contours
1327
1338
  should be labeled.
1339
+ clabelfs (int): Contour labels font size. Default 9
1328
1340
  nosplit (bool): Controls whether the contour underlying labels are
1329
1341
  removed or not. Defaut True
1330
1342
  gradient (bool): Whether the first derivate of values should be used.
@@ -1425,7 +1437,7 @@ class PS:
1425
1437
  ax = fig.add_subplot()
1426
1438
  for key in recs:
1427
1439
  phase_parts = phase.split(")")[0].split("(")
1428
- if phase_parts[0] in key:
1440
+ if phase_parts[0] in key or phase == "sys":
1429
1441
  tmin, pmin, tmax, pmax = self.shapes[key].bounds
1430
1442
  # ttspace = self.xspace[np.logical_and(self.xspace >= tmin - self.xstep, self.xspace <= tmax + self.xstep)]
1431
1443
  # ppspace = self.yspace[np.logical_and(self.yspace >= pmin - self.ystep, self.yspace <= pmax + self.ystep)]
@@ -1556,57 +1568,62 @@ class PS:
1556
1568
  else:
1557
1569
  cntv = 10
1558
1570
  # ------------
1559
- with warnings.catch_warnings():
1560
- warnings.filterwarnings("ignore", category=UserWarning)
1561
- if filled:
1562
- if colors is not None:
1563
- cont = ax.contourf(
1564
- tg, pg, zg, cntv, colors=colors, alpha=alpha
1565
- )
1566
- if filled_over:
1567
- contover = ax.contour(
1568
- tg, pg, zg, cntv, colors=colors
1571
+ if self.shapes[key].geom_type == "MultiPolygon":
1572
+ shapelist = list(self.shapes[key].geoms)
1573
+ else:
1574
+ shapelist = [self.shapes[key]]
1575
+ for shape in shapelist:
1576
+ with warnings.catch_warnings():
1577
+ warnings.filterwarnings("ignore", category=UserWarning)
1578
+ if filled:
1579
+ if colors is not None:
1580
+ cont = ax.contourf(
1581
+ tg, pg, zg, cntv, colors=colors, alpha=alpha
1569
1582
  )
1570
- else:
1571
- cont = ax.contourf(
1572
- tg, pg, zg, cntv, cmap=cmap, alpha=alpha
1573
- )
1574
- if filled_over:
1575
- contover = ax.contour(
1576
- tg, pg, zg, cntv, colors="whitesmoke"
1583
+ if filled_over:
1584
+ contover = ax.contour(
1585
+ tg, pg, zg, cntv, colors=colors
1586
+ )
1587
+ else:
1588
+ cont = ax.contourf(
1589
+ tg, pg, zg, cntv, cmap=cmap, alpha=alpha
1577
1590
  )
1578
- else:
1579
- if colors is not None:
1580
- cont = ax.contour(tg, pg, zg, cntv, colors=colors)
1591
+ if filled_over:
1592
+ contover = ax.contour(
1593
+ tg, pg, zg, cntv, colors="whitesmoke"
1594
+ )
1581
1595
  else:
1582
- cont = ax.contour(tg, pg, zg, cntv, cmap=cmap)
1583
- patch = PolygonPatch(self.shapes[key], fc="none", ec="none")
1584
- ax.add_patch(patch)
1585
- # label if needed
1586
- if (not filled or filled_over) and key in labelkyes_ok:
1587
- positions = []
1588
- contlbl = contover if filled_over else cont
1589
- for seg in contlbl.get_paths():
1590
- inside = np.fromiter(
1591
- map(
1592
- self.shapes[key].contains,
1593
- MultiPoint(seg.vertices).geoms,
1594
- ),
1595
- dtype=bool,
1596
+ if colors is not None:
1597
+ cont = ax.contour(tg, pg, zg, cntv, colors=colors)
1598
+ else:
1599
+ cont = ax.contour(tg, pg, zg, cntv, cmap=cmap)
1600
+ patch = PolygonPatch(shape, fc="none", ec="none")
1601
+ ax.add_patch(patch)
1602
+ # label if needed
1603
+ if (not filled or filled_over) and key in labelkyes_ok:
1604
+ positions = []
1605
+ contlbl = contover if filled_over else cont
1606
+ for seg in contlbl.get_paths():
1607
+ inside = np.fromiter(
1608
+ map(
1609
+ shape.contains,
1610
+ MultiPoint(seg.vertices).geoms,
1611
+ ),
1612
+ dtype=bool,
1613
+ )
1614
+ if np.any(inside):
1615
+ positions.append(seg.vertices[inside].mean(axis=0))
1616
+ ax.clabel(
1617
+ contlbl,
1618
+ fontsize=kwargs.get("clabelfs", 9),
1619
+ manual=positions,
1620
+ fmt="%g",
1621
+ inline_spacing=3,
1622
+ inline=not nosplit,
1596
1623
  )
1597
- if np.any(inside):
1598
- positions.append(seg.vertices[inside].mean(axis=0))
1599
- ax.clabel(
1600
- contlbl,
1601
- fontsize=9,
1602
- manual=positions,
1603
- fmt="%g",
1604
- inline_spacing=3,
1605
- inline=not nosplit,
1606
- )
1607
- cont.set_clip_path(patch)
1608
- if filled and filled_over:
1609
- contover.set_clip_path(patch)
1624
+ cont.set_clip_path(patch)
1625
+ if filled and filled_over:
1626
+ contover.set_clip_path(patch)
1610
1627
 
1611
1628
  if only is None:
1612
1629
  self.add_overlay(ax)
@@ -2720,7 +2737,9 @@ class PTPS(PS):
2720
2737
  )
2721
2738
  plt.show()
2722
2739
 
2723
- def pointcalc(self, t=None, p=None, label=False, skiplabels=0, labelfs=6, show_output=False):
2740
+ def pointcalc(
2741
+ self, t=None, p=None, label=False, skiplabels=0, labelfs=6, show_output=False
2742
+ ):
2724
2743
  if t is None or p is None:
2725
2744
  fig, ax = plt.subplots()
2726
2745
  ax.autoscale_view()