xarpes 0.4.0__tar.gz → 0.6.0__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.
- {xarpes-0.4.0 → xarpes-0.6.0}/.gitignore +7 -1
- {xarpes-0.4.0 → xarpes-0.6.0}/PKG-INFO +14 -8
- {xarpes-0.4.0 → xarpes-0.6.0}/README.md +11 -4
- xarpes-0.6.0/dev_tools/Rmd2ipynb.py +109 -0
- xarpes-0.4.0/dev_tools/Rmd2py.py → xarpes-0.6.0/dev_tools/ipynb2Rmd2py.py +167 -19
- {xarpes-0.4.0 → xarpes-0.6.0}/doc/conf.py +2 -1
- xarpes-0.6.0/doc/index.rst +29 -0
- xarpes-0.6.0/doc/modules/bandmap.rst +5 -0
- xarpes-0.6.0/doc/modules/mdcs.rst +5 -0
- xarpes-0.6.0/doc/modules/selfenergies.rst +5 -0
- xarpes-0.6.0/doc/modules/settings_parameters.rst +7 -0
- xarpes-0.6.0/doc/modules/settings_plots.rst +8 -0
- xarpes-0.6.0/doc/notebooks/graphene.ipynb +993 -0
- xarpes-0.6.0/doc/notebooks/srtio3.ipynb +1121 -0
- xarpes-0.6.0/doc/notebooks/verification.ipynb +1567 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/doc/requirements.txt +2 -1
- xarpes-0.6.0/examples/graphene/data_sets/graphene_152_angles.npy +0 -0
- xarpes-0.6.0/examples/graphene/data_sets/graphene_152_ekin.npy +0 -0
- xarpes-0.6.0/examples/graphene/data_sets/graphene_152_intensities.npy +0 -0
- xarpes-0.6.0/examples/graphene/graphene.Rmd +359 -0
- xarpes-0.6.0/examples/graphene/graphene.py +292 -0
- xarpes-0.6.0/examples/srtio3/data_sets/STO_2_0010STO_2_angles.npy +0 -0
- xarpes-0.6.0/examples/srtio3/data_sets/STO_2_0010STO_2_ekin.npy +0 -0
- xarpes-0.6.0/examples/srtio3/data_sets/STO_2_0010STO_2_intensities.npy +0 -0
- xarpes-0.6.0/examples/srtio3/srtio3.Rmd +329 -0
- xarpes-0.6.0/examples/srtio3/srtio3.py +262 -0
- xarpes-0.6.0/examples/verification/data_sets/verification_angles.npy +0 -0
- xarpes-0.6.0/examples/verification/data_sets/verification_intensities.npy +0 -0
- xarpes-0.6.0/examples/verification/data_sets/verification_kinergies.npy +0 -0
- xarpes-0.6.0/examples/verification/verification.Rmd +186 -0
- xarpes-0.6.0/examples/verification/verification.py +142 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/pyproject.toml +1 -1
- xarpes-0.6.0/xarpes/__init__.py +36 -0
- xarpes-0.6.0/xarpes/bandmap.py +897 -0
- xarpes-0.6.0/xarpes/constants.py +13 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/xarpes/distributions.py +45 -43
- {xarpes-0.4.0 → xarpes-0.6.0}/xarpes/functions.py +247 -7
- xarpes-0.6.0/xarpes/mdcs.py +1078 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/xarpes/plotting.py +1 -47
- xarpes-0.6.0/xarpes/selfenergies.py +1816 -0
- xarpes-0.6.0/xarpes/settings_parameters.py +75 -0
- xarpes-0.6.0/xarpes/settings_plots.py +54 -0
- xarpes-0.4.0/doc/index.rst +0 -17
- xarpes-0.4.0/doc/modules/spectral.rst +0 -5
- xarpes-0.4.0/examples/graphene/graphene.Rmd +0 -431
- xarpes-0.4.0/examples/graphene/graphene.py +0 -348
- xarpes-0.4.0/examples/srtio3/srtio3.Rmd +0 -530
- xarpes-0.4.0/examples/srtio3/srtio3.py +0 -429
- xarpes-0.4.0/xarpes/__init__.py +0 -6
- xarpes-0.4.0/xarpes/constants.py +0 -12
- xarpes-0.4.0/xarpes/spectral.py +0 -2476
- {xarpes-0.4.0 → xarpes-0.6.0}/.readthedocs.yaml +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/LICENSE +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/doc/Makefile +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/doc/README.md +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/doc/_static/xarpes_small.svg +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/doc/modules/distributions.rst +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/doc/modules/functions.rst +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/doc/modules/plotting.rst +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/examples/graphene/data_sets/graphene_152.ibw +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/examples/srtio3/data_sets/STO_2_0010STO_2_.ibw +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/logo/Makefile +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/logo/exubi.svg +0 -0
- {xarpes-0.4.0 → xarpes-0.6.0}/logo/xarpes.svg +0 -0
|
@@ -81,6 +81,10 @@ target/
|
|
|
81
81
|
.ipynb_checkpoints
|
|
82
82
|
*.ipynb
|
|
83
83
|
|
|
84
|
+
# --- allow tracked notebooks in documentation ---
|
|
85
|
+
!doc/notebooks/
|
|
86
|
+
!doc/notebooks/*.ipynb
|
|
87
|
+
|
|
84
88
|
# IPython
|
|
85
89
|
profile_default/
|
|
86
90
|
ipython_config.py
|
|
@@ -173,5 +177,7 @@ cython_debug/
|
|
|
173
177
|
# VS Code
|
|
174
178
|
.vscode/
|
|
175
179
|
|
|
176
|
-
# Ignore
|
|
180
|
+
# Ignore conversion scripts if placed in examples folder
|
|
181
|
+
examples/Rmd2ipynb.py
|
|
182
|
+
examples/ipynb2Rmd2py.py
|
|
177
183
|
examples/Rmd2py.py
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: xarpes
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Extraction from angle resolved photoemission spectra
|
|
5
5
|
Author: xARPES Developers
|
|
6
6
|
Requires-Python: >=3.7.0
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
License-File: LICENSE
|
|
11
10
|
Requires-Dist: igor2>=0.5.8
|
|
12
11
|
Requires-Dist: jupyterlab
|
|
13
12
|
Requires-Dist: jupytext
|
|
14
|
-
Requires-Dist: matplotlib
|
|
13
|
+
Requires-Dist: matplotlib<3.10.0
|
|
15
14
|
Requires-Dist: numpy
|
|
16
15
|
Requires-Dist: scipy
|
|
17
16
|
Requires-Dist: lmfit
|
|
@@ -33,7 +32,9 @@ This project is currently undergoing **beta testing**. Some of the functionaliti
|
|
|
33
32
|
|
|
34
33
|
# Contributing
|
|
35
34
|
|
|
36
|
-
Contributions to the code are most welcome. xARPES is intended to co-develop alongside the increasing complexity of experimental ARPES data sets. Contributions can be made by forking the code and creating a pull request. Importing of file formats from different beamlines is particularly encouraged.
|
|
35
|
+
Contributions to the code are most welcome. xARPES is intended to co-develop alongside the increasing complexity of experimental ARPES data sets. Contributions can be made by forking the code and creating a pull request. Importing of file formats from different beamlines is particularly encouraged. For development of the examples, the following scripts in `/dev_tools` could be useful:
|
|
36
|
+
- The `Rmd2ipynb.py` file, to generate the `.ipynb` from which the examples can conveniently be developed; to be executed after cloning/pulling updated `.Rmd` and `.py` files, or if you prefer developing with `.Rmd` files.
|
|
37
|
+
- The `ipynb2Rmd2py.py` file, to synchronise the `.Rmd` and `.py` files from the `.ipynb` file; to be executed right before pushing modifications to the repository. Note that this script resets some metadata in the `.Rmd` to prevent the tracking of their changes due to local virtual environments, etc.
|
|
37
38
|
|
|
38
39
|
# Installation
|
|
39
40
|
|
|
@@ -91,7 +92,7 @@ Answer `y` to questions. Create and activate a new environment:
|
|
|
91
92
|
conda create -n <my_env> -c conda-forge
|
|
92
93
|
conda activate <my_env>
|
|
93
94
|
|
|
94
|
-
Where `<my_env>` must be replaced by your desired name. Package compatibility
|
|
95
|
+
Where `<my_env>` must be replaced by your desired name. Package compatibility issues may arise if conda installs from different channels. This can be prevented by appending `--strict-channel-priority` to the creation command.
|
|
95
96
|
|
|
96
97
|
### Installing xARPES
|
|
97
98
|
|
|
@@ -148,12 +149,17 @@ Then perform editable installation:
|
|
|
148
149
|
|
|
149
150
|
# Examples
|
|
150
151
|
|
|
151
|
-
After installation of xARPES, the `examples/` folder can be downloaded
|
|
152
|
+
After installation of xARPES, the `examples/` folder can be downloaded from the terminal into the current directory:
|
|
152
153
|
|
|
153
|
-
|
|
154
|
+
xarpes_download_examples
|
|
154
155
|
|
|
155
156
|
This attempts to download the examples from the version corresponding encountered in `__init__.py`. If no corresponding tagged version can be downloaded, the code attempts to download the latest examples instead.
|
|
156
157
|
|
|
158
|
+
The examples can also be installed by executing `.py`or `.ipynb` executable files containing the following:
|
|
159
|
+
|
|
160
|
+
import xarpes
|
|
161
|
+
xarpes.download_examples()
|
|
162
|
+
|
|
157
163
|
# Execution
|
|
158
164
|
|
|
159
165
|
It is recommended to use JupyterLab to analyse data. JupyterLab is launched using:
|
|
@@ -10,7 +10,9 @@ This project is currently undergoing **beta testing**. Some of the functionaliti
|
|
|
10
10
|
|
|
11
11
|
# Contributing
|
|
12
12
|
|
|
13
|
-
Contributions to the code are most welcome. xARPES is intended to co-develop alongside the increasing complexity of experimental ARPES data sets. Contributions can be made by forking the code and creating a pull request. Importing of file formats from different beamlines is particularly encouraged.
|
|
13
|
+
Contributions to the code are most welcome. xARPES is intended to co-develop alongside the increasing complexity of experimental ARPES data sets. Contributions can be made by forking the code and creating a pull request. Importing of file formats from different beamlines is particularly encouraged. For development of the examples, the following scripts in `/dev_tools` could be useful:
|
|
14
|
+
- The `Rmd2ipynb.py` file, to generate the `.ipynb` from which the examples can conveniently be developed; to be executed after cloning/pulling updated `.Rmd` and `.py` files, or if you prefer developing with `.Rmd` files.
|
|
15
|
+
- The `ipynb2Rmd2py.py` file, to synchronise the `.Rmd` and `.py` files from the `.ipynb` file; to be executed right before pushing modifications to the repository. Note that this script resets some metadata in the `.Rmd` to prevent the tracking of their changes due to local virtual environments, etc.
|
|
14
16
|
|
|
15
17
|
# Installation
|
|
16
18
|
|
|
@@ -68,7 +70,7 @@ Answer `y` to questions. Create and activate a new environment:
|
|
|
68
70
|
conda create -n <my_env> -c conda-forge
|
|
69
71
|
conda activate <my_env>
|
|
70
72
|
|
|
71
|
-
Where `<my_env>` must be replaced by your desired name. Package compatibility
|
|
73
|
+
Where `<my_env>` must be replaced by your desired name. Package compatibility issues may arise if conda installs from different channels. This can be prevented by appending `--strict-channel-priority` to the creation command.
|
|
72
74
|
|
|
73
75
|
### Installing xARPES
|
|
74
76
|
|
|
@@ -125,12 +127,17 @@ Then perform editable installation:
|
|
|
125
127
|
|
|
126
128
|
# Examples
|
|
127
129
|
|
|
128
|
-
After installation of xARPES, the `examples/` folder can be downloaded
|
|
130
|
+
After installation of xARPES, the `examples/` folder can be downloaded from the terminal into the current directory:
|
|
129
131
|
|
|
130
|
-
|
|
132
|
+
xarpes_download_examples
|
|
131
133
|
|
|
132
134
|
This attempts to download the examples from the version corresponding encountered in `__init__.py`. If no corresponding tagged version can be downloaded, the code attempts to download the latest examples instead.
|
|
133
135
|
|
|
136
|
+
The examples can also be installed by executing `.py`or `.ipynb` executable files containing the following:
|
|
137
|
+
|
|
138
|
+
import xarpes
|
|
139
|
+
xarpes.download_examples()
|
|
140
|
+
|
|
134
141
|
# Execution
|
|
135
142
|
|
|
136
143
|
It is recommended to use JupyterLab to analyse data. JupyterLab is launched using:
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Generate .ipynb notebooks from .Rmd files using Jupytext.
|
|
4
|
+
|
|
5
|
+
- For every .Rmd (excluding hidden folders and .ipynb_checkpoints),
|
|
6
|
+
create or overwrite a sibling <notebook>.ipynb using Jupytext.
|
|
7
|
+
|
|
8
|
+
Dependencies:
|
|
9
|
+
pip install jupytext
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
Place Rmd2ipynb.py in the /examples directory, where it is .gitignored.
|
|
13
|
+
$ python Rmd2ipynb.py # run from anywhere; it operates where it exists.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def find_base_dir() -> str:
|
|
22
|
+
"""Return the directory where this script lives (or CWD in a REPL)."""
|
|
23
|
+
return (os.path.dirname(os.path.abspath(__file__))
|
|
24
|
+
if "__file__" in globals() else os.getcwd())
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def is_hidden(name: str) -> bool:
|
|
28
|
+
"""Return True if a file or directory name is considered hidden."""
|
|
29
|
+
return name.startswith(".")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_jupytext() -> Optional[object]:
|
|
33
|
+
"""
|
|
34
|
+
Try to import jupytext and return the module, or None if unavailable.
|
|
35
|
+
|
|
36
|
+
Prints a single warning if jupytext is not installed.
|
|
37
|
+
"""
|
|
38
|
+
try:
|
|
39
|
+
import jupytext # type: ignore
|
|
40
|
+
return jupytext
|
|
41
|
+
except ImportError:
|
|
42
|
+
print(
|
|
43
|
+
"[WARN] 'jupytext' is not installed. "
|
|
44
|
+
"Install it with 'pip install jupytext' to enable "
|
|
45
|
+
".Rmd -> .ipynb conversion.",
|
|
46
|
+
file=sys.stderr,
|
|
47
|
+
)
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def convert_rmd_to_ipynb(rmd_path: str, jupytext) -> None:
|
|
52
|
+
"""
|
|
53
|
+
Convert a single .Rmd file to a .ipynb notebook using Jupytext.
|
|
54
|
+
|
|
55
|
+
The .ipynb file is written next to the .Rmd file. Existing notebooks
|
|
56
|
+
are overwritten.
|
|
57
|
+
"""
|
|
58
|
+
base, ext = os.path.splitext(rmd_path)
|
|
59
|
+
if ext.lower() != ".rmd":
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
ipynb_path = base + ".ipynb"
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
# Let Jupytext auto-detect the format from the extension
|
|
66
|
+
nb = jupytext.read(rmd_path)
|
|
67
|
+
jupytext.write(nb, ipynb_path)
|
|
68
|
+
print(f"Converted: {rmd_path} -> {ipynb_path}")
|
|
69
|
+
except Exception as exc:
|
|
70
|
+
print(
|
|
71
|
+
f"[ERROR] Failed to convert '{rmd_path}' to .ipynb: {exc}",
|
|
72
|
+
file=sys.stderr,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def main() -> None:
|
|
77
|
+
base_dir = find_base_dir()
|
|
78
|
+
jupytext = get_jupytext()
|
|
79
|
+
if jupytext is None:
|
|
80
|
+
# Nothing to do if we don't have jupytext
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
converted_any = False
|
|
84
|
+
|
|
85
|
+
for path, folders, files in os.walk(base_dir, topdown=True):
|
|
86
|
+
# Skip hidden folders and notebook checkpoint caches
|
|
87
|
+
folders[:] = [
|
|
88
|
+
name for name in folders
|
|
89
|
+
if not is_hidden(name) and name != ".ipynb_checkpoints"
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
for name in files:
|
|
93
|
+
if is_hidden(name):
|
|
94
|
+
continue
|
|
95
|
+
if not name.endswith(".Rmd"):
|
|
96
|
+
continue
|
|
97
|
+
if ".ipynb_checkpoints" in path:
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
rmd = os.path.join(path, name)
|
|
101
|
+
convert_rmd_to_ipynb(rmd, jupytext)
|
|
102
|
+
converted_any = True
|
|
103
|
+
|
|
104
|
+
if not converted_any:
|
|
105
|
+
print("No .Rmd files found to convert.")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
if __name__ == "__main__":
|
|
109
|
+
main()
|
|
@@ -15,17 +15,23 @@ Usage:
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
import os
|
|
18
|
+
import re
|
|
18
19
|
import shutil
|
|
19
20
|
import subprocess
|
|
20
21
|
import sys
|
|
21
22
|
|
|
23
|
+
|
|
22
24
|
def find_base_dir() -> str:
|
|
23
25
|
# Safe base directory (works both when run as script or in REPL)
|
|
24
|
-
return os.path.dirname(os.path.abspath(__file__))
|
|
26
|
+
return (os.path.dirname(os.path.abspath(__file__))
|
|
27
|
+
if "__file__" in globals()
|
|
28
|
+
else os.getcwd())
|
|
29
|
+
|
|
25
30
|
|
|
26
31
|
def is_hidden(name: str) -> bool:
|
|
27
32
|
return name.startswith(".")
|
|
28
33
|
|
|
34
|
+
|
|
29
35
|
def run_jupytext_ipynb_to_rmd(ipynb_path: str) -> bool:
|
|
30
36
|
"""
|
|
31
37
|
Use the jupytext CLI to convert .ipynb -> .Rmd next to it.
|
|
@@ -33,29 +39,40 @@ def run_jupytext_ipynb_to_rmd(ipynb_path: str) -> bool:
|
|
|
33
39
|
"""
|
|
34
40
|
jupytext = shutil.which("jupytext")
|
|
35
41
|
if not jupytext:
|
|
36
|
-
print("[WARN] 'jupytext' not found on PATH.
|
|
42
|
+
print("[WARN] 'jupytext' not found on PATH. "
|
|
43
|
+
"Skipping .ipynb -> .Rmd step for:",
|
|
37
44
|
ipynb_path, file=sys.stderr)
|
|
38
45
|
return False
|
|
39
46
|
|
|
40
47
|
cmd = [jupytext, "--to", "rmarkdown", ipynb_path]
|
|
41
48
|
try:
|
|
42
|
-
res = subprocess.run(
|
|
49
|
+
res = subprocess.run(
|
|
50
|
+
cmd,
|
|
51
|
+
check=True,
|
|
52
|
+
stdout=subprocess.PIPE,
|
|
53
|
+
stderr=subprocess.STDOUT,
|
|
54
|
+
text=True,
|
|
55
|
+
)
|
|
43
56
|
# Optional: uncomment to see jupytext output
|
|
44
57
|
# print(res.stdout, end="")
|
|
45
58
|
return True
|
|
46
59
|
except subprocess.CalledProcessError as e:
|
|
47
|
-
print(f"[ERROR] jupytext failed for {ipynb_path}\n{e.stdout}",
|
|
60
|
+
print(f"[ERROR] jupytext failed for {ipynb_path}\n{e.stdout}",
|
|
61
|
+
file=sys.stderr)
|
|
48
62
|
return False
|
|
49
63
|
|
|
64
|
+
|
|
50
65
|
def convert_rmd_to_py(rmd_path: str) -> None:
|
|
51
66
|
"""
|
|
52
67
|
Convert a single .Rmd file to a .py script:
|
|
53
68
|
- YAML front matter is skipped
|
|
54
69
|
- Markdown outside code fences is commented with '# '
|
|
55
|
-
- Code inside fences (``` or ~~~) is written verbatim (with existing magic
|
|
70
|
+
- Code inside fences (``` or ~~~) is written verbatim (with existing magic
|
|
71
|
+
handling)
|
|
56
72
|
"""
|
|
57
73
|
py_path = rmd_path[:-3] + "py" # replace .Rmd with .py
|
|
58
|
-
with open(rmd_path, "r", encoding="utf-8") as lines,
|
|
74
|
+
with open(rmd_path, "r", encoding="utf-8") as lines, \
|
|
75
|
+
open(py_path, "w", encoding="utf-8") as text:
|
|
59
76
|
text.write("#!/usr/bin/env python3\n")
|
|
60
77
|
first_magic_comment = True
|
|
61
78
|
in_yaml = False
|
|
@@ -64,31 +81,33 @@ def convert_rmd_to_py(rmd_path: str) -> None:
|
|
|
64
81
|
for raw in lines:
|
|
65
82
|
line = raw
|
|
66
83
|
|
|
67
|
-
# ---- YAML front matter
|
|
84
|
+
# ---- YAML front matter --------------------------------------------
|
|
68
85
|
if line.startswith("---") and not in_code:
|
|
69
86
|
in_yaml = not in_yaml
|
|
70
87
|
continue
|
|
71
88
|
if in_yaml:
|
|
72
89
|
continue
|
|
73
90
|
|
|
74
|
-
# ---- Fence open/close (```... or ~~~...)
|
|
91
|
+
# ---- Fence open/close (```... or ~~~...) --------------------------
|
|
75
92
|
# Rmd/Quarto code chunks: ```{python, echo=FALSE} ... ```
|
|
76
|
-
if (line.lstrip().startswith("```") or
|
|
93
|
+
if (line.lstrip().startswith("```") or
|
|
94
|
+
line.lstrip().startswith("~~~")) and not in_yaml:
|
|
77
95
|
in_code = not in_code
|
|
78
96
|
# Do not emit the fence line itself
|
|
79
97
|
continue
|
|
80
98
|
|
|
81
99
|
if in_code:
|
|
82
|
-
# ---- Inside code fence: keep code, apply your filters
|
|
100
|
+
# ---- Inside code fence: keep code, apply your filters ---------
|
|
83
101
|
# Skip lines marked as "Jupyter only"
|
|
84
102
|
if "Jupyter only" in line:
|
|
85
103
|
continue
|
|
86
104
|
|
|
87
105
|
# Remove IPython magics
|
|
88
|
-
if "%matplotlib widget" in line or
|
|
106
|
+
if ("%matplotlib widget" in line or
|
|
107
|
+
"%matplotlib inline" in line):
|
|
89
108
|
continue
|
|
90
109
|
|
|
91
|
-
# Remove global Jupyter hooks (e.g. get_ipython().events
|
|
110
|
+
# Remove global Jupyter hooks (e.g. get_ipython().events...)
|
|
92
111
|
if "get_ipython" in line:
|
|
93
112
|
continue
|
|
94
113
|
|
|
@@ -104,22 +123,104 @@ def convert_rmd_to_py(rmd_path: str) -> None:
|
|
|
104
123
|
text.write(line)
|
|
105
124
|
|
|
106
125
|
else:
|
|
107
|
-
# ---- Outside code fence: Markdown -> Python comments
|
|
126
|
+
# ---- Outside code fence: Markdown -> Python comments ----------
|
|
108
127
|
if line.strip() == "":
|
|
109
128
|
# Preserve blank lines (safe in Python)
|
|
110
129
|
text.write("\n")
|
|
111
130
|
else:
|
|
112
|
-
# Comment any Markdown/text line so it doesn't break
|
|
131
|
+
# Comment any Markdown/text line so it doesn't break
|
|
132
|
+
# execution
|
|
113
133
|
text.write("# " + line)
|
|
114
134
|
|
|
135
|
+
|
|
136
|
+
def normalise_rmd_metadata(rmd_path: str) -> None:
|
|
137
|
+
"""
|
|
138
|
+
Standardise the YAML metadata of the Rmd file (string-based, no yaml lib):
|
|
139
|
+
|
|
140
|
+
- jupytext_version: 1.15.2
|
|
141
|
+
- kernelspec.display_name: Python 3 (ipykernel)
|
|
142
|
+
- kernelspec.name: python3
|
|
143
|
+
|
|
144
|
+
Only modifies existing lines in the YAML header. If the keys do not exist,
|
|
145
|
+
nothing is added.
|
|
146
|
+
"""
|
|
147
|
+
try:
|
|
148
|
+
with open(rmd_path, "r", encoding="utf-8") as f:
|
|
149
|
+
lines = f.readlines()
|
|
150
|
+
except OSError:
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
if not lines:
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
# Find first two '---' lines that delimit the YAML front matter.
|
|
157
|
+
if not lines[0].startswith("---"):
|
|
158
|
+
return
|
|
159
|
+
|
|
160
|
+
yaml_start = 0
|
|
161
|
+
yaml_end = None
|
|
162
|
+
for i in range(1, len(lines)):
|
|
163
|
+
if lines[i].startswith("---"):
|
|
164
|
+
yaml_end = i
|
|
165
|
+
break
|
|
166
|
+
|
|
167
|
+
if yaml_end is None:
|
|
168
|
+
# Malformed header, bail out.
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
header_lines = lines[yaml_start + 1:yaml_end]
|
|
172
|
+
header = "".join(header_lines)
|
|
173
|
+
|
|
174
|
+
# Replace jupytext_version
|
|
175
|
+
header = re.sub(
|
|
176
|
+
r'^(\s*jupytext_version:\s*).*$',
|
|
177
|
+
r'\g<1>1.15.2',
|
|
178
|
+
header,
|
|
179
|
+
flags=re.MULTILINE,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Replace kernelspec.display_name
|
|
183
|
+
header = re.sub(
|
|
184
|
+
r'^(\s*display_name:\s*).*$',
|
|
185
|
+
r'\g<1>Python 3 (ipykernel)',
|
|
186
|
+
header,
|
|
187
|
+
flags=re.MULTILINE,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Replace kernelspec.name
|
|
191
|
+
header = re.sub(
|
|
192
|
+
r'^(\s*name:\s*).*$',
|
|
193
|
+
r'\g<1>python3',
|
|
194
|
+
header,
|
|
195
|
+
flags=re.MULTILINE,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
new_header_lines = header.splitlines(keepends=True)
|
|
199
|
+
new_lines = (
|
|
200
|
+
lines[:yaml_start + 1] +
|
|
201
|
+
new_header_lines +
|
|
202
|
+
lines[yaml_end:]
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
try:
|
|
206
|
+
with open(rmd_path, "w", encoding="utf-8") as f:
|
|
207
|
+
f.writelines(new_lines)
|
|
208
|
+
except OSError:
|
|
209
|
+
# If we can't write, silently skip; script should still continue.
|
|
210
|
+
return
|
|
211
|
+
|
|
212
|
+
|
|
115
213
|
def main() -> None:
|
|
116
214
|
base_dir = find_base_dir()
|
|
117
215
|
|
|
118
|
-
# ---- Pass 1: .ipynb -> .Rmd via jupytext
|
|
216
|
+
# ---- Pass 1: .ipynb -> .Rmd via jupytext -------------------------------
|
|
119
217
|
converted_any = False
|
|
120
218
|
for path, folders, files in os.walk(base_dir, topdown=True):
|
|
121
219
|
# Skip hidden folders and notebook checkpoint caches
|
|
122
|
-
folders[:] = [
|
|
220
|
+
folders[:] = [
|
|
221
|
+
name for name in folders
|
|
222
|
+
if not is_hidden(name) and name != ".ipynb_checkpoints"
|
|
223
|
+
]
|
|
123
224
|
|
|
124
225
|
for name in files:
|
|
125
226
|
if is_hidden(name):
|
|
@@ -130,14 +231,18 @@ def main() -> None:
|
|
|
130
231
|
continue
|
|
131
232
|
|
|
132
233
|
ipynb = os.path.join(path, name)
|
|
234
|
+
|
|
235
|
+
copy_ipynb_to_docs(ipynb, base_dir)
|
|
236
|
+
|
|
133
237
|
ok = run_jupytext_ipynb_to_rmd(ipynb)
|
|
134
238
|
converted_any = converted_any or ok
|
|
135
239
|
|
|
136
240
|
if not converted_any:
|
|
137
|
-
# Not an error—maybe there are no ipynb files, or jupytext isn't
|
|
241
|
+
# Not an error—maybe there are no ipynb files, or jupytext isn't
|
|
242
|
+
# installed.
|
|
138
243
|
pass
|
|
139
244
|
|
|
140
|
-
# ---- Pass 2: .Rmd -> .py
|
|
245
|
+
# ---- Pass 2: .Rmd -> .py ----------------------------------------------
|
|
141
246
|
for path, folders, files in os.walk(base_dir, topdown=True):
|
|
142
247
|
folders[:] = [name for name in folders if not is_hidden(name)]
|
|
143
248
|
for name in files:
|
|
@@ -147,7 +252,50 @@ def main() -> None:
|
|
|
147
252
|
continue
|
|
148
253
|
|
|
149
254
|
rmd = os.path.join(path, name)
|
|
255
|
+
|
|
256
|
+
# Normalise jupytext/kernelspec metadata in YAML header
|
|
257
|
+
normalise_rmd_metadata(rmd)
|
|
258
|
+
|
|
259
|
+
# Convert .Rmd -> .py
|
|
150
260
|
convert_rmd_to_py(rmd)
|
|
151
261
|
|
|
262
|
+
|
|
263
|
+
def copy_ipynb_to_docs(ipynb_path: str, base_dir: str) -> None:
|
|
264
|
+
"""
|
|
265
|
+
Copy ipynb into <repo>/doc/notebooks, flattening any subfolders.
|
|
266
|
+
|
|
267
|
+
If two notebooks share the same filename, disambiguate by appending a
|
|
268
|
+
suffix derived from their relative directory.
|
|
269
|
+
"""
|
|
270
|
+
repo_root = os.path.dirname(base_dir)
|
|
271
|
+
dst_dir = os.path.join(repo_root, "doc", "notebooks")
|
|
272
|
+
os.makedirs(dst_dir, exist_ok=True)
|
|
273
|
+
|
|
274
|
+
name = os.path.basename(ipynb_path)
|
|
275
|
+
dst = os.path.join(dst_dir, name)
|
|
276
|
+
|
|
277
|
+
if os.path.exists(dst):
|
|
278
|
+
# Disambiguate collisions by using the relative folder path.
|
|
279
|
+
rel_dir = os.path.relpath(os.path.dirname(ipynb_path), base_dir)
|
|
280
|
+
rel_dir = "" if rel_dir == "." else rel_dir
|
|
281
|
+
suffix = re.sub(r"[^A-Za-z0-9]+", "_", rel_dir).strip("_")
|
|
282
|
+
root, ext = os.path.splitext(name)
|
|
283
|
+
new_name = f"{root}__{suffix}{ext}" if suffix else name
|
|
284
|
+
dst = os.path.join(dst_dir, new_name)
|
|
285
|
+
|
|
286
|
+
# If *still* colliding, add a numeric suffix.
|
|
287
|
+
if os.path.exists(dst):
|
|
288
|
+
i = 2
|
|
289
|
+
while True:
|
|
290
|
+
new_name = f"{root}__{suffix}__{i}{ext}" if suffix else \
|
|
291
|
+
f"{root}__{i}{ext}"
|
|
292
|
+
dst = os.path.join(dst_dir, new_name)
|
|
293
|
+
if not os.path.exists(dst):
|
|
294
|
+
break
|
|
295
|
+
i += 1
|
|
296
|
+
|
|
297
|
+
shutil.copy2(ipynb_path, dst)
|
|
298
|
+
|
|
299
|
+
|
|
152
300
|
if __name__ == "__main__":
|
|
153
|
-
main()
|
|
301
|
+
main()
|
|
@@ -24,6 +24,7 @@ extensions = [
|
|
|
24
24
|
'sphinx.ext.viewcode',
|
|
25
25
|
'numpydoc',
|
|
26
26
|
'myst_parser',
|
|
27
|
+
'nbsphinx',
|
|
27
28
|
]
|
|
28
29
|
|
|
29
30
|
exclude_patterns = ['README.md']
|
|
@@ -40,4 +41,4 @@ html_theme = 'sphinx_rtd_theme'
|
|
|
40
41
|
# The following setting specifies the order in which members are documented
|
|
41
42
|
autodoc_member_order = 'bysource'
|
|
42
43
|
|
|
43
|
-
numpydoc_show_class_members = False
|
|
44
|
+
numpydoc_show_class_members = False
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.. include:: ../README.md
|
|
2
|
+
:parser: myst_parser.sphinx_
|
|
3
|
+
|
|
4
|
+
.. toctree::
|
|
5
|
+
:caption: Modules
|
|
6
|
+
:hidden:
|
|
7
|
+
|
|
8
|
+
modules/bandmap
|
|
9
|
+
modules/mdcs
|
|
10
|
+
modules/selfenergies
|
|
11
|
+
modules/distributions
|
|
12
|
+
modules/functions
|
|
13
|
+
modules/plotting
|
|
14
|
+
modules/settings_parameters
|
|
15
|
+
modules/settings_plots
|
|
16
|
+
|
|
17
|
+
.. toctree::
|
|
18
|
+
:caption: Tutorials
|
|
19
|
+
:hidden:
|
|
20
|
+
|
|
21
|
+
notebooks/verification
|
|
22
|
+
notebooks/srtio3
|
|
23
|
+
notebooks/graphene
|
|
24
|
+
|
|
25
|
+
.. toctree::
|
|
26
|
+
:caption: More
|
|
27
|
+
:hidden:
|
|
28
|
+
|
|
29
|
+
genindex
|