How to plot band structure? - python

I'm running a Vasp calculation with pyiron. I can easily plot the total density of states by accessing the ElectronicStructure and Dos objects, e.g.
from pyiron.project import Project
pr = Project('tmp')
pr.remove_jobs(recursive=True)
vasp = pr.create_job(pr.job_type.Vasp, 'vasp')
vasp.structure = pr.create_ase_bulk('Al')
vasp.run()
dos = vasp.get_electronic_structure().get_dos()
dos.plot_total_dos()
Is there a similarly convenient way of plotting the band structure hiding somewhere?

Although there isn't a direct plot function, the band structure can be plot using the eigenvalue matrix
import matplotlib.pylab as plt
plt.plot(vasp.get_electronic_structure().eigenvalue_matrix);

Or to plot it manually you could use:
# The trace is system dependent, in this example we use:
trace = np.array([[0, 0, 0], # Gamma
[1, 0, 0], # X
[1, 1, 0], # M
[0, 0, 0], # Gamma
[0, 0, 1], # Z
[1, 0, 1], # R
[1, 1, 1], # A
[0, 0, 1]]) # Z
label_ticks = ['$\Gamma$', 'X', 'M', '$\Gamma$', 'Z', 'R', 'A', 'Z']
energy = ham['output/electronic_structure/eig_matrix']
E_f = ham_chg['output/electronic_structure/efermi']
energy -= E_f
n_kpoints = len(energy)
n_trace = int(n_kpoints / (len(trace)-1))
normal_ticks = [i*n_trace for i in range(len(trace))]
plt.axhline(y=0, ls='--', color='k')
plt.plot(energy, 'r-')
plt.xlim(normal_ticks[0], normal_ticks[-1])
plt.xticks(normal_ticks, label_ticks)
plt.grid(axis='x')
plt.ylabel("Energy - $E_F$ [eV]")
plt.ylim(-1, 1);
This requires two VASP calculation, first you calculate the charge density:
ham_1.write_charge_density = True
And after this job is executed you use the charge density to calculate the band structure by restarting from the previous job:
ham_2 = ham.restart_from_charge_density(job_name="job_band", icharg=11)
But to my knowledge we currently have no automated functionality for this.

If you are using VASP to calculate the band structure, a friendly tool named VASPKIT will help you plot it easily! Here's a link!
After your installation is complete, open vaspkit in your folder, then type: 21
211) Band-Structure
212) Projected Band-Structure of Only-One-Selected Atom
213) Projected Band-Structure of Each Element
214) Projected Band-Structure of Selected Atoms
215) Projected Band-Structure by Element-Weights
216) The Sum of Projected Band for Selected Atoms and Orbitals
Then you can follow the prompts to automatically draw the energy band diagram.

Related

How to calculate the probability that a sample belongs to a certain class from the mixture Gaussian distribution?

I would like to know, for this mixture of Gaussian distributions generated by the data we give ourselves, how do we figure out which component is more likely to belong to a new sample we are given?
I learned that Matlab seems to have functions that can be calculated directly, is there any in python? I haven't found an answer so far.
import matplotlib.pyplot as plt
import numpy as np
import random
# Bivariate example
dim = 2
# Settings
n = 500
NumberOfMixtures = 3
# Mixture weights (non-negative, sum to 1)
w = [0.5, 0.25, 0.25]
# Mean vectors and covariance matrices
MeanVectors = [ [0,0], [-5,5], [5,5] ]
CovarianceMatrices = [ [[1, 0], [0, 1]], [[1, .8], [.8, 1]], [[1, -.8], [-.8, 1]] ]
# Initialize arrays
samples = np.empty( (n,dim) ); samples[:] = np.NaN
componentlist = np.empty( (n,1) ); componentlist[:] = np.NaN
# Generate samples
for iter in range(n):
# Get random number to select the mixture component with probability according to mixture weights
DrawComponent = random.choices(range(NumberOfMixtures), weights=w, cum_weights=None, k=1)[0]
# Draw sample from selected mixture component
DrawSample = np.random.multivariate_normal(MeanVectors[DrawComponent], CovarianceMatrices[DrawComponent], 1)
# Store results
componentlist[iter] = DrawComponent
samples[iter, :] = DrawSample
# Report fractions
print('Fraction of mixture component 0:', np.sum(componentlist==0)/n)
print('Fraction of mixture component 1:',np.sum(componentlist==1)/n)
print('Fraction of mixture component 2:',np.sum(componentlist==2)/n)
# Visualize result
plt.plot(samples[:, 0], samples[:, 1], '.', alpha=0.5)
plt.grid()
plt.show()
The problem has been sovled, the answer can refer in the link:
https://stackoverflow.com/questions/42971126/multivariate-gaussian-distribution-scipy

How to set absolute position of GLMeshItem in 3D pyqtgraph implementation

I am building a visualizer for some data and want to use 3D spheres plotted in pyqtgraphs 3D OpenGL components to represent targets identified within the data provided.
I am able to generate the spheres and move them using GLMeshItem.translate() commands, however I am not able to find a convenient way of setting coordinates of the sphere without first getting the current position of said spheres through a call to .transform() and then generating a translate command from it's current position to the new absolute coordinates I would like it to be moved to. It may be that that is the only way to accomplish this, I just suspect there is a more direct set the mesh items absolute coordinates that I just can't seem to identify.
The following code shows a basic framework for what I am doing, and also the current method I am using to move the sphere.
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
import pyqtgraph.opengl as gl
import numpy as np
app = QtGui.QApplication([])
w = gl.GLViewWidget()
w.showMaximized()
w.setWindowTitle('pyqtgraph example: GLMeshItem')
w.setCameraPosition(distance=40)
g = gl.GLGridItem()
g.scale(2,2,1)
w.addItem(g)
verts = np.array([
[0, 0, 0],
[2, 0, 0],
[1, 2, 0],
[1, 1, 1],
])
faces = np.array([
[0, 1, 2],
[0, 1, 3],
[0, 2, 3],
[1, 2, 3]
])
colors = np.array([
[1, 0, 0, 0.3],
[0, 1, 0, 0.3],
[0, 0, 1, 0.3],
[1, 1, 0, 0.3]
])
md = gl.MeshData.sphere(rows=4, cols=4)
colors = np.ones((md.faceCount(), 4), dtype=float)
colors[::2,0] = 0
colors[:,1] = np.linspace(0, 1, colors.shape[0])
md.setFaceColors(colors)
m3 = gl.GLMeshItem(meshdata=md, smooth=False)#, shader='balloon')
w.addItem(m3)
target = gl.MeshData.sphere(4,4,10)
targetMI = gl.GLMeshItem(meshdata = target, drawFaces = True,smooth = False)
w.addItem(targetMI)
while(1):
targetMI.translate(0.1,0,0)
app.processEvents()
## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
As can be seen in this example. translate works fine for moving relative to the current position. I am just curious as to whether there is a method for doing an absolute position move on the GLMeshItem (in this case targetMI) such that I could make it move to a coordinate without having to first get the transform and then calculating the translate required to move to the desired coordinates.
An option is to reset the item’s transform to an identity transformation by resetTransform(), before you set the absolute position by translate(). e.g:
targetMI.resetTransform()
targetMI.translate(10, 0, 0)

Adding an animation to a random walk plot [Python]

I have written a code that plots random walks. There are traj different random walks generated and each consists of n steps. I would like to animate their moves. How can I do that?
My code below:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def random_walk_2D(n, traj = 1):
for i in range(traj):
skoki = np.array([[0, 1], [1, 0], [-1, 0], [0, -1]])
losy = np.random.randint(4, size = n)
temp = skoki[losy, :]
x = np.array([[0, 0]])
temp1 = np.concatenate((x, temp), axis = 0)
traj = np.cumsum(temp1, axis = 0)
plt.plot(traj[:, 0], traj[:, 1])
plt.plot(traj[-1][0], traj[-1][1], 'ro') #the last point
plt.show()
As it stands now, you generate traj in one shot. I mean that traj in traj = np.cumsum(temp1, axis = 0) already contains all the "story" from the beginning to the end. If you want to create an animation that is in "real time", you should not generate traj in one shot, but iteratively, plotting new steps as they come. What about doing:
import numpy as np
import matplotlib.pyplot as plt
def real_time_random_walk_2D_NT(
nb_steps, nb_trajs, with_dots=False, save_trajs=False, tpause=.01
):
"""
Parameters
----------
nb_steps : integer
number of steps
nb_trajs : integer
number of trajectories
save_trajs : boolean (optional)
If True, entire trajectories are saved rather than
saving only the last steps needed for plotting.
False by default.
with_dots : boolean (optional)
If True, dots representative of random-walking entities
are displayed. Has precedence over `save_trajs`.
False by default.
tpause : float (optional)
Pausing time between 2 steps. .01 secondes by default.
"""
skoki = np.array([[0, 1], [1, 0], [-1, 0], [0, -1]])
trajs = np.zeros((nb_trajs, 1, 2))
for i in range(nb_steps):
_steps = []
for j in range(nb_trajs):
traj = trajs[j,:,:]
losy = np.random.randint(4, size = 1)
temp = skoki[losy, :]
traj = np.concatenate((traj, temp), axis = 0)
traj[-1,:] += traj[-2,:]
_steps.append(traj)
if save_trajs or with_dots:
trajs = np.array(_steps)
if with_dots:
plt.cla()
plt.plot(trajs[:,i, 0].T, trajs[:,i, 1].T, 'ro') ## There are leeway in avoiding these costly transpositions
plt.plot(trajs[:,:i+1, 0].T, trajs[:,:i+1, 1].T)
else:
plt.plot(trajs[:,-1+i:i+1, 0].T, trajs[:,-1+i:i+1, 1].T)
else:
trajs = np.array(_steps)[:,-2:,:]
plt.plot(trajs[:,:, 0].T, trajs[:,:, 1].T)
plt.pause(tpause)
real_time_random_walk_2D_NT(50, 6, with_dots=True)
real_time_random_walk_2D_NT(50, 6)

How can I mirror a polygon using Python?

I have a set of images over which polygons are drawn. I have the points of those polygons and I draw these using Shapely and check whether certain points from an eye tracker fall into the polygons.
Now, some of those images are mirrored but I do not have the coordinates of the polygons drawn in them. How can I flip the polygons horizontally? Is there a way to do this with Shapely?
if you want to reflect a polygon with respect to a vertical axis, i.e., to flip them horizontally, one option would be to use the scale transformation (using negative unit scaling factor) provided by shapely.affinity or to use a custom transformation:
from shapely.affinity import scale
from shapely.ops import transform
from shapely.geometry import Polygon
def reflection(x0):
return lambda x, y: (2*x0 - x, y)
P = Polygon([[0, 0], [1, 1], [1, 2], [0, 1]])
print(P)
#POLYGON ((0 0, 1 1, 1 2, 0 1, 0 0))
Q1 = scale(P, xfact = -1, origin = (1, 0))
Q2 = transform(reflection(1), P)
print(Q1)
#POLYGON ((2 0, 1 1, 1 2, 2 1, 2 0))
print(Q2)
#POLYGON ((2 0, 1 1, 1 2, 2 1, 2 0))
by multiplying [[1,0], [0,-1]], You can get the vertically flipped shape. (I tested this on jupyter notebook)
pts = np.array([[153, 347],
[161, 323],
[179, 305],
[195, 315],
[184, 331],
[177, 357]])
display(Polygon(pts))
display(Polygon(pts.dot([[1,0],[0,-1]])))
And If you multiply [[-1,0],[0,1]], you will get horizontally flipped shape.
Refer linear transformation to understand why this works.

What is this plot called and how to make it in matplotlib?

Suppose I have a graph like this
plot(np.random.rand(10))
pylab.ylim([-0,1.5])
and I have a state sequence as such
In[141]:np.random.randint(5,size=(1, 10))
Out[142]:array([[2, 2, 4, 2, 1, 2, 0, 0, 4, 4]])
I want to superimpose that state sequence on the above plot like this:
But how does one do this in matplotlib?
To summarise: I want different parts of your plot to have differently coloured background that depends on the state, where each unique state has a unique colour.
To divide your plot into differently colored sections you can use the axvspan function.
This requires that you know the x-coordinate boundaries for your states.
Assuming that a state is always L units long, and that STATE_COLOR is a mapping between state number and a matplotlib color ('r', 'k', 'b', ...) then you get the following:
# States and their colors
state_list = [1, 2, 1]
STATE_COLOR = { 1 : 'r', 2 : 'y' }
L = 1.5 # Constant state length
x = np.linspace(0, 4.5)
y = x**2 - 3
# Draw states
for i, state in enumerate(state_list):
x1 = i * L
x2 = (i+1) * L
plt.axvspan(x1, x2, color=STATE_COLOR[state])
# Draw line data
plt.plot(x, y)

Categories

Resources