ipyvasp 0.9.91__py2.py3-none-any.whl → 0.9.94__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/__init__.py CHANGED
@@ -31,7 +31,7 @@ from .bsdos import *
31
31
  from .potential import *
32
32
  from .evals_dataframe import *
33
33
  from .utils import *
34
- from .widgets import Files, BandsWidget, KpathWidget, summarize, load_results
34
+ from .widgets import Files, BandsWidget, KPathWidget, summarize, load_results
35
35
  from .core import plot_toolkit, spatial_toolkit
36
36
  from .core.spatial_toolkit import to_basis, to_R3, get_TM, get_bz, rotation
37
37
  from .core.plot_toolkit import (
ipyvasp/_enplots.py CHANGED
@@ -716,8 +716,9 @@ def splot_dos_lines(
716
716
  **legend_kws,
717
717
  }
718
718
  add_legend(ax, **kwargs) # Labels are picked from plot
719
-
720
- kws = dict(ylim=elim or []) if vertical else dict(xlim=elim or [])
719
+
720
+ elim = elim if elim is not None else []
721
+ kws = dict(ylim=elim) if vertical else dict(xlim=elim)
721
722
  xlabel, ylabel = "Energy (eV)", "DOS"
722
723
  if vertical:
723
724
  xlabel, ylabel = ylabel, xlabel
@@ -754,7 +755,7 @@ def _format_rgb_data(
754
755
  if data["pros"].shape[2] == 2:
755
756
  data["norms"][:, :, 2] = np.nan # Avoid wrong info here
756
757
  elif data["pros"].shape[2] == 1:
757
- data["pros"][:, :, 1:] = np.nan
758
+ data["norms"][:, :, 1:] = np.nan
758
759
 
759
760
  lws = np.sum(rgb, axis=2) # Sum of all colors
760
761
  lws = maxwidth * lws / (float(np.max(lws)) or 1) # Normalize to maxwidth
@@ -773,8 +774,7 @@ def _format_rgb_data(
773
774
  indices = range(np.shape(data["evals"])[1])
774
775
 
775
776
  # Now process data to make single data for faster plotting.
776
- txt = "Projection: [{}]</br>Value:".format(", ".join(labels))
777
- K, E, C, S, PT, OT, KT, ET = [], [], [], [], [], [], [], []
777
+ K, E, C, S, CDATA = [], [], [], [], []
778
778
  for i, b in enumerate(indices):
779
779
  K = [*K, *data["kpath"], np.nan]
780
780
  E = [*E, *data["evals"][:, i], np.nan]
@@ -784,32 +784,26 @@ def _format_rgb_data(
784
784
  "rgb(0,0,0)",
785
785
  ]
786
786
  S = [*S, *data["widths"][:, i], data["widths"][-1, i]]
787
- PT = [*PT, *[f"{txt} [{s}, {p}, {d}]" for (s, p, d) in data["norms"][:, i]], ""]
788
- OT = [*OT, *[f"Occ: {t:>7.4f}" for t in data["occs"][:, i]], ""]
789
- KT = [
790
- *KT,
791
- *[
792
- f"K<sub>{j+1}</sub>: {x:>7.3f}{y:>7.3f}{z:>7.3f}"
793
- for j, (x, y, z) in enumerate(data["kpoints"])
794
- ],
795
- "",
796
- ]
797
- ET = [
798
- *ET,
799
- *["{}".format(b + 1) for _ in data["kpath"]],
800
- "",
801
- ] # Add bands subscripts to labels.
802
-
803
- T = [
804
- f"</br>{p} </br></br>Band: {e} {o}</br>{k}"
805
- for (p, e, o, k) in zip(PT, ET, OT, KT)
806
- ]
787
+
788
+ CDATA = [*CDATA , *[
789
+ {
790
+ "nk":j+1,
791
+ **{f"k{u}":v for u,v in zip("xyz",xyz)},
792
+ "nb":b+1,
793
+ "occ":occ,
794
+ **{c:"" if np.isnan(v) else v for c,v in zip("rgb",rgb)}
795
+ }
796
+ for (j, xyz), occ, rgb in zip(
797
+ enumerate(data["kpoints"]), data["occs"][:, i],data["norms"][:, i]
798
+ )
799
+ ], {k:np.nan for k in ("nk","kx","ky","kz","nb","occ","r","g","b")}]
800
+
807
801
  return {
808
802
  "K": K,
809
803
  "E": E,
810
804
  "C": C,
811
805
  "S": S,
812
- "T": T,
806
+ "CDATA": CDATA,
813
807
  "labels": labels,
814
808
  } # K, energy, marker color, marker size, text, labels that get changed
815
809
 
@@ -830,10 +824,15 @@ def _fmt_labels(ticklabels):
830
824
  ]
831
825
  return ticklabels
832
826
 
827
+ _hover_temp = { # keep order same
828
+ "xy":"(%{x}, %{y})",
829
+ "k": "<br>K<sub>%{customdata.nk}</sub>: %{customdata.kx:.3f} %{customdata.ky:.3f} %{customdata.kz:.3f}",
830
+ "b":"Band: %{customdata.nb}, Occ: %{customdata.occ:.4f}"
831
+ }
833
832
 
834
833
  @gu._fmt_doc(_docs)
835
834
  def iplot_bands(
836
- K, E, fig=None, elim=None, kticks=None, interp=None, title=None, **kwargs
835
+ K, E, occs = None, fig=None, elim=None, kticks=None, interp=None, title=None, **kwargs
837
836
  ):
838
837
  """Plot band structure using plotly.
839
838
  {params}\n {K}\n {E}
@@ -854,18 +853,15 @@ def iplot_bands(
854
853
  data = _format_rgb_data(
855
854
  K,
856
855
  E,
857
- [E],
856
+ [E], # don't let it fail if no projections
858
857
  ["X"],
859
858
  interp,
860
- E,
859
+ E if occs is None else occs,
861
860
  np.array([K, K, K]).reshape((-1, 3)),
862
861
  maxwidth=1,
863
862
  indices=indices,
864
863
  ) # moking other arrays, we need only
865
- K, E, T = data["K"], data["E"], data["T"] # Fixed K and E as single line data
866
- T = [
867
- "Band" + t.split("Band")[1].split("Occ")[0] for t in T
868
- ] # Just Band number here
864
+ K, E = data["K"], data["E"]
869
865
 
870
866
  if fig is None:
871
867
  fig = go.Figure()
@@ -873,10 +869,12 @@ def iplot_bands(
873
869
  kwargs = {
874
870
  "mode": "markers + lines",
875
871
  "marker": dict(size=0.1),
872
+ "hovertemplate": "<br>".join(_hover_temp.values()),
873
+ "customdata": [{k:v for k,v in d.items() if not k in 'rgb'} for d in data["CDATA"]], # useless rgb data to skip
876
874
  **kwargs,
877
875
  } # marker so that it is selectable by box, otherwise it does not
878
- fig.add_trace(go.Scatter(x=K, y=E, hovertext=T, **kwargs))
879
-
876
+ fig.add_trace(go.Scatter(x=K, y=E, **kwargs))
877
+
880
878
  fig.update_layout(
881
879
  template="plotly_white",
882
880
  title=(
@@ -932,14 +930,7 @@ def iplot_rgb_lines(
932
930
  data = _format_rgb_data(
933
931
  K, E, pros, labels, interp, occs, kpoints, maxwidth=maxwidth, indices=indices
934
932
  )
935
- K, E, C, S, T, labels = (
936
- data["K"],
937
- data["E"],
938
- data["C"],
939
- data["S"],
940
- data["T"],
941
- data["labels"],
942
- )
933
+ K, E, C, S, labels = [data[key] for key in "K E C S labels".split()]
943
934
 
944
935
  if fig is None:
945
936
  fig = go.Figure()
@@ -948,13 +939,18 @@ def iplot_rgb_lines(
948
939
  kwargs.pop("marker_size", None) # Provided by S
949
940
  kwargs.update(
950
941
  {
951
- "hovertext": T,
952
942
  "marker": {
953
943
  "line_color": "rgba(0,0,0,0)",
954
944
  **kwargs.get("marker", {}),
955
945
  "color": C,
956
946
  "size": S,
957
947
  },
948
+ "hovertemplate": "<br>".join([_hover_temp["xy"],
949
+ "<br>Projection: [{}, {}, {}]".format(*labels), # clean labels instead of ''
950
+ "Value: [%{customdata.r}, %{customdata.g}, %{customdata.b}]",
951
+ _hover_temp["k"], _hover_temp["b"],
952
+ ]),
953
+ "customdata": data["CDATA"], # need for selection and hover template
958
954
  }
959
955
  ) # marker edge should be free
960
956
 
@@ -967,7 +963,7 @@ def iplot_rgb_lines(
967
963
  + ", ".join(labels)
968
964
  + "]", # Do not set autosize = False, need to be responsive in widgets boxes
969
965
  margin=go.layout.Margin(l=60, r=50, b=40, t=75, pad=0),
970
- yaxis=go.layout.YAxis(title_text="Energy (eV)", range=elim or [min(E), max(E)]),
966
+ yaxis=go.layout.YAxis(title_text="Energy (eV)",range=elim or [min(E), max(E)]),
971
967
  xaxis=go.layout.XAxis(
972
968
  ticktext=_fmt_labels(xticklabels),
973
969
  tickvals=xticks,
ipyvasp/_lattice.py CHANGED
@@ -232,7 +232,7 @@ def periodic_table(selection=None):
232
232
  return ax
233
233
 
234
234
 
235
- def write_poscar(poscar_data, outfile=None, selective_dynamics=None, overwrite=False, comment=""):
235
+ def write_poscar(poscar_data, outfile=None, selective_dynamics=None, overwrite=False, comment="", scale=None):
236
236
  """Writes POSCAR data to a file or returns string
237
237
 
238
238
  Parameters
@@ -246,6 +246,8 @@ def write_poscar(poscar_data, outfile=None, selective_dynamics=None, overwrite=F
246
246
  If file already exists, overwrite=True changes it.
247
247
  comment: str
248
248
  Add comment, previous comment will be there too.
249
+ scale: float
250
+ Scale factor for the basis vectors. Default is provided by loaded data.
249
251
 
250
252
 
251
253
  .. note::
@@ -253,7 +255,14 @@ def write_poscar(poscar_data, outfile=None, selective_dynamics=None, overwrite=F
253
255
  """
254
256
  _comment = poscar_data.metadata.comment + comment
255
257
  out_str = f"{poscar_data.SYSTEM} # " + (_comment or "Created by ipyvasp")
256
- scale = poscar_data.metadata.scale
258
+
259
+ if scale is None:
260
+ scale = poscar_data.metadata.scale
261
+ elif not isinstance(scale, (int, float)):
262
+ raise TypeError("scale must be a number or None.")
263
+ elif scale == 0:
264
+ raise ValueError("scale can not be zero.")
265
+
257
266
  out_str += "\n {:<20.14f}\n".format(scale)
258
267
  out_str += "\n".join(
259
268
  ["{:>22.16f}{:>22.16f}{:>22.16f}".format(*a) for a in poscar_data.basis / scale]
@@ -550,9 +559,9 @@ class InvokeMaterialsProject:
550
559
  else:
551
560
  print(self._cif)
552
561
 
553
- def write_poscar(self, outfile=None, overwrite=False, comment=""):
562
+ def write_poscar(self, outfile=None, overwrite=False, comment="",scale=None):
554
563
  "Use `ipyvasp.lattice.POSCAR.write` if you need extra options."
555
- write_poscar(self.export_poscar(), outfile=outfile, overwrite=overwrite, comment=comment)
564
+ write_poscar(self.export_poscar(), outfile=outfile, overwrite=overwrite, comment=comment, scale=scale)
556
565
 
557
566
  def export_poscar(self):
558
567
  "Export poscar data form cif content."
ipyvasp/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.9.91"
1
+ __version__ = "0.9.94"
ipyvasp/bsdos.py CHANGED
@@ -605,6 +605,7 @@ class Bands(_BandsDosBase):
605
605
  return iplot_bands(
606
606
  {"K": data.kpath, "indices": data.bands},
607
607
  data.evals[spin] - data.ezero,
608
+ occs = data.occs[spin],
608
609
  **kwargs,
609
610
  )
610
611
 
@@ -20,6 +20,7 @@ import PIL # For text image.
20
20
 
21
21
  import plotly.graph_objects as go
22
22
  from plotly.io._base_renderers import open_html_in_browser
23
+ from einteract import patched_plotly
23
24
 
24
25
  from .spatial_toolkit import to_R3, rotation
25
26
  from ..utils import _sig_kwargs
@@ -1011,7 +1012,7 @@ def iplot2html(fig, outfile=None, modebar=True):
1011
1012
  def iplot2widget(fig, fig_widget=None, template=None):
1012
1013
  "Converts plotly's figure to FigureWidget by copying attributes and data. If fig_widget is provided, it will update it. Adds template if provided. If fig is FigureWidget, it is just returned"
1013
1014
  if isinstance(fig, go.FigureWidget):
1014
- return fig
1015
+ return patched_plotly(fig) # add attributes selected and clicked
1015
1016
 
1016
1017
  if not isinstance(fig, go.Figure):
1017
1018
  raise ValueError("fig must be instance of plotly.graph_objects.Figure")
@@ -1035,7 +1036,7 @@ def iplot2widget(fig, fig_widget=None, template=None):
1035
1036
  for data in fig.data:
1036
1037
  fig_widget.add_trace(data)
1037
1038
 
1038
- return fig_widget
1039
+ return patched_plotly(fig_widget) # add attributes selected and clicked
1039
1040
 
1040
1041
  @_sig_kwargs(plt.imshow, ('ax','X'))
1041
1042
  def image2plt(image_or_fname, ax = None, crop = None, **kwargs):
ipyvasp/lattice.py CHANGED
@@ -342,7 +342,7 @@ class POSCAR:
342
342
  [
343
343
  f"{k}={v}"
344
344
  for k, v in zip(
345
- "abcαβγ", (*self.data.norms.round(3), *self.data.angles.round(3))
345
+ ['a','b','c','alpha','beta','gamma'], (*self.data.norms.round(3), *self.data.angles.round(3))
346
346
  )
347
347
  ]
348
348
  )
@@ -436,10 +436,10 @@ class POSCAR:
436
436
  return weas_viewer(self, **kwargs)
437
437
 
438
438
  def view_kpath(self, height='400px'):
439
- "Initialize a KpathWidget instance to view kpath for current POSCAR, and you can select others too."
440
- from .widgets import KpathWidget
439
+ "Initialize a KPathWidget instance to view kpath for current POSCAR, and you can select others too."
440
+ from .widgets import KPathWidget
441
441
 
442
- return KpathWidget([self.path,],height=height)
442
+ return KPathWidget([self.path,],height=height)
443
443
 
444
444
  @_sub_doc(plat.iplot_lattice)
445
445
  @_sig_kwargs(plat.iplot_lattice, ("poscar_data",))