ipyvasp 0.9.3__py2.py3-none-any.whl → 0.9.4__py2.py3-none-any.whl
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/_version.py +1 -1
- ipyvasp/core/plot_toolkit.py +1 -1
- ipyvasp/widgets.py +87 -60
- {ipyvasp-0.9.3.dist-info → ipyvasp-0.9.4.dist-info}/METADATA +1 -1
- {ipyvasp-0.9.3.dist-info → ipyvasp-0.9.4.dist-info}/RECORD +9 -9
- {ipyvasp-0.9.3.dist-info → ipyvasp-0.9.4.dist-info}/LICENSE +0 -0
- {ipyvasp-0.9.3.dist-info → ipyvasp-0.9.4.dist-info}/WHEEL +0 -0
- {ipyvasp-0.9.3.dist-info → ipyvasp-0.9.4.dist-info}/entry_points.txt +0 -0
- {ipyvasp-0.9.3.dist-info → ipyvasp-0.9.4.dist-info}/top_level.txt +0 -0
ipyvasp/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.9.
|
|
1
|
+
__version__ = "0.9.4"
|
ipyvasp/core/plot_toolkit.py
CHANGED
|
@@ -1019,7 +1019,7 @@ def iplot2widget(fig, fig_widget=None, template=None):
|
|
|
1019
1019
|
elif not isinstance(fig_widget, go.FigureWidget):
|
|
1020
1020
|
raise ValueError("fig_widget must be FigureWidget")
|
|
1021
1021
|
else:
|
|
1022
|
-
scene = fig_widget.layout.scene # keep scene from widget
|
|
1022
|
+
scene = fig_widget.layout.scene if fig_widget.data else fig.layout.scene# keep scene from widget, but if looks a new fig, keep from previous
|
|
1023
1023
|
|
|
1024
1024
|
fig_widget.data = [] # Clear previous data
|
|
1025
1025
|
if template is not None:
|
ipyvasp/widgets.py
CHANGED
|
@@ -159,6 +159,10 @@ class Files:
|
|
|
159
159
|
def __len__(self): return len(self._files)
|
|
160
160
|
def __bool__(self): return bool(self._files)
|
|
161
161
|
|
|
162
|
+
def map(self,func):
|
|
163
|
+
"Map files to a function!"
|
|
164
|
+
return map(func, self._files)
|
|
165
|
+
|
|
162
166
|
def with_name(self, name):
|
|
163
167
|
"Change name of all files. Only keeps existing files."
|
|
164
168
|
return self.__class__([f.with_name(name) for f in self._files])
|
|
@@ -204,19 +208,28 @@ class Files:
|
|
|
204
208
|
if old in dd.options:
|
|
205
209
|
dd.value = old
|
|
206
210
|
|
|
207
|
-
def interactive(self, func,
|
|
208
|
-
|
|
209
|
-
other_controls=None,
|
|
211
|
+
def interactive(self, func, *args,
|
|
212
|
+
free_widgets=None,
|
|
210
213
|
options={"manual": False},
|
|
211
214
|
height="400px",
|
|
215
|
+
panel_size = 25,
|
|
212
216
|
**kwargs):
|
|
213
217
|
"""
|
|
214
|
-
Interact with
|
|
218
|
+
Interact with `func(path, *args, <free_widgets,optional>, **kwargs)` that takes selected Path as first argument. Returns a widget that saves attributes of the function call such as .f, .args, .kwargs.
|
|
219
|
+
`args` are widgets to be modified by func, such as plotly's FigureWidget.
|
|
220
|
+
Note that `free_widgets` can also be passed to function but does not run function when changed.
|
|
221
|
+
|
|
215
222
|
See docs of self.interact for more details on the parameters. kwargs are passed to ipywidgets.interactive to create controls.
|
|
216
223
|
|
|
224
|
+
>>> import plotly.graph_objects as go
|
|
225
|
+
>>> import ipyvasp as ipv
|
|
226
|
+
>>> fs = ipv.Files('.','**/POSCAR')
|
|
227
|
+
>>> def plot(path, fig, bl,plot_cell,eqv_sites):
|
|
228
|
+
>>> ipv.iplot2widget(ipv.POSCAR(path).iplot_lattice(
|
|
229
|
+
>>> bond_length=bl,plot_cell=plot_cell,eqv_sites=eqv_sites
|
|
230
|
+
>>> ),fig_widget=fig) # it keeps updating same view
|
|
231
|
+
>>> out = fs.interactive(plot, go.FigureWidget(),bl=(0,6,2),plot_cell=True, eqv_sites=True)
|
|
217
232
|
|
|
218
|
-
>>> fls = Files()
|
|
219
|
-
>>> out = fls.interactive(lambda path: print(path.read_text())) # prints contents of selected file on output widget
|
|
220
233
|
>>> out.f # function
|
|
221
234
|
>>> out.args # arguments
|
|
222
235
|
>>> out.kwargs # keyword arguments
|
|
@@ -228,13 +241,16 @@ class Files:
|
|
|
228
241
|
info = ipw.HTML().add_class("fprogess")
|
|
229
242
|
dd = Dropdown(description='File', options=self._files)
|
|
230
243
|
|
|
231
|
-
def interact_func(fname, **
|
|
244
|
+
def interact_func(fname, **kws):
|
|
232
245
|
if fname: # This would be None if no file is selected
|
|
233
246
|
info.value = _progress_svg
|
|
234
247
|
try:
|
|
235
248
|
start = time()
|
|
236
|
-
|
|
237
|
-
|
|
249
|
+
if 'free_widgets' in func.__code__.co_varnames:
|
|
250
|
+
kws['free_widgets'] = free_widgets # user allowed to pass this
|
|
251
|
+
names = ', '.join(func.__code__.co_varnames)
|
|
252
|
+
print(f"Running {func.__name__}({names})")
|
|
253
|
+
func(Path(fname).absolute(), *args, **kws) # Have Path object absolue if user changes directory
|
|
238
254
|
print(f"Finished in {time() - start:.3f} seconds.")
|
|
239
255
|
finally:
|
|
240
256
|
info.value = ""
|
|
@@ -253,38 +269,45 @@ class Files:
|
|
|
253
269
|
) # make output scrollable and avoid overflow
|
|
254
270
|
|
|
255
271
|
others = out.children[1:-1] # exclude files_dd and Output widget
|
|
256
|
-
|
|
257
|
-
|
|
272
|
+
if not isinstance(panel_size,int):
|
|
273
|
+
raise TypeError('panel_size should be integer in units of em')
|
|
274
|
+
|
|
275
|
+
_style = f"""<style>
|
|
276
|
+
.files-interact {{
|
|
258
277
|
--jp-widgets-inline-label-width: 4em;
|
|
259
|
-
--jp-widgets-inline-width:
|
|
278
|
+
--jp-widgets-inline-width: {panel_size-2}em;
|
|
260
279
|
--jp-widgets-inline-width-short: 9em;
|
|
261
|
-
}
|
|
262
|
-
.files-interact {max-height:
|
|
263
|
-
.files-interact > div {overflow:auto;max-height:100%;padding:8px;}
|
|
264
|
-
.files-interact > div:first-child {width:
|
|
265
|
-
.files-interact > div:last-child {width:calc(100% -
|
|
266
|
-
.files-interact .fprogess {position:absolute !important; left:50%; top:50%; transform:translate(-50%,-50%); z-index:1}
|
|
280
|
+
}}
|
|
281
|
+
.files-interact {{max-height:{height};width:100%;}}
|
|
282
|
+
.files-interact > div {{overflow:auto;max-height:100%;padding:8px;}}
|
|
283
|
+
.files-interact > div:first-child {{width:{panel_size}em}}
|
|
284
|
+
.files-interact > div:last-child {{width:calc(100% - {panel_size}em)}}
|
|
285
|
+
.files-interact .fprogess {{position:absolute !important; left:50%; top:50%; transform:translate(-50%,-50%); z-index:1}}
|
|
267
286
|
</style>"""
|
|
268
287
|
if others:
|
|
269
288
|
others = [ipw.HTML(f"<hr/>{_style}"), *others]
|
|
270
289
|
else:
|
|
271
290
|
others = [ipw.HTML(_style)]
|
|
272
291
|
|
|
273
|
-
if
|
|
274
|
-
raise TypeError("
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
292
|
+
if free_widgets and not isinstance(free_widgets, (list, tuple)):
|
|
293
|
+
raise TypeError("free_widgets must be a list or tuple of widgets.")
|
|
294
|
+
|
|
295
|
+
for w in args:
|
|
296
|
+
if not isinstance(w,ipw.DOMWidget):
|
|
297
|
+
raise TypeError(f'args can only contain a DOMWidget instance, got {type(w)}')
|
|
298
|
+
|
|
299
|
+
if args:
|
|
280
300
|
output.layout.max_height = "200px"
|
|
301
|
+
output.layout.min_height = "8em" # fisrt fix
|
|
281
302
|
out_collapser = Checkbox(description="Hide output widget", value=False)
|
|
282
303
|
|
|
283
304
|
def toggle_output(change):
|
|
284
305
|
if out_collapser.value:
|
|
285
306
|
output.layout.height = "0px" # dont use display = 'none' as it will clear widgets and wont show again
|
|
307
|
+
output.layout.min_height = "0px"
|
|
286
308
|
else:
|
|
287
309
|
output.layout.height = "auto"
|
|
310
|
+
output.layout.min_height = "8em"
|
|
288
311
|
|
|
289
312
|
out_collapser.observe(toggle_output, "value")
|
|
290
313
|
others.append(out_collapser)
|
|
@@ -293,7 +316,7 @@ class Files:
|
|
|
293
316
|
others = [
|
|
294
317
|
*others,
|
|
295
318
|
ipw.HTML(f"<hr/>"),
|
|
296
|
-
*(
|
|
319
|
+
*(free_widgets or []),
|
|
297
320
|
] # add hr to separate other controls
|
|
298
321
|
|
|
299
322
|
out.children = [
|
|
@@ -303,7 +326,7 @@ class Files:
|
|
|
303
326
|
children=[dd, VBox(others)]
|
|
304
327
|
), # other widgets in box to make scrollable independent file selection
|
|
305
328
|
VBox(
|
|
306
|
-
children=[
|
|
329
|
+
children=[output, *args, info]
|
|
307
330
|
), # output in box to make scrollable,
|
|
308
331
|
],
|
|
309
332
|
layout=Layout(height=height, max_height=height),
|
|
@@ -317,61 +340,64 @@ class Files:
|
|
|
317
340
|
box.children = box._interact.children
|
|
318
341
|
box._files._dd = box._interact._dd
|
|
319
342
|
|
|
320
|
-
def interact(self,
|
|
321
|
-
|
|
322
|
-
other_controls=None,
|
|
343
|
+
def interact(self, *args,
|
|
344
|
+
free_widgets=None,
|
|
323
345
|
options={"manual": False},
|
|
324
346
|
height="400px",
|
|
347
|
+
panel_size=25,
|
|
325
348
|
**kwargs,
|
|
326
349
|
):
|
|
327
|
-
"""Interact with a
|
|
350
|
+
"""Interact with a `func(path, *args, <free_widgets,optional>, **kwargs)`. `path` is passed from selected File.
|
|
328
351
|
A CSS class 'files-interact' is added to the final widget to let you style it.
|
|
329
352
|
|
|
330
353
|
Parameters
|
|
331
354
|
----------
|
|
332
|
-
|
|
355
|
+
args :
|
|
333
356
|
Any displayable widget can be passed. These are placed below the output widget of interact.
|
|
334
|
-
For example you can add plotly's FigureWidget that updates based on the selection,
|
|
335
|
-
|
|
336
|
-
Default is None. If not None, these are assumed to be ipywidgets and are placed below the widgets created by kwargs.
|
|
357
|
+
For example you can add plotly's FigureWidget that updates based on the selection, these are passed to function after path.
|
|
358
|
+
free_widgets : list/tuple
|
|
359
|
+
Default is None. If not None, these are assumed to be ipywidgets and are placed below the widgets created by kwargs.
|
|
360
|
+
These can be passed to the decorated function if added as arguemnt there like `func(..., free_widgets)`, but don't trigger execution.
|
|
337
361
|
options : dict
|
|
338
|
-
Default is {'
|
|
362
|
+
Default is {'manual':False}. If True, the decorated function is not called automatically, and you have to call it manually on button press. You can pass button name as 'manual_name' in options.
|
|
339
363
|
height : str
|
|
340
364
|
Default is '90vh'. height of the final widget. This is important to avoid very long widgets.
|
|
365
|
+
panel_size: int
|
|
366
|
+
Side panel size in units of em.
|
|
341
367
|
|
|
342
368
|
kwargs are passed to ipywidgets.interactive and decorated function. Resulting widgets are placed below the file selection widget.
|
|
343
|
-
`
|
|
369
|
+
Widgets in `args` can be controlled by `free_widgets` externally if defined gloablly or inside function if you pass `free_widgets` as argument like `func(..., free_widgets)`.
|
|
344
370
|
|
|
345
371
|
The decorated function can be called later separately as well, and has .args and .kwargs attributes to access the latest arguments
|
|
346
372
|
and .result method to access latest. For a function `f`, `f.result` is same as `f(*f.args, **f.kwargs)`.
|
|
347
373
|
|
|
348
|
-
|
|
349
|
-
>>>
|
|
350
|
-
>>>
|
|
351
|
-
>>>
|
|
352
|
-
>>>
|
|
353
|
-
>>>
|
|
354
|
-
>>>
|
|
374
|
+
>>> import plotly.graph_objects as go
|
|
375
|
+
>>> import ipyvasp as ipv
|
|
376
|
+
>>> fs = ipv.Files('.','**/POSCAR')
|
|
377
|
+
>>> @fs.interact(go.FigureWidget(),bl=(0,6,2),plot_cell=True, eqv_sites=True)
|
|
378
|
+
>>> def plot(path, fig, bl,plot_cell,eqv_sites):
|
|
379
|
+
>>> ipv.iplot2widget(ipv.POSCAR(path).iplot_lattice(
|
|
380
|
+
>>> bond_length=bl,plot_cell=plot_cell,eqv_sites=eqv_sites
|
|
381
|
+
>>> ),fig_widget=fig) # it keeps updating same view
|
|
355
382
|
|
|
356
383
|
.. note::
|
|
357
384
|
Use self.interactive to get a widget that stores the argements and can be called later in a notebook cell.
|
|
358
385
|
"""
|
|
359
386
|
|
|
360
387
|
def inner(func):
|
|
361
|
-
display(self.interactive(func,
|
|
362
|
-
|
|
363
|
-
other_controls=other_controls,
|
|
388
|
+
display(self.interactive(func, *args,
|
|
389
|
+
free_widgets=free_widgets,
|
|
364
390
|
options=options,
|
|
365
391
|
height=height,
|
|
392
|
+
panel_size=panel_size,
|
|
366
393
|
**kwargs)
|
|
367
394
|
)
|
|
368
395
|
return func
|
|
369
396
|
return inner
|
|
370
397
|
|
|
371
|
-
|
|
372
398
|
def kpath_widget(self, height='400px'):
|
|
373
399
|
"Get KpathWidget instance with these files."
|
|
374
|
-
return KpathWidget(files = self.
|
|
400
|
+
return KpathWidget(files = self.with_name('POSCAR'), height = height)
|
|
375
401
|
|
|
376
402
|
def bands_widget(self, height='450px'):
|
|
377
403
|
"Get BandsWidget instance with these files."
|
|
@@ -596,10 +622,8 @@ class BandsWidget(VBox):
|
|
|
596
622
|
self._select_dict = {} # store selection data
|
|
597
623
|
self._kwargs = {}
|
|
598
624
|
|
|
599
|
-
Files(files)._attributed_interactive(self,
|
|
600
|
-
|
|
601
|
-
other_widgets=[self._fig],
|
|
602
|
-
other_controls=[
|
|
625
|
+
Files(files)._attributed_interactive(self, self._load_data, self._fig,
|
|
626
|
+
free_widgets=[
|
|
603
627
|
self._tsd,
|
|
604
628
|
self._brange,
|
|
605
629
|
self._ktcicks,
|
|
@@ -626,7 +650,8 @@ class BandsWidget(VBox):
|
|
|
626
650
|
"Use slef.files.update(...) to keep state of widget preserved."
|
|
627
651
|
return self._files
|
|
628
652
|
|
|
629
|
-
def _load_data(self, path): # Automatically redirectes to output widget
|
|
653
|
+
def _load_data(self, path, fig): # Automatically redirectes to output widget
|
|
654
|
+
if not hasattr(self, '_interact'): return # First time not availablebu
|
|
630
655
|
self._interact.output_widget.clear_output(wait=True) # Why need again?
|
|
631
656
|
with self._interact.output_widget:
|
|
632
657
|
self._bands = (
|
|
@@ -684,6 +709,7 @@ class BandsWidget(VBox):
|
|
|
684
709
|
return self._select_dict.get("data", None)
|
|
685
710
|
|
|
686
711
|
def _update_graph(self, btn):
|
|
712
|
+
if not hasattr(self, '_interact'): return # First time not available
|
|
687
713
|
self._interact.output_widget.clear_output(wait=True) # Why need again?
|
|
688
714
|
with self._interact.output_widget:
|
|
689
715
|
hsk = [
|
|
@@ -815,7 +841,7 @@ class KpathWidget(VBox):
|
|
|
815
841
|
self._clicktime = None
|
|
816
842
|
self._kpoints = {}
|
|
817
843
|
|
|
818
|
-
|
|
844
|
+
free_widgets = [
|
|
819
845
|
HBox([self._add, self._del, self._tsb], layout=Layout(min_height="24px")),
|
|
820
846
|
ipw.HTML(
|
|
821
847
|
"<style>.KpathWidget .widget-select-multiple { min-height: 180px; }\n .widget-select-multiple > select {height: 100%;}</style>"
|
|
@@ -826,7 +852,7 @@ class KpathWidget(VBox):
|
|
|
826
852
|
]
|
|
827
853
|
|
|
828
854
|
Files(files)._attributed_interactive(self,
|
|
829
|
-
self._update_fig,
|
|
855
|
+
self._update_fig, self._fig, free_widgets=free_widgets, height=height
|
|
830
856
|
)
|
|
831
857
|
|
|
832
858
|
self._tsb.on_click(self._update_theme)
|
|
@@ -850,7 +876,8 @@ class KpathWidget(VBox):
|
|
|
850
876
|
"POSCAR class associated to current selection."
|
|
851
877
|
return self._poscar
|
|
852
878
|
|
|
853
|
-
def _update_fig(self, path):
|
|
879
|
+
def _update_fig(self, path, fig):
|
|
880
|
+
if not hasattr(self, '_interact'): return # First time not available
|
|
854
881
|
from .lattice import POSCAR # to avoid circular import
|
|
855
882
|
|
|
856
883
|
with self._interact.output_widget:
|
|
@@ -859,10 +886,10 @@ class KpathWidget(VBox):
|
|
|
859
886
|
)
|
|
860
887
|
self._poscar = POSCAR(path)
|
|
861
888
|
ptk.iplot2widget(
|
|
862
|
-
self._poscar.iplot_bz(fill=False, color="red"),
|
|
889
|
+
self._poscar.iplot_bz(fill=False, color="red"), fig, template
|
|
863
890
|
)
|
|
864
|
-
with
|
|
865
|
-
|
|
891
|
+
with fig.batch_animate():
|
|
892
|
+
fig.add_trace(
|
|
866
893
|
go.Scatter3d(
|
|
867
894
|
x=[],
|
|
868
895
|
y=[],
|
|
@@ -2,7 +2,7 @@ ipyvasp/__init__.py,sha256=rlorju9arMtHw1QRYPljday-PyZWJdSCxg4lw3g6t0Q,1409
|
|
|
2
2
|
ipyvasp/__main__.py,sha256=eJV1TZSiT8mC_VqAeksNnBI2I8mKMiPkEIlwikbtOjI,216
|
|
3
3
|
ipyvasp/_enplots.py,sha256=D38paN8zqZgluNAwmCwcocd7-_h_T0HTGolI1eBkDes,37484
|
|
4
4
|
ipyvasp/_lattice.py,sha256=GxG0C4lwVGvBYIy3jwR1kahWR7L6kJlqjIiQGgESjcM,104135
|
|
5
|
-
ipyvasp/_version.py,sha256=
|
|
5
|
+
ipyvasp/_version.py,sha256=iPcoATf7BiWjSu-KocRdM5zFTR4wx4ktCHlGGpvdc1M,23
|
|
6
6
|
ipyvasp/bsdos.py,sha256=1rG68S-dLEYveIWGK7r8CRa7Qqlqno0l1ncfo2ocihk,30424
|
|
7
7
|
ipyvasp/cli.py,sha256=aWFEVhNmnW8eSOp5uh95JaDwLQ9K9nlCQcbnOSuhWgw,6844
|
|
8
8
|
ipyvasp/evals_dataframe.py,sha256=-sqxK7LPV6sYDO_XXmZ80FznOaXTkVdbqJKKvTUtMak,20637
|
|
@@ -11,15 +11,15 @@ ipyvasp/misc.py,sha256=SZJ_ePUR2-HEKYTEpDHVRVE7zpIQVTCjiuw0BCC9UTU,2349
|
|
|
11
11
|
ipyvasp/potential.py,sha256=tzA73c5lkp6ahLSJchMrU043-QWaOV0nIOUA7VMmfKQ,11408
|
|
12
12
|
ipyvasp/surface.py,sha256=MjE5oB0wW6Pca_C-xu8rN6OMH7lUEeNPNyM7Kz_Im-8,23766
|
|
13
13
|
ipyvasp/utils.py,sha256=rVyD5SkO_Y7ok5W-fJeQys9X8pLLbDK7VOgbAbcE4WU,14227
|
|
14
|
-
ipyvasp/widgets.py,sha256=
|
|
14
|
+
ipyvasp/widgets.py,sha256=iWkH7PbzZFPUZ2LrSRLafTPxXfiRfNFG5Ddaq3Wd_BU,45655
|
|
15
15
|
ipyvasp/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
ipyvasp/core/parser.py,sha256=C3CaZsJbPME_ttYlYy4DXeOdL7dnkXs-cHRwFZL6bio,38058
|
|
17
|
-
ipyvasp/core/plot_toolkit.py,sha256=
|
|
17
|
+
ipyvasp/core/plot_toolkit.py,sha256=3RoPsND5gPssBSfS5H4TjoZ2Qz7B97vpxeKadc2cRRs,36046
|
|
18
18
|
ipyvasp/core/serializer.py,sha256=XpqnfVGsUXiN2CuVRPyqsSVouxRBO-UH6AnsHnPYvZY,36729
|
|
19
19
|
ipyvasp/core/spatial_toolkit.py,sha256=8DBYTiBFWJ7OBKuvOPw7UoEVCyNjJhSW0OcudjYZvAw,14748
|
|
20
|
-
ipyvasp-0.9.
|
|
21
|
-
ipyvasp-0.9.
|
|
22
|
-
ipyvasp-0.9.
|
|
23
|
-
ipyvasp-0.9.
|
|
24
|
-
ipyvasp-0.9.
|
|
25
|
-
ipyvasp-0.9.
|
|
20
|
+
ipyvasp-0.9.4.dist-info/LICENSE,sha256=F3SO5RiAZOMfmMGf1KOuk2g_c4ObvuBJhd9iBLDgXoQ,1263
|
|
21
|
+
ipyvasp-0.9.4.dist-info/METADATA,sha256=PvaEna3-zdOpEQhg5_iD9ECRt7N4nqI5aPluv6-VJ9M,2420
|
|
22
|
+
ipyvasp-0.9.4.dist-info/WHEEL,sha256=iYlv5fX357PQyRT2o6tw1bN-YcKFFHKqB_LwHO5wP-g,110
|
|
23
|
+
ipyvasp-0.9.4.dist-info/entry_points.txt,sha256=C7m0Sjmr14wFjflCkWXLzr5N6-cQj8uJC9n82mUtzt8,44
|
|
24
|
+
ipyvasp-0.9.4.dist-info/top_level.txt,sha256=ftziWlMWu_1VpDP1sRTFrkfBnWxAi393HYDVu4wRhUk,8
|
|
25
|
+
ipyvasp-0.9.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|