#!/usr/bin/env python # coding: utf-8 # # Plotting Density of States with
Plotly and Pymatgen # ### About the Author: # # This notebook was contributed by plotly user [Germain Salvato-Vallverdu](https://plotly.com/~gvallverdu). You can follow him on [GitHub](https://github.com/gVallverdu?tab=activity) or visit [his webpage](http://gvallver.perso.univ-pau.fr/). # ### Introduction # This notebook will go over an example for plotting the density of states and the band diagram of Silicon using python with [pymatgen](http://pymatgen.org/) and [plotly](https://plotly.com/) packages. # # * [pymatgen](http://pymatgen.org/) : (Python Materials Genomics) A robust, open-source Python library for materials analysis. # * [plotly](https://plotly.com/) : A platform for publishing beautiful, interactive graphs from Python to the web. # Firstly, we import numpy and pymatgen tools # In[1]: import numpy as np from pymatgen.io.vaspio.vasp_output import Vasprun # read vasprun.xml output file of VASP from pymatgen.electronic_structure.core import Spin # Next, we import plotly tools # In[2]: import plotly.plotly as pltly # plotting functions import plotly.tools as tls # plotly tools import plotly.graph_objs as go # plot and configuration tools : Scatter, Line, Layout # # Band Diagram and Denisty of States of Silicon # ### 1) Plot the density of states # First, read projected density of states (DOS) from a VASP calculation on ``"./DOS/vasprun.xml"`` file using pymatgen. # In[3]: dosrun = Vasprun("./DOS/vasprun.xml") spd_dos = dosrun.complete_dos.get_spd_dos() # Set up the scatter plots for the total DOS and the contribution of 3s and 3p atomic orbital to the total DOS. # In[4]: # total DOS trace_tdos = go.Scatter( x=dosrun.tdos.densities[Spin.up], y=dosrun.tdos.energies - dosrun.efermi, mode="lines", name="total DOS", line=go.Line(color="#444444"), fill="tozeroy" ) # 3s contribution to the total DOS trace_3s = go.Scatter( x=spd_dos["S"].densities[Spin.up], y=dosrun.tdos.energies - dosrun.efermi, mode="lines", name="3s", line=go.Line(color="red") ) # 3p contribution to the total DOS trace_3p = go.Scatter( x=spd_dos["P"].densities[Spin.up], y=dosrun.tdos.energies - dosrun.efermi, mode="lines", name="3p", line=go.Line(color="green") ) dosdata = go.Data([trace_tdos, trace_3s, trace_3p]) # Customize axes and general aspect of the plot. # In[5]: dosxaxis = go.XAxis( title="Density of states", showgrid=True, showline=True, range=[.01, 3], mirror="ticks", ticks="inside", linewidth=2, tickwidth=2 ) dosyaxis = go.YAxis( title="$E - E_f \quad / \quad \\text{eV}$", showgrid=True, showline=True, ticks="inside", mirror='ticks', linewidth=2, tickwidth=2, zerolinewidth=2 ) doslayout = go.Layout( title="Density of states of Silicon", xaxis=dosxaxis, yaxis=dosyaxis ) # In[6]: dosfig = go.Figure(data=dosdata, layout=doslayout) plot_url = pltly.plot(dosfig, filename="DOS_Si", auto_open=False) tls.embed(plot_url) # ### 2) Plot the band diagram # First, read bands from a VASP calculation on ``"./Bandes/vasprun.xml"`` file using pymatgen. # In[7]: run = Vasprun("./Bandes/vasprun.xml", parse_projected_eigen = True) bands = run.get_band_structure("./Bandes/KPOINTS", line_mode=True, efermi=dosrun.efermi) # Look for the boundaries of the band diagram in order to set up y axes range. # In[8]: emin = 1e100 emax = -1e100 for spin in bands.bands.keys(): for band in range(bands.nb_bands): emin = min(emin, min(bands.bands[spin][band])) emax = max(emax, max(bands.bands[spin][band])) emin = emin - bands.efermi - 1 emax = emax - bands.efermi + 1 # Each band is plotted using a scatter plot. # In[20]: kptslist = [k for k in range(len(bands.kpoints))] bandTraces = list() for band in range(bands.nb_bands): bandTraces.append( go.Scatter( x=kptslist, y=[e - bands.efermi for e in bands.bands[Spin.up][band]], mode="lines", line=go.Line(color="#666666"), showlegend=False ) ) # Add vertical lines at each high symmetry k-points and a label at the bottom. # In[21]: labels = [r"$L$", r"$\Gamma$", r"$X$", r"$U,K$", r"$\Gamma$"] step = len(bands.kpoints) / (len(labels) - 1) # vertical lines vlines = list() for i, label in enumerate(labels): vlines.append( go.Scatter( x=[i * step, i * step], y=[emin, emax], mode="lines", line=go.Line(color="#111111", width=1), showlegend=False ) ) # Labels of highsymetry k-points are added as Annotation object annotations = list() for i, label in enumerate(labels): annotations.append( go.Annotation( x=i * step, y=emin, xref="x1", yref="y1", text=label, xanchor="center", yanchor="top", showarrow=False ) ) # Customize axes and general aspect of the plot. # In[22]: bandxaxis = go.XAxis( title="k-points", range=[0, len(bands.kpoints)], showgrid=True, showline=True, ticks="", showticklabels=False, mirror=True, linewidth=2 ) bandyaxis = go.YAxis( title="$E - E_f \quad / \quad \\text{eV}$", range=[emin, emax], showgrid=True, showline=True, zeroline=True, mirror="ticks", ticks="inside", linewidth=2, tickwidth=2, zerolinewidth=2 ) bandlayout = go.Layout( title="Bands diagram of Silicon", xaxis=bandxaxis, yaxis=bandyaxis, annotations=go.Annotations(annotations) ) # In[24]: bandfig = go.Figure(data=bandTraces + vlines, layout=bandlayout) plot_url = pltly.plot(bandfig, filename="Bands_Si", auto_open=False) tls.embed(plot_url) # ### 3) Use subplots to plot DOS and bands together # We will now make a figure with both the band diagram and the density of states using the ``make_subplots`` facility. First, we set up a figure with two columns, one row. At the end, the two plots will share y axis. # In[25]: dosbandfig = tls.make_subplots(rows=1, cols=2, shared_yaxes=True) # We use the previously defined traces for the band and the densities of state and add them to the figure object. # # * The bands are plotted on the left subplot (1, 1) # * The densities of states are plotted on the right subplot (1, 2) # In[26]: # add the bands for btrace in bandTraces: dosbandfig.append_trace(btrace, 1, 1) # add vlines for specific k-points for vline in vlines: dosbandfig.append_trace(vline, 1, 1) # add the densities dosbandfig.append_trace(trace_tdos, 1, 2) dosbandfig.append_trace(trace_3s, 1, 2) dosbandfig.append_trace(trace_3p, 1, 2) # Customize axes and general aspect of the plot using previously defined axis and layout options. The ``"domain"`` of each subplot is also define. # In[27]: dosbandfig["layout"].update( go.Layout( title="Bands diagram and density of states of Silicon", xaxis1=bandxaxis, yaxis1=bandyaxis, xaxis2=dosxaxis, annotations=go.Annotations(annotations) ) ) # adjust size of subplots dosbandfig["layout"]["xaxis1"]["domain"] = [0., 0.7] dosbandfig["layout"]["xaxis2"]["domain"] = [0.702, 1.] # add some specific options dosbandfig["layout"]["yaxis1"]["mirror"] = "allticks" dosbandfig["layout"]["xaxis2"]["mirror"] = "allticks" # In[28]: plot_url = pltly.plot(dosbandfig, filename="DOS_bands_Si", auto_open=False) tls.embed(plot_url) # ### 4) Atomic orbital contributions in bands using a color scale # As previously done for the density of states, the contribution of 3s and 3p atomic orbital may be highlighted using a color scale. The main idea, from [this example](https://github.com/vossjo/ase-espresso/wiki/Band-structure-calculation-example), is to normalize atomic orbital contributions and build the RGB code of the color from these contributions. # # Thus, we first compute atomic orbital normalized contributions from projected bands : # In[29]: # extract projected bands name = "Si" pbands = bands.get_projections_on_elts_and_orbitals({name: ["s", "p", "d"]}) # compute contributions contrib = np.zeros((bands.nb_bands, len(bands.kpoints), 3)) for band in range(bands.nb_bands): for k in range(len(bands.kpoints)): sc = pbands[Spin.up][band][k][name]["s"]**2 pc = pbands[Spin.up][band][k][name]["p"]**2 dc = pbands[Spin.up][band][k][name]["d"]**2 tot = sc + pc + dc if tot != 0.0: contrib[band, k, 0] = sc / tot contrib[band, k, 1] = pc / tot contrib[band, k, 2] = dc / tot # Now for each band, for each couple of consecutive points, we plot a line plot with a specific color, defined from the atomic orbital contributions to the current band. # In[30]: colorBands = list() # will contain the list of all lines nkpts = len(bands.kpoints) for band in range(bands.nb_bands): eband = [e - bands.efermi for e in bands.bands[Spin.up][band]] for k in range(nkpts - 1): red, green, blue = [int(255 * (contrib[band, k, i] + contrib[band, k+1, i])/2) for i in range(3)] colorBands.append( go.Scatter( x=[k, k+1], y=[eband[k], eband[k+1]], mode="lines", line=go.Line(color="rgb({}, {}, {})".format(red, green, blue)), showlegend=False ) ) # As previously, two subplots are used to plot the band diagram on the left and the density of states on the right. # In[31]: # set up a new figure with two subplots colorbandfig = tls.make_subplots(rows=1, cols=2, shared_yaxes=True) # add the bands in the first subplot for btrace in colorBands: colorbandfig.append_trace(btrace, 1, 1) # add vlines for specific k-points in the first subplot for vline in vlines: colorbandfig.append_trace(vline, 1, 1) # add the densities in the second subplot colorbandfig.append_trace(trace_tdos, 1, 2) colorbandfig.append_trace(trace_3s, 1, 2) colorbandfig.append_trace(trace_3p, 1, 2) # Layout configuration colorbandfig["layout"].update( go.Layout( title="Bands diagram and density of states of Silicon", xaxis1=bandxaxis, yaxis1=bandyaxis, xaxis2=dosxaxis, annotations=go.Annotations(annotations) ) ) # adjust size of subplots colorbandfig["layout"]["xaxis1"]["domain"] = [0., 0.7] colorbandfig["layout"]["xaxis2"]["domain"] = [0.702, 1.] # add some specific options colorbandfig["layout"]["yaxis1"]["mirror"] = "allticks" colorbandfig["layout"]["xaxis2"]["mirror"] = "allticks" # add a custom legend legend = go.Legend( x=.98, y=.98, xanchor="right", yanchor="top", bordercolor='#333', borderwidth=1 ) colorbandfig["layout"]["legend"] = legend # do the plot plot_url = pltly.plot(colorbandfig, filename="DOS_bands_Si_color", auto_open=False) tls.embed(plot_url) # In[2]: from IPython.display import HTML, display display(HTML('')) display(HTML('')) import publisher publisher.publish('density-of-states ', '/ipython-notebooks/density-of-states/', 'plotting the density of states and the band diagram using pymatgen and plotly', 'Plotting Density of States with Plotly and Pymatgen') # In[ ]: