ipyvasp 0.7.7__tar.gz → 0.7.9__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.
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/PKG-INFO +15 -2
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/__init__.py +5 -1
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/_enplots.py +5 -7
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/_lattice.py +0 -8
- ipyvasp-0.7.9/ipyvasp/_version.py +1 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/bsdos.py +10 -14
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/cli.py +35 -19
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/core/parser.py +8 -8
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/core/plot_toolkit.py +33 -12
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/core/serializer.py +16 -7
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/evals_dataframe.py +23 -7
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/widgets.py +22 -11
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp.egg-info/PKG-INFO +15 -2
- ipyvasp-0.7.7/ipyvasp/_version.py +0 -1
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/LICENSE +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/README.md +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/__main__.py +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/core/__init__.py +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/core/spatial_toolkit.py +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/lattice.py +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/misc.py +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/potential.py +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp/utils.py +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp.egg-info/SOURCES.txt +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp.egg-info/dependency_links.txt +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp.egg-info/entry_points.txt +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp.egg-info/requires.txt +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/ipyvasp.egg-info/top_level.txt +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/setup.cfg +0 -0
- {ipyvasp-0.7.7 → ipyvasp-0.7.9}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ipyvasp
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.9
|
|
4
4
|
Summary: A processing tool for VASP DFT input/output processing in Jupyter Notebook.
|
|
5
5
|
Home-page: https://github.com/massgh/ipyvasp
|
|
6
6
|
Author: Abdul Saboor
|
|
@@ -13,8 +13,21 @@ Classifier: Programming Language :: Python :: 3
|
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Requires-Python: >=3.8
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
|
-
Provides-Extra: extra
|
|
17
16
|
License-File: LICENSE
|
|
17
|
+
Requires-Dist: matplotlib==3.7.0
|
|
18
|
+
Requires-Dist: numpy==1.23.2
|
|
19
|
+
Requires-Dist: scipy==1.9.1
|
|
20
|
+
Requires-Dist: ipywidgets>=8.0.4
|
|
21
|
+
Requires-Dist: pillow>=9.3.0
|
|
22
|
+
Requires-Dist: pandas==1.4.4
|
|
23
|
+
Requires-Dist: plotly==5.14.1
|
|
24
|
+
Requires-Dist: requests==2.28.1
|
|
25
|
+
Requires-Dist: typer==0.9.0
|
|
26
|
+
Provides-Extra: extra
|
|
27
|
+
Requires-Dist: jupyterlab>=3.5.2; extra == "extra"
|
|
28
|
+
Requires-Dist: ipython>=8.7; extra == "extra"
|
|
29
|
+
Requires-Dist: ase>=3.22.1; extra == "extra"
|
|
30
|
+
Requires-Dist: nglview>=3.0.4; extra == "extra"
|
|
18
31
|
|
|
19
32
|
|
|
20
33
|
# ipyvasp
|
|
@@ -11,8 +11,11 @@ __all__ = [ # For documentation purpose
|
|
|
11
11
|
"plt2html",
|
|
12
12
|
"iplot2html",
|
|
13
13
|
"iplot2widget",
|
|
14
|
+
"image2plt",
|
|
15
|
+
"iplot2plt",
|
|
14
16
|
"webshow",
|
|
15
17
|
"list_files",
|
|
18
|
+
"load_results",
|
|
16
19
|
"parse_text",
|
|
17
20
|
"summarize",
|
|
18
21
|
"OUTCAR",
|
|
@@ -27,7 +30,7 @@ from .bsdos import *
|
|
|
27
30
|
from .potential import *
|
|
28
31
|
from .evals_dataframe import *
|
|
29
32
|
from .utils import *
|
|
30
|
-
from .widgets import
|
|
33
|
+
from .widgets import BandsWidget, KpathWidget, FilesWidget, summarize, load_results
|
|
31
34
|
from .core import plot_toolkit, spatial_toolkit
|
|
32
35
|
from .core.spatial_toolkit import to_basis, to_R3, get_TM, get_bz, rotation
|
|
33
36
|
from .core.plot_toolkit import (
|
|
@@ -37,6 +40,7 @@ from .core.plot_toolkit import (
|
|
|
37
40
|
plt2html,
|
|
38
41
|
iplot2html,
|
|
39
42
|
iplot2widget,
|
|
43
|
+
image2plt,
|
|
40
44
|
webshow,
|
|
41
45
|
)
|
|
42
46
|
|
|
@@ -51,17 +51,16 @@ def _validate_data(K, E, elim, kticks, interp):
|
|
|
51
51
|
if np.shape(E)[0] != len(K):
|
|
52
52
|
raise ValueError("Length of first dimension of E must be equal to length of K.")
|
|
53
53
|
|
|
54
|
-
if kticks
|
|
54
|
+
if isinstance(kticks, zip):
|
|
55
|
+
kticks = list(kticks) # otherwise it will be empty after first use
|
|
56
|
+
elif kticks is None:
|
|
55
57
|
kticks = []
|
|
56
58
|
|
|
57
|
-
if not isinstance(kticks, (list, tuple
|
|
59
|
+
if not isinstance(kticks, (list, tuple)):
|
|
58
60
|
raise ValueError(
|
|
59
61
|
"kticks must be a list, tuple or zip consisting of (index, label) pairs. index must be an int or tuple of (i, i+1) to join broken path."
|
|
60
62
|
)
|
|
61
63
|
|
|
62
|
-
if isinstance(kticks, zip):
|
|
63
|
-
kticks = list(kticks) # otherwise it will be empty after first use
|
|
64
|
-
|
|
65
64
|
for k, v in kticks:
|
|
66
65
|
if not isinstance(k, (np.integer, int)):
|
|
67
66
|
raise ValueError("First item of pairs in kticks must be int")
|
|
@@ -159,7 +158,6 @@ def splot_bands(K, E, ax=None, elim=None, kticks=None, interp=None, **kwargs):
|
|
|
159
158
|
|
|
160
159
|
lines = ax.plot(K, E, **kwargs)
|
|
161
160
|
_ = [line.set_label(None) for line in lines[1:]]
|
|
162
|
-
|
|
163
161
|
adjust_axes(
|
|
164
162
|
ax=ax,
|
|
165
163
|
ylabel="Energy (eV)",
|
|
@@ -723,7 +721,7 @@ def splot_dos_lines(
|
|
|
723
721
|
xlabel, ylabel = "Energy (eV)", "DOS"
|
|
724
722
|
if vertical:
|
|
725
723
|
xlabel, ylabel = ylabel, xlabel
|
|
726
|
-
adjust_axes(ax, xlabel=xlabel, ylabel=ylabel,
|
|
724
|
+
adjust_axes(ax, xlabel=xlabel, ylabel=ylabel, **kws)
|
|
727
725
|
return ax
|
|
728
726
|
|
|
729
727
|
|
|
@@ -2502,11 +2502,6 @@ def transpose_poscar(poscar_data, axes=[1, 0, 2]):
|
|
|
2502
2502
|
|
|
2503
2503
|
def add_atoms(poscar_data, name, positions):
|
|
2504
2504
|
"Add atoms with a `name` to a POSCAR at given `positions` in fractional coordinates."
|
|
2505
|
-
if name in poscar_data.types.keys():
|
|
2506
|
-
raise Exception(
|
|
2507
|
-
f"{name!r} already exists in POSCAR. Cannot add duplicate atoms."
|
|
2508
|
-
)
|
|
2509
|
-
|
|
2510
2505
|
positions = np.array(positions)
|
|
2511
2506
|
if (not np.ndim(positions) == 2) or (not positions.shape[1] == 3):
|
|
2512
2507
|
raise ValueError("`positions` must be a 2D array of shape (n,3)")
|
|
@@ -2544,9 +2539,6 @@ def _validate_func(func, nargs, return_type):
|
|
|
2544
2539
|
|
|
2545
2540
|
def replace_atoms(poscar_data, func, name):
|
|
2546
2541
|
"""Replace atoms satisfying a `func(i,x,y,z) -> bool` with a new `name`"""
|
|
2547
|
-
if name in poscar_data.types.keys():
|
|
2548
|
-
return poscar_data # no change
|
|
2549
|
-
|
|
2550
2542
|
_validate_func(func, 4, bool)
|
|
2551
2543
|
data = poscar_data.to_dict() # Copy data to avoid modifying original
|
|
2552
2544
|
mask = _masked_data(poscar_data, func)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.9"
|
|
@@ -236,7 +236,8 @@ class Bands(_BandsDosBase):
|
|
|
236
236
|
|
|
237
237
|
Parameters
|
|
238
238
|
----------
|
|
239
|
-
source : instance of `ipyvasp.DataSource` such as `ipyvasp.Vasprun` or `ipyvasp.Vaspout`.
|
|
239
|
+
source : instance of `ipyvasp.DataSource` such as `ipyvasp.Vasprun` or `ipyvasp.Vaspout`.
|
|
240
|
+
You can define your own class to parse data with same attributes and methods by subclassing `ipyvasp.DataSource`.
|
|
240
241
|
"""
|
|
241
242
|
|
|
242
243
|
def __init__(self, source):
|
|
@@ -396,12 +397,8 @@ class Bands(_BandsDosBase):
|
|
|
396
397
|
) # picks available spins if uspins is None
|
|
397
398
|
|
|
398
399
|
if not spins:
|
|
399
|
-
spins = data.spins
|
|
400
|
-
|
|
401
|
-
spins = [
|
|
402
|
-
spins[0] for _ in labels
|
|
403
|
-
] # only one spin channel is available, so use it for all projections
|
|
404
|
-
|
|
400
|
+
spins = [data.spins[0] for _ in labels]
|
|
401
|
+
|
|
405
402
|
output = {
|
|
406
403
|
"kpath": kpts.kpath,
|
|
407
404
|
"kpoints": kpts.kpoints,
|
|
@@ -495,6 +492,8 @@ class Bands(_BandsDosBase):
|
|
|
495
492
|
kwargs["kticks"] = (
|
|
496
493
|
kwargs.get("kticks", None) or self.get_kticks()
|
|
497
494
|
) # User can provide kticks, but if not, use default
|
|
495
|
+
if isinstance(kwargs["kticks"], zip):
|
|
496
|
+
kwargs["kticks"] = list(kwargs["kticks"]) # otherwise it will consumed below
|
|
498
497
|
|
|
499
498
|
# Need to fetch data for gap and plot later
|
|
500
499
|
self._breaks = [
|
|
@@ -597,7 +596,8 @@ class DOS(_BandsDosBase):
|
|
|
597
596
|
|
|
598
597
|
Parameters
|
|
599
598
|
----------
|
|
600
|
-
source : instance of `ipyvasp.DataSource` such as `ipyvasp.Vasprun` or `ipyvasp.Vaspout`.
|
|
599
|
+
source : instance of `ipyvasp.DataSource` such as `ipyvasp.Vasprun` or `ipyvasp.Vaspout`.
|
|
600
|
+
You can define your own class to parse data with same attributes and methods by subclassing `ipyvasp.DataSource`.
|
|
601
601
|
"""
|
|
602
602
|
|
|
603
603
|
def __init__(self, source):
|
|
@@ -621,12 +621,8 @@ class DOS(_BandsDosBase):
|
|
|
621
621
|
)
|
|
622
622
|
|
|
623
623
|
if not spins:
|
|
624
|
-
spins = dos.spins
|
|
625
|
-
|
|
626
|
-
spins = [
|
|
627
|
-
spins[0] for _ in labels
|
|
628
|
-
] # only one spin channel is available, so use it for all projections
|
|
629
|
-
|
|
624
|
+
spins = [dos.spins[0] for _ in labels]
|
|
625
|
+
|
|
630
626
|
out = dos.to_dict()
|
|
631
627
|
out["labels"] = labels
|
|
632
628
|
|
|
@@ -5,7 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
import typer
|
|
6
6
|
from typing_extensions import Annotated
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
from .lattice import POSCAR, get_kpath
|
|
10
10
|
from .utils import _sig_kwargs
|
|
11
11
|
|
|
@@ -61,6 +61,8 @@ def _get_kpath(kpoints: str, n: int = 5, poscar: str = "POSCAR", **kwargs):
|
|
|
61
61
|
@vasprun_app.command("minify")
|
|
62
62
|
def minify(files: List[Path]):
|
|
63
63
|
"Remove projected data from vasprun.xml file to reduce file size."
|
|
64
|
+
from .core.parser import minify_vasprun
|
|
65
|
+
|
|
64
66
|
for file in files:
|
|
65
67
|
minify_vasprun(file)
|
|
66
68
|
|
|
@@ -109,12 +111,15 @@ def _get_E0(files: List[Path]):
|
|
|
109
111
|
@app.command("set-dir")
|
|
110
112
|
def _set_dir(
|
|
111
113
|
paths: List[Path], command: Annotated[str, typer.Option("-c", "--command")] = "",
|
|
112
|
-
ignore_error: Annotated[bool, typer.Option("-i", "--ignore-error")] = False
|
|
114
|
+
ignore_error: Annotated[bool, typer.Option("-i", "--ignore-error")] = False,
|
|
115
|
+
time_interval: Annotated[int, typer.Option("-t",'--time-interval')] = 0
|
|
113
116
|
):
|
|
114
117
|
"""Set multiple directories like a for loop to execute a shell command within each of them.
|
|
115
118
|
It will raise an error if the command fails in any of the directories.
|
|
116
119
|
To ignore the error and keep running in other directiories in sequence, use -i/--ignore-error.
|
|
117
120
|
It will raise the shell errors but python will go through all the directories.
|
|
121
|
+
|
|
122
|
+
To keep repeating a command after some time interval, use -t/--time-interval (seconds). Only works for a command
|
|
118
123
|
|
|
119
124
|
Examples:
|
|
120
125
|
|
|
@@ -124,6 +129,7 @@ def _set_dir(
|
|
|
124
129
|
"""
|
|
125
130
|
from platform import system
|
|
126
131
|
from subprocess import Popen
|
|
132
|
+
from time import sleep
|
|
127
133
|
from .utils import set_dir, color
|
|
128
134
|
|
|
129
135
|
os = system() # operating system
|
|
@@ -137,20 +143,30 @@ def _set_dir(
|
|
|
137
143
|
|
|
138
144
|
abs_paths = [f.absolute() for f in dirs] # absolute path is must but after filtering
|
|
139
145
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
146
|
+
def run(abs_paths, dirs, command, ignore_error):
|
|
147
|
+
for path, d in zip(abs_paths,dirs):
|
|
148
|
+
with set_dir(path):
|
|
149
|
+
print(color.gb(f"📁 {str(d)!r}"))
|
|
150
|
+
|
|
151
|
+
if command:
|
|
152
|
+
if os == "Windows":
|
|
153
|
+
try:
|
|
154
|
+
p = Popen("pwsh.exe -NoProfile -c " + command, shell=False)
|
|
155
|
+
except:
|
|
156
|
+
p = Popen("powershell.exe -NoProfile -c " + command, shell=False)
|
|
157
|
+
|
|
158
|
+
else:
|
|
159
|
+
p = Popen(command, shell=True) # Linux, MacOS, shell to get args
|
|
160
|
+
|
|
161
|
+
p.wait()
|
|
162
|
+
if not ignore_error and p.returncode != 0:
|
|
163
|
+
raise RuntimeError(f"Command {command} failed in {path}. Exiting...\n" +
|
|
164
|
+
"Use -i or --ignore-error switch to suppress error and continue in other directories silently."
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
if time_interval > 0 and command: # repeat only if command given
|
|
168
|
+
while True: # keep going until interrupted
|
|
169
|
+
run(abs_paths, dirs, command, ignore_error)
|
|
170
|
+
sleep(time_interval)
|
|
171
|
+
else:
|
|
172
|
+
run(abs_paths, dirs, command, ignore_error)
|
|
@@ -192,8 +192,8 @@ class Vasprun(DataSource):
|
|
|
192
192
|
).iter("v")
|
|
193
193
|
]
|
|
194
194
|
)
|
|
195
|
-
info_dict["NBANDS"] = int(
|
|
196
|
-
ET.fromstring(
|
|
195
|
+
info_dict["NBANDS"] = int( # Bad initializations, read last one
|
|
196
|
+
ET.fromstring(list(self.read("<i.*NBANDS", "</i>"))[-1]).text
|
|
197
197
|
)
|
|
198
198
|
info_dict["NELECTS"] = int(
|
|
199
199
|
float(ET.fromstring(next(self.read("<i.*NELECT", "</i>"))).text)
|
|
@@ -504,6 +504,11 @@ class Vasprun(DataSource):
|
|
|
504
504
|
0
|
|
505
505
|
] # bring closer points first by sorting and take closest ones
|
|
506
506
|
|
|
507
|
+
if ezero is not None:
|
|
508
|
+
if not isinstance(ezero, (int, np.integer, float)):
|
|
509
|
+
raise TypeError("ezero should be a float or integer")
|
|
510
|
+
zero = ezero
|
|
511
|
+
|
|
507
512
|
if bands:
|
|
508
513
|
if not isinstance(bands, (list, tuple, range)):
|
|
509
514
|
raise TypeError(
|
|
@@ -512,7 +517,7 @@ class Vasprun(DataSource):
|
|
|
512
517
|
for b in bands:
|
|
513
518
|
if (not isinstance(b, (int, np.integer))) and (b < 0):
|
|
514
519
|
raise TypeError(
|
|
515
|
-
"bands should be a tuple/list/range of
|
|
520
|
+
"bands should be a tuple/list/range of positive integers"
|
|
516
521
|
)
|
|
517
522
|
_bands = list(bands)
|
|
518
523
|
evals = evals[:, :, _bands]
|
|
@@ -522,11 +527,6 @@ class Vasprun(DataSource):
|
|
|
522
527
|
if (not isinstance(elim, (list, tuple))) and (len(elim) != 2):
|
|
523
528
|
raise TypeError("elim should be a tuple of length 2")
|
|
524
529
|
|
|
525
|
-
if ezero is not None:
|
|
526
|
-
if not isinstance(ezero, (int, np.integer, float)):
|
|
527
|
-
raise TypeError("ezero should be a float or integer")
|
|
528
|
-
zero = ezero
|
|
529
|
-
|
|
530
530
|
idx_max = np.max(np.where(evals - zero <= np.max(elim))[2]) + 1
|
|
531
531
|
idx_min = np.min(np.where(evals - zero >= np.min(elim))[2])
|
|
532
532
|
evals = evals[:, :, idx_min:idx_max]
|
|
@@ -22,6 +22,7 @@ import plotly.graph_objects as go
|
|
|
22
22
|
from plotly.io._base_renderers import open_html_in_browser
|
|
23
23
|
|
|
24
24
|
from .spatial_toolkit import to_R3, rotation
|
|
25
|
+
from ..utils import _sig_kwargs
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
def global_matplotlib_settings(rcParams={}, display_format="svg"):
|
|
@@ -243,7 +244,6 @@ def adjust_axes(
|
|
|
243
244
|
xlabel=None,
|
|
244
245
|
ylabel=None,
|
|
245
246
|
vlines=False,
|
|
246
|
-
zeroline=True,
|
|
247
247
|
**kwargs,
|
|
248
248
|
):
|
|
249
249
|
"""
|
|
@@ -255,8 +255,6 @@ def adjust_axes(
|
|
|
255
255
|
Matplotlib axes object on which settings are applied.
|
|
256
256
|
vlines : bool
|
|
257
257
|
If True, draw vertical lines at points of xticks.
|
|
258
|
-
zeroline : bool
|
|
259
|
-
If True, drawn when `xlim` is not empty.
|
|
260
258
|
|
|
261
259
|
|
|
262
260
|
Other parameters are well known matplotlib parameters.
|
|
@@ -274,15 +272,6 @@ def adjust_axes(
|
|
|
274
272
|
ax.set_yticklabels(yticklabels if yticklabels else list(map(str, yticks)))
|
|
275
273
|
if xlim:
|
|
276
274
|
ax.set_xlim(xlim)
|
|
277
|
-
if zeroline:
|
|
278
|
-
ax.hlines(
|
|
279
|
-
0,
|
|
280
|
-
min(xlim),
|
|
281
|
-
max(xlim),
|
|
282
|
-
color=(0, 0, 0, 0.6),
|
|
283
|
-
linestyle="dashed",
|
|
284
|
-
lw=0.3,
|
|
285
|
-
)
|
|
286
275
|
if ylim:
|
|
287
276
|
ax.set_ylim(ylim)
|
|
288
277
|
|
|
@@ -1040,3 +1029,35 @@ def iplot2widget(fig, fig_widget=None, template=None):
|
|
|
1040
1029
|
fig_widget.add_trace(data)
|
|
1041
1030
|
|
|
1042
1031
|
return fig_widget
|
|
1032
|
+
|
|
1033
|
+
@_sig_kwargs(plt.imshow, ('ax','X'))
|
|
1034
|
+
def image2plt(image_or_fname, ax = None, crop = None, **kwargs):
|
|
1035
|
+
"""Plot PIL image, numpy array or image file on given matploltib axes.
|
|
1036
|
+
`crop` is list or tuple of [x0,y0,x1,y1] in [0,1] interval.
|
|
1037
|
+
kwargs are passed to plt.imshow."""
|
|
1038
|
+
if ax is None:
|
|
1039
|
+
ax = get_axes()
|
|
1040
|
+
if isinstance(image_or_fname, str):
|
|
1041
|
+
im_array = plt.imread(image_or_fname)
|
|
1042
|
+
else:
|
|
1043
|
+
try:
|
|
1044
|
+
im_array = np.asarray(image_or_fname) # PIL image to array
|
|
1045
|
+
except:
|
|
1046
|
+
raise ValueError("Not a valid PIL image or filename.")
|
|
1047
|
+
|
|
1048
|
+
if crop:
|
|
1049
|
+
if not isinstance(crop, (list, tuple)):
|
|
1050
|
+
raise ValueError("crop must be list or tuple of [x0,y0,x1,y1]")
|
|
1051
|
+
if max(crop) > 1 and min(crop) < 0:
|
|
1052
|
+
raise ValueError("crop values must be in [0,1] interval.")
|
|
1053
|
+
if len(crop) != 4:
|
|
1054
|
+
raise ValueError("crop must be list or tuple of [x0,y0,x1,y1]")
|
|
1055
|
+
(x0,y0),(x1,y1) = [int(im_array.shape[0]*v) for v in crop[:2]], [int(im_array.shape[1]*v) for v in crop[2:]]
|
|
1056
|
+
|
|
1057
|
+
im_array = im_array[y0:y1+1,x0:x1+1] # image origin is top left, so y0 is first
|
|
1058
|
+
|
|
1059
|
+
# Some kwargs are very important to be default. User can override them.
|
|
1060
|
+
aspect = im_array.shape[0]/im_array.shape[1]
|
|
1061
|
+
kwargs = {'interpolation':'none', 'extent': [0,1,0,1], 'aspect': aspect, **kwargs}
|
|
1062
|
+
ax.imshow(im_array, **kwargs)
|
|
1063
|
+
return ax
|
|
@@ -350,7 +350,7 @@ class PoscarData(Dict2Data):
|
|
|
350
350
|
|
|
351
351
|
def get_distance(self, atom1, atom2):
|
|
352
352
|
"""
|
|
353
|
-
Returns the distance between two atoms.
|
|
353
|
+
Returns the mimimum distance between two atoms taking translations into account.
|
|
354
354
|
Provide atom1 and atom2 as strings such as get_distance('Ga', 'As') to get a mimimal distance between two types
|
|
355
355
|
or as a dict with a single key as get_distance({'Ga':0}, {'As':0}) to get distance between specific atoms,
|
|
356
356
|
or mixed as get_distance('Ga', {'As':0}) to get minimum distance between a type and a specific atom.
|
|
@@ -378,16 +378,25 @@ class PoscarData(Dict2Data):
|
|
|
378
378
|
|
|
379
379
|
dists = []
|
|
380
380
|
for idx in idx1:
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
381
|
+
for trans in set(product([-1,0,1],[-1,0,1],[-1,0,1])):
|
|
382
|
+
C = self.to_cartesian(self.positions[idx] + trans) # translate around to get lowest distance
|
|
383
|
+
|
|
384
|
+
dists = [
|
|
385
|
+
*dists,
|
|
386
|
+
*np.linalg.norm(self.coords[tuple(idx2),] - C, axis=1),
|
|
387
|
+
] # Get the second closest distance, first is itself
|
|
387
388
|
|
|
388
389
|
dists = np.array(dists)
|
|
389
390
|
dists = dists[dists > 0] # Remove distance with itself
|
|
390
391
|
return np.min(dists)
|
|
392
|
+
|
|
393
|
+
def to_fractional(self, coords):
|
|
394
|
+
"Converts cartesian coordinates to fractional coordinates in the basis of cell."
|
|
395
|
+
return to_basis(self.basis, coords)
|
|
396
|
+
|
|
397
|
+
def to_cartesian(self, points):
|
|
398
|
+
"Converts fractional coordinates in the basis of cell to cartesian coordinates."
|
|
399
|
+
return to_R3(self.basis, points)
|
|
391
400
|
|
|
392
401
|
def get_selective_dynamics(self, func):
|
|
393
402
|
"""
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
__all__ = ["visualize_df","EvalsDataFrame"]
|
|
2
2
|
|
|
3
|
+
from contextlib import suppress
|
|
4
|
+
|
|
3
5
|
import numpy as np
|
|
4
6
|
import pandas as pd
|
|
5
7
|
from scipy.interpolate import griddata
|
|
6
8
|
import matplotlib.pyplot as plt
|
|
7
9
|
|
|
10
|
+
|
|
8
11
|
# Inside packages import
|
|
9
12
|
from .core.parser import DataSource
|
|
10
13
|
from .core import plot_toolkit as ptk
|
|
@@ -112,6 +115,13 @@ class EvalsDataFrame(pd.DataFrame):
|
|
|
112
115
|
raise ValueError("source must be a single DataSource object!")
|
|
113
116
|
else:
|
|
114
117
|
super().__init__(*source, **kwargs) # For other opertaions on dataframe
|
|
118
|
+
|
|
119
|
+
with suppress(BaseException): # Does not work first time
|
|
120
|
+
# Add currently available path after each operation
|
|
121
|
+
if 'kpath' in self.columns:
|
|
122
|
+
self['kpath'] = self._kpath()
|
|
123
|
+
else:
|
|
124
|
+
self.insert(7,'kpath', self._kpath()) # after kpt
|
|
115
125
|
|
|
116
126
|
@property
|
|
117
127
|
def _constructor(self):
|
|
@@ -304,7 +314,7 @@ class EvalsDataFrame(pd.DataFrame):
|
|
|
304
314
|
kxyz, kij = self._collect_kxyz(*args[:2], shift=shift)
|
|
305
315
|
ax = ax or ptk.get_axes()
|
|
306
316
|
minmax_c = [0, 1]
|
|
307
|
-
cmap = kwargs.get("cmap", self.current_attrs
|
|
317
|
+
cmap = kwargs.get("cmap", self.current_attrs.get("cmap",None))
|
|
308
318
|
|
|
309
319
|
if arrows:
|
|
310
320
|
arrows_data = self._collect_arrows_data(arrows)
|
|
@@ -382,7 +392,7 @@ class EvalsDataFrame(pd.DataFrame):
|
|
|
382
392
|
kxyz, kij = self._collect_kxyz(*args[:3], shift=shift)
|
|
383
393
|
ax = ax or ptk.get_axes(axes_3d=True)
|
|
384
394
|
minmax_c = [0, 1]
|
|
385
|
-
cmap = kwargs.get("cmap", self.current_attrs
|
|
395
|
+
cmap = kwargs.get("cmap", self.current_attrs.get("cmap",None))
|
|
386
396
|
|
|
387
397
|
if arrows:
|
|
388
398
|
arrows_data = self._collect_arrows_data(arrows)
|
|
@@ -429,16 +439,16 @@ class EvalsDataFrame(pd.DataFrame):
|
|
|
429
439
|
|
|
430
440
|
def colorbar(self, cax=None, nticks=6, digits=2, **kwargs):
|
|
431
441
|
"Add colobar to most recent plot. kwargs are passed to ipyvasp.splots.add_colorbar"
|
|
432
|
-
if not self.current_attrs
|
|
442
|
+
if not self.current_attrs.get("ax",None):
|
|
433
443
|
raise ValueError(
|
|
434
444
|
"No plot has been made yet by using `splot, splot3d` or already consumed by `colorbar`"
|
|
435
445
|
)
|
|
436
|
-
if not self.current_attrs
|
|
446
|
+
if not self.current_attrs.get("cmap",None):
|
|
437
447
|
raise ValueError("No Mappable for colorbar found!")
|
|
438
448
|
|
|
439
|
-
ax = self.current_attrs
|
|
440
|
-
cmap = self.current_attrs
|
|
441
|
-
minmax_c = self.current_attrs
|
|
449
|
+
ax = self.current_attrs.get("ax",None)
|
|
450
|
+
cmap = self.current_attrs.get("cmap",None)
|
|
451
|
+
minmax_c = self.current_attrs.get("minmax_c",[0,1])
|
|
442
452
|
self.current_attrs["ax"] = None # Reset
|
|
443
453
|
self.current_attrs["cmap"] = None # Reset
|
|
444
454
|
if ax.name == "3d":
|
|
@@ -463,6 +473,12 @@ class EvalsDataFrame(pd.DataFrame):
|
|
|
463
473
|
"Returns cartesian coodinates of kpoints as numpy array"
|
|
464
474
|
return self["x y z".split()].to_numpy()
|
|
465
475
|
|
|
476
|
+
def _kpath(self):
|
|
477
|
+
kindex = sorted(np.unique(self["kpt"]))
|
|
478
|
+
coords = self.coords[kindex]
|
|
479
|
+
kpath = np.cumsum([0, *np.linalg.norm(coords[1:] - coords[:-1], axis=1)])
|
|
480
|
+
kpath = kpath / kpath[-1] # Normalized
|
|
481
|
+
return kpath[self["kpt"]] # full array in current order
|
|
466
482
|
|
|
467
483
|
# from ipywidgets import interact
|
|
468
484
|
# import matplotlib.pyplot as plt
|
|
@@ -322,16 +322,16 @@ class FilesWidget(VBox):
|
|
|
322
322
|
|
|
323
323
|
others = out.children[1:-1] # exclude files_dd and Output widget
|
|
324
324
|
_style = """<style>
|
|
325
|
-
.
|
|
325
|
+
.FW-Interact {
|
|
326
326
|
--jp-widgets-inline-label-width: 4em;
|
|
327
327
|
--jp-widgets-inline-width: 18em;
|
|
328
328
|
--jp-widgets-inline-width-short: 9em;
|
|
329
329
|
}
|
|
330
|
-
.
|
|
331
|
-
.
|
|
332
|
-
.
|
|
333
|
-
.
|
|
334
|
-
.
|
|
330
|
+
.FW-Interact {max-height:90vh;width:100%;}
|
|
331
|
+
.FW-Interact > div {overflow:auto;max-height:100%;padding:8px;}
|
|
332
|
+
.FW-Interact > div:first-child {width:20em}
|
|
333
|
+
.FW-Interact > div:last-child {width:calc(100% - 20em)}
|
|
334
|
+
.FW-Interact .FW-Progess {position:absolute !important; left:50%; top:50%; transform:translate(-50%,-50%); z-index:1}
|
|
335
335
|
</style>"""
|
|
336
336
|
if others:
|
|
337
337
|
others = [ipw.HTML(f"<hr/>{_style}"), *others]
|
|
@@ -375,7 +375,7 @@ class FilesWidget(VBox):
|
|
|
375
375
|
), # output in box to make scrollable,
|
|
376
376
|
],
|
|
377
377
|
layout=Layout(height=height, max_height=height),
|
|
378
|
-
).add_class("
|
|
378
|
+
).add_class("FW-Interact")
|
|
379
379
|
] # important for every widget separately
|
|
380
380
|
return out
|
|
381
381
|
|
|
@@ -388,7 +388,7 @@ class FilesWidget(VBox):
|
|
|
388
388
|
**kwargs,
|
|
389
389
|
):
|
|
390
390
|
"""Interact with a function that takes a selected Path as first argument.
|
|
391
|
-
A CSS class '
|
|
391
|
+
A CSS class 'FW-Interact' is added to the final widget to let you style it.
|
|
392
392
|
|
|
393
393
|
Parameters
|
|
394
394
|
----------
|
|
@@ -498,7 +498,10 @@ class _PropPicker(VBox):
|
|
|
498
498
|
orbs.update({k: [idx] for idx, k in enumerate(sorbs[16:], start=16)})
|
|
499
499
|
|
|
500
500
|
self._orbs = orbs
|
|
501
|
+
old_orb = self._widgets["orbs"].value
|
|
501
502
|
self._widgets["orbs"].options = list(orbs.keys())
|
|
503
|
+
if old_orb in self._widgets["orbs"].options:
|
|
504
|
+
self._widgets["orbs"].value = old_orb
|
|
502
505
|
|
|
503
506
|
atoms = {"-": [], "All": range(system_summary.NIONS)}
|
|
504
507
|
for key, tp in system_summary.types.to_dict().items():
|
|
@@ -507,7 +510,10 @@ class _PropPicker(VBox):
|
|
|
507
510
|
atoms[f"{key}{n}"] = [v]
|
|
508
511
|
|
|
509
512
|
self._atoms = atoms
|
|
513
|
+
old_atom = self._widgets["atoms"].value
|
|
510
514
|
self._widgets["atoms"].options = list(atoms.keys())
|
|
515
|
+
if old_atom in self._widgets["atoms"].options:
|
|
516
|
+
self._widgets["atoms"].value = old_atom
|
|
511
517
|
|
|
512
518
|
def update(self, system_summary):
|
|
513
519
|
return self._process(system_summary)
|
|
@@ -720,6 +726,11 @@ class BandsWidget(VBox):
|
|
|
720
726
|
)
|
|
721
727
|
self._click_save_data(None) # Load into view
|
|
722
728
|
self._warn_update(None)
|
|
729
|
+
|
|
730
|
+
@property
|
|
731
|
+
def source(self):
|
|
732
|
+
"Returns data source object such as Vasprun or Vaspout."
|
|
733
|
+
return self.bands.source
|
|
723
734
|
|
|
724
735
|
@property
|
|
725
736
|
def bands(self):
|
|
@@ -758,14 +769,14 @@ class BandsWidget(VBox):
|
|
|
758
769
|
self._kwargs = {"projections": self._ppicks.projections, **self._kwargs}
|
|
759
770
|
fig = self.bands.iplot_rgb_lines(**self._kwargs, name="Up")
|
|
760
771
|
if self.bands.source.summary.ISPIN == 2:
|
|
761
|
-
self.bands.iplot_rgb_lines(**self._kwargs, name="Down", fig=fig)
|
|
772
|
+
self.bands.iplot_rgb_lines(**self._kwargs, spin=1, name="Down", fig=fig)
|
|
762
773
|
|
|
763
774
|
self.iplot = partial(self.bands.iplot_rgb_lines, **self._kwargs)
|
|
764
775
|
self.splot = partial(self.bands.splot_rgb_lines, **self._kwargs)
|
|
765
776
|
else:
|
|
766
777
|
fig = self.bands.iplot_bands(**self._kwargs, name="Up")
|
|
767
778
|
if self.bands.source.summary.ISPIN == 2:
|
|
768
|
-
self.bands.iplot_bands(**self._kwargs, name="Down", fig=fig)
|
|
779
|
+
self.bands.iplot_bands(**self._kwargs, spin=1, name="Down", fig=fig)
|
|
769
780
|
|
|
770
781
|
self.iplot = partial(self.bands.iplot_bands, **self._kwargs)
|
|
771
782
|
self.splot = partial(self.bands.splot_bands, **self._kwargs)
|
|
@@ -906,7 +917,7 @@ class KpathWidget(VBox):
|
|
|
906
917
|
return self._poscar
|
|
907
918
|
|
|
908
919
|
def _update_fig(self, path):
|
|
909
|
-
from .
|
|
920
|
+
from .lattice import POSCAR # to avoid circular import
|
|
910
921
|
|
|
911
922
|
with self._interact.output_widget:
|
|
912
923
|
template = (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ipyvasp
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.9
|
|
4
4
|
Summary: A processing tool for VASP DFT input/output processing in Jupyter Notebook.
|
|
5
5
|
Home-page: https://github.com/massgh/ipyvasp
|
|
6
6
|
Author: Abdul Saboor
|
|
@@ -13,8 +13,21 @@ Classifier: Programming Language :: Python :: 3
|
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Requires-Python: >=3.8
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
|
-
Provides-Extra: extra
|
|
17
16
|
License-File: LICENSE
|
|
17
|
+
Requires-Dist: matplotlib==3.7.0
|
|
18
|
+
Requires-Dist: numpy==1.23.2
|
|
19
|
+
Requires-Dist: scipy==1.9.1
|
|
20
|
+
Requires-Dist: ipywidgets>=8.0.4
|
|
21
|
+
Requires-Dist: pillow>=9.3.0
|
|
22
|
+
Requires-Dist: pandas==1.4.4
|
|
23
|
+
Requires-Dist: plotly==5.14.1
|
|
24
|
+
Requires-Dist: requests==2.28.1
|
|
25
|
+
Requires-Dist: typer==0.9.0
|
|
26
|
+
Provides-Extra: extra
|
|
27
|
+
Requires-Dist: jupyterlab>=3.5.2; extra == "extra"
|
|
28
|
+
Requires-Dist: ipython>=8.7; extra == "extra"
|
|
29
|
+
Requires-Dist: ase>=3.22.1; extra == "extra"
|
|
30
|
+
Requires-Dist: nglview>=3.0.4; extra == "extra"
|
|
18
31
|
|
|
19
32
|
|
|
20
33
|
# ipyvasp
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.7.7"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|