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 CHANGED
@@ -1 +1 @@
1
- __version__ = "0.9.3"
1
+ __version__ = "0.9.4"
@@ -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
- other_widgets=None,
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 a function that takes selected Path as first argument. Returns a widget that saves attributes of the function call such as .f, .args, .kwargs.
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, **kwargs):
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
- print(f"Running {func.__name__}({fname!r}, {kwargs})")
237
- func(Path(fname).absolute(), **kwargs) # Have Path object absolue if user changes directory
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
- _style = """<style>
257
- .files-interact {
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: 18em;
278
+ --jp-widgets-inline-width: {panel_size-2}em;
260
279
  --jp-widgets-inline-width-short: 9em;
261
- }
262
- .files-interact {max-height:90vh;width:100%;}
263
- .files-interact > div {overflow:auto;max-height:100%;padding:8px;}
264
- .files-interact > div:first-child {width:20em}
265
- .files-interact > div:last-child {width:calc(100% - 20em)}
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 other_controls and not isinstance(other_controls, (list, tuple)):
274
- raise TypeError("other_controls must be a list or tuple of widgets.")
275
-
276
- if other_widgets and not isinstance(other_widgets, (list, tuple)):
277
- raise TypeError("other_widgets must be a list or tuple of widgets.")
278
-
279
- if other_widgets:
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
- *(other_controls or []),
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=[Box([output]), *(other_widgets or []), info]
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
- other_widgets=None,
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 function that takes a selected Path as first argument.
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
- other_widgets : list/tuple
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, but is not part of the function, so it is displayed only once.
335
- other_controls : list/tuple
336
- Default is None. If not None, these are assumed to be ipywidgets and are placed below the widgets created by kwargs. These are not passed to the decorated function.
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 {'manua':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.
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
- `other_widgets` can be controlled by `other_controls` externally. For example, you can add a button to update a plotly's FigureWidget.
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
- >>> fls = Files()
350
- >>> @fls.interact(x = False)
351
- >>> def f(path,x):
352
- >>> print('path:',path)
353
- >>> print('Path Type: ', type(path))
354
- >>> print('x: ',x)
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
- other_widgets=other_widgets,
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._files, height = height)
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
- self._load_data,
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
- other_controls = [
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, [self._fig], other_controls, height=height
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"), self._fig, template
889
+ self._poscar.iplot_bz(fill=False, color="red"), fig, template
863
890
  )
864
- with self._fig.batch_animate():
865
- self._fig.add_trace(
891
+ with fig.batch_animate():
892
+ fig.add_trace(
866
893
  go.Scatter3d(
867
894
  x=[],
868
895
  y=[],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ipyvasp
3
- Version: 0.9.3
3
+ Version: 0.9.4
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
@@ -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=5uBZ3sUaocnyIWuJeW9M94Z77vA1kKmwKxiblrnbKlc,23
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=mP1tqYO-tPk4Xq_fgkGPGN2AfRf9V-al3Yl7vzKp5lU,43758
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=8t5svyWbOm-PS7ZvIptnK6F46kp6uwoGNdohPv5dQKA,35962
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.3.dist-info/LICENSE,sha256=F3SO5RiAZOMfmMGf1KOuk2g_c4ObvuBJhd9iBLDgXoQ,1263
21
- ipyvasp-0.9.3.dist-info/METADATA,sha256=v2jvMQ--zKh-b0GAF5XywZDMKJi8x3hUAMMvKGdfiD0,2420
22
- ipyvasp-0.9.3.dist-info/WHEEL,sha256=iYlv5fX357PQyRT2o6tw1bN-YcKFFHKqB_LwHO5wP-g,110
23
- ipyvasp-0.9.3.dist-info/entry_points.txt,sha256=C7m0Sjmr14wFjflCkWXLzr5N6-cQj8uJC9n82mUtzt8,44
24
- ipyvasp-0.9.3.dist-info/top_level.txt,sha256=ftziWlMWu_1VpDP1sRTFrkfBnWxAi393HYDVu4wRhUk,8
25
- ipyvasp-0.9.3.dist-info/RECORD,,
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,,