VTK rendering 2D mesh in python - python

so i'm trying to render a 2D mesh using vtk (in python). I have a list
of tuples containing all the points and also a list of tuples containing the
points of each cell. Just to experiment, I tried to create a polydata object
of a square with 4 elements and render it, but i ended up with this:
I would like it to show the lines connecting the nodes (like a wireframe)
instead of solid square..
This is the code to produce the image above:
def main2():
#Array of vectors containing the coordinates of each point
nodes = np.array([[0, 0, 0], [1, 0, 0], [2, 0, 0], [2, 1, 0], [2, 2, 0],
[1, 2, 0], [0, 2, 0], [0, 1, 0], [1, 1, 0]])
#Array of tuples containing the nodes correspondent of each element
elements = np.array([(0, 1, 8, 7), (7, 8, 5, 6), (1, 2, 3, 8), (8, 3, 4,
5)])
#Make the building blocks of polyData attributes
Mesh = vtk.vtkPolyData()
Points = vtk.vtkPoints()
Cells = vtk.vtkCellArray()
#Load the point and cell's attributes
for i in range(len(nodes)):
Points.InsertPoint(i, nodes[i])
for i in range(len(elements)):
Cells.InsertNextCell(mkVtkIdList(elements[i]))
#Assign pieces to vtkPolyData
Mesh.SetPoints(Points)
Mesh.SetPolys(Cells)
#Mapping the whole thing
MeshMapper = vtk.vtkPolyDataMapper()
if vtk.VTK_MAJOR_VERSION <= 5:
MeshMapper.SetInput(Mesh)
else:
MeshMapper.SetInputData(Mesh)
#Create an actor
MeshActor = vtk.vtkActor()
MeshActor.SetMapper(MeshMapper)
#Rendering Stuff
camera = vtk.vtkCamera()
camera.SetPosition(1,1,1)
camera.SetFocalPoint(0,0,0)
renderer = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(renderer)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
renderer.AddActor(MeshActor)
renderer.SetActiveCamera(camera)
renderer.ResetCamera()
renderer.SetBackground(1,1,1)
renWin.SetSize(300,300)
#Interact with data
renWin.Render()
iren.Start()
main2()
I would also like to know if it's possible to have a gridline as the
background of the render window, instead of a black color, just like this:
Thanks in advance!

You can use MeshActor.GetProperty().SetRepresentationToWireframe() (https://www.vtk.org/doc/nightly/html/classvtkProperty.html#a2a4bdf2f46dc499ead4011024eddde5c) to render the actor as wireframe, or MeshActor.GetProperty().SetEdgeVisibility(True) to render it as solid with edges rendered as lines.
Regarding the render window background, I don't know.

Thanks to #MafiaSkafia I created what I was looking for, 2D grid for 3D purposes, maybe someone will be looking for something like this too.
# plane
planeSource = vtk.vtkPlaneSource()
planeSource.SetOrigin(-100.0, -100.0, 0.0)
# planeSource.SetNormal(0.0, 0.0, 1.0)
planeSource.SetResolution(100,100)
planeSource.SetPoint1(100.0,-100.0,0.0)
planeSource.SetPoint2(-100.0,100.0,0.0)
planeSource.Update()
plane = planeSource.GetOutput()
# Create a mapper and actor
mapperP = vtk.vtkPolyDataMapper()
mapperP.SetInputData(plane)
actorP = vtk.vtkActor()
actorP.SetMapper(mapperP)
actorP.GetProperty().SetColor(0,0,0)
actorP.GetProperty().EdgeVisibilityOn() # showing mesh
actorP.GetProperty().SetEdgeColor(1,1,1)
actorP.GetProperty().SetOpacity(0.2) # transparency
...
renderer.AddActor(actorP)

Related

VTK: creating polygon and a hole with vtkDelaunay2D not working

I would like to render a Polygon with a hole in VTK. I found that the vtkDelaunay2D class should do the trick. I followed the tutorial here vtkDelaunay2D Example and it worked perfectly.
Afterwards I tried to create a different polygon with a different hole. And I don't get why it's not working and would like to know what I would have to change.
This is how it should look like.
This is how it looks like in reality.
This is the code I used:
import vtk
import random
points = vtk.vtkPoints()
ls = [
[2, 2], [-2, 2], [-2, -2], [2, -2],
[5, 5], [-5, 5], [-8, 0], [-5, -5], [5, -5], [8, 0],
[10, 10], [-10, 10], [-10, -10], [10, -10]
]
for x, y in ls:
points.InsertNextPoint(x, y, 0)
aPolyData = vtk.vtkPolyData()
aPolyData.SetPoints(points)
aCellArray = vtk.vtkCellArray()
cPolygon = vtk.vtkPolygon()
start = 0
for idd in range(start, start + 4):
cPolygon.GetPointIds().InsertNextId(idd)
aCellArray.InsertNextCell(cPolygon)
boundary = vtk.vtkPolyData()
boundary.SetPoints(aPolyData.GetPoints())
boundary.SetPolys(aCellArray)
delaunay = vtk.vtkDelaunay2D()
delaunay.SetInputData(aPolyData)
delaunay.SetSourceData(boundary)
################################## Actors etc:
meshMapper = vtk.vtkPolyDataMapper()
meshMapper.SetInputConnection(delaunay.GetOutputPort())
colors = vtk.vtkNamedColors()
meshActor = vtk.vtkActor()
meshActor.SetMapper(meshMapper)
meshActor.GetProperty().EdgeVisibilityOn()
meshActor.GetProperty().SetEdgeColor(colors.GetColor3d("Peacock"))
meshActor.GetProperty().SetInterpolationToFlat()
boundaryMapper = vtk.vtkPolyDataMapper()
boundaryMapper.SetInputData(boundary)
boundaryActor = vtk.vtkActor()
boundaryActor.SetMapper(boundaryMapper)
boundaryActor.GetProperty().SetColor(colors.GetColor3d("Raspberry"))
boundaryActor.GetProperty().SetLineWidth(3)
boundaryActor.GetProperty().EdgeVisibilityOn()
boundaryActor.GetProperty().SetEdgeColor(1, 1, 0)
boundaryActor.GetProperty().SetRepresentationToWireframe()
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderer.AddActor(meshActor)
renderer.AddActor(boundaryActor)
renderer.SetBackground(colors.GetColor3d("Mint"))
renderWindow.SetSize(640, 480)
renderWindow.Render()
renderWindowInteractor.Start()
As far as I can tell it should work. Like in the example I create a set of points, define a boundary around the first 4 points (the should be hole) and then just render it.
Change
for idd in range(start, start + 4):
into
for idd in reversed(range(start, start + 4)):

How to plot band structure?

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.

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)

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.

List all faces for all edges

A very simple question:
how to compute efficiently in Python (or Cython) the following quantity.
Given the list of polygons in 3D (polygon
There is a list of polygons given in the following form:
vertex = np.array([[0, 0, 0], [0, 0, 1], [0, 1, 0],[1, 0, 0],[0.5, 0.5, 0.5]], order = 'F').T
polygons = np.array([3, 0, 1, 2, 4, 1, 2, 3 ,4])
i.e. polygon is a 1D array, which contains entries of the form [N,i1,i2,i3,i4,...],
N is the number of vertices in a polygons and then the id numbers of the vertices in the vertex array (in the example above there is one triangle with 3 vertices [0,1,2] and one polygon with 4 vertices [1,2,3,4]
I need to compute the information: a list of all edges and for each edge the information
which faces contain this edge.
And I need to do it fast: the number of vertices can be large.
Update
The polygon is closed, i.e. a polygon [4, 0, 1, 5, 7] means that there are 4 vertices and edges are 0-1, 1-5, 5-7, 7-0
The face is a synonim to polygon in fact.
Dunno if this is the fastest option, most probably not, but it works. I think the slowest part is edges.index((v, polygon[i + 1])) where we have to find if this edge is already in list. Vertex array is not really needed since edge is a pair of vertex indexes. I used face_index as a reference to polygon index since you didn't write what face is.
vertex = [[0,0,0], [0,0,1], [0,1,0],[1,0,0],[0.5,0.5,0.5]]
polygons = [3,0,1,2,4,1,2,3,4]
_polygons = polygons
edges = []
faces = []
face_index = 0
while _polygons:
polygon = _polygons[1:_polygons[0] + 1]
polygon.append(polygon[0])
_polygons = _polygons[_polygons[0] + 1:]
for i, v in enumerate(polygon[0:-1]):
if not (v, polygon[i + 1]) in edges:
edges.append((v, polygon[i + 1]))
faces.append([face_index, ])
else:
faces[edges.index((v, polygon[i + 1]))].append(face_index)
face_index += 1
edges = map(lambda edge, face: (edge, face), edges, faces)
print edges
<<< [((0, 1), [0]), ((1, 2), [0, 1]), ((2, 0), [0]), ((2, 3), [1]), ((3, 4), [1]), ((4, 1), [1])]
You can make it faster by removing line polygon.append(polygon[0]) and append first vertice of polygon to vertices list in polygon manually, which shouldn't be a problem.
I mean change polygons = [3,0,1,2,4,1,2,3,4] into polygons = [3,0,1,2,0,4,1,2,3,4,1].
PS Try to use PEP8. It is a code typing style. It says that you should put a space after every comma in iterables so it's eaasier to read.

Categories

Resources