ipyvasp 0.7.8__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.
Files changed (30) hide show
  1. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/PKG-INFO +15 -2
  2. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/__init__.py +2 -1
  3. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/_enplots.py +5 -7
  4. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/_lattice.py +0 -8
  5. ipyvasp-0.7.9/ipyvasp/_version.py +1 -0
  6. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/bsdos.py +10 -14
  7. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/cli.py +35 -19
  8. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/core/parser.py +8 -8
  9. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/core/plot_toolkit.py +0 -12
  10. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/core/serializer.py +16 -7
  11. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/evals_dataframe.py +23 -7
  12. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/widgets.py +22 -11
  13. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp.egg-info/PKG-INFO +15 -2
  14. ipyvasp-0.7.8/ipyvasp/_version.py +0 -1
  15. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/LICENSE +0 -0
  16. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/README.md +0 -0
  17. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/__main__.py +0 -0
  18. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/core/__init__.py +0 -0
  19. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/core/spatial_toolkit.py +0 -0
  20. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/lattice.py +0 -0
  21. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/misc.py +0 -0
  22. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/potential.py +0 -0
  23. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp/utils.py +0 -0
  24. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp.egg-info/SOURCES.txt +0 -0
  25. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp.egg-info/dependency_links.txt +0 -0
  26. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp.egg-info/entry_points.txt +0 -0
  27. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp.egg-info/requires.txt +0 -0
  28. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/ipyvasp.egg-info/top_level.txt +0 -0
  29. {ipyvasp-0.7.8 → ipyvasp-0.7.9}/setup.cfg +0 -0
  30. {ipyvasp-0.7.8 → 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.8
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
@@ -15,6 +15,7 @@ __all__ = [ # For documentation purpose
15
15
  "iplot2plt",
16
16
  "webshow",
17
17
  "list_files",
18
+ "load_results",
18
19
  "parse_text",
19
20
  "summarize",
20
21
  "OUTCAR",
@@ -29,7 +30,7 @@ from .bsdos import *
29
30
  from .potential import *
30
31
  from .evals_dataframe import *
31
32
  from .utils import *
32
- from .widgets import summarize, BandsWidget, KpathWidget, FilesWidget
33
+ from .widgets import BandsWidget, KpathWidget, FilesWidget, summarize, load_results
33
34
  from .core import plot_toolkit, spatial_toolkit
34
35
  from .core.spatial_toolkit import to_basis, to_R3, get_TM, get_bz, rotation
35
36
  from .core.plot_toolkit import (
@@ -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 is None:
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, zip)):
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, zeroline=False, **kws)
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`. You can define your own class to parse data with same attributes and methods by subclassing `ipyvasp.DataSource`.
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 # because they will be loaded anyway
400
- if len(spins) == 1 and labels: # in case projections not given, check label
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`. You can define your own class to parse data with same attributes and methods by subclassing `ipyvasp.DataSource`.
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 # because they will be loaded anyway
625
- if len(spins) == 1 and labels: # in case projections not given, check label
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
- from .core.parser import minify_vasprun
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
- for path, d in zip(abs_paths,dirs):
141
- with set_dir(path):
142
- print(color.gb(f"📁 {str(d)!r}"))
143
-
144
- if command:
145
- if os == "Windows":
146
- try:
147
- p = Popen("pwsh.exe -NoProfile -c " + command, shell=False)
148
- except:
149
- p = Popen("powershell.exe -NoProfile -c " + command, shell=False)
150
-
151
- else:
152
- p = Popen(command, shell=True) # Linux, MacOS, shell to get args
153
-
154
- p.wait()
155
- if not ignore_error and p.returncode != 0:
156
- raise RuntimeError(f"Command {command} failed in {path}. Exiting...")
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(next(self.read("<i.*NBANDS", "</i>"))).text
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 of positive integers"
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]
@@ -244,7 +244,6 @@ def adjust_axes(
244
244
  xlabel=None,
245
245
  ylabel=None,
246
246
  vlines=False,
247
- zeroline=True,
248
247
  **kwargs,
249
248
  ):
250
249
  """
@@ -256,8 +255,6 @@ def adjust_axes(
256
255
  Matplotlib axes object on which settings are applied.
257
256
  vlines : bool
258
257
  If True, draw vertical lines at points of xticks.
259
- zeroline : bool
260
- If True, drawn when `xlim` is not empty.
261
258
 
262
259
 
263
260
  Other parameters are well known matplotlib parameters.
@@ -275,15 +272,6 @@ def adjust_axes(
275
272
  ax.set_yticklabels(yticklabels if yticklabels else list(map(str, yticks)))
276
273
  if xlim:
277
274
  ax.set_xlim(xlim)
278
- if zeroline:
279
- ax.hlines(
280
- 0,
281
- min(xlim),
282
- max(xlim),
283
- color=(0, 0, 0, 0.6),
284
- linestyle="dashed",
285
- lw=0.3,
286
- )
287
275
  if ylim:
288
276
  ax.set_ylim(ylim)
289
277
 
@@ -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
- dists = [
382
- *dists,
383
- *np.linalg.norm(
384
- self.coords[tuple(idx2),] - self.coords[idx, :], axis=1
385
- ),
386
- ] # Get the second closest distance, first is itself
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["cmap"])
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["cmap"])
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["ax"]:
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["cmap"]:
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["ax"]
440
- cmap = self.current_attrs["cmap"]
441
- minmax_c = self.current_attrs["minmax_c"]
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
- .FilesWidget-Interact {
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
- .FilesWidget-Interact {max-height:90vh;width:100%;}
331
- .FilesWidget-Interact > div {overflow:auto;max-height:100%;padding:8px;}
332
- .FilesWidget-Interact > div:first-child {width:20em}
333
- .FilesWidget-Interact > div:last-child {width:calc(100% - 20em)}
334
- .FilesWidget-Interact .FW-Progess {position:absolute !important; left:50%; top:50%; transform:translate(-50%,-50%); z-index:1}
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("FilesWidget-Interact")
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 'FilesWidget-Interact' is added to the final widget to let you style it.
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 .misc import POSCAR # to avoid circular import
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.8
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.8"
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