I'm trying to display an EnSight file in a Qt/VTK application. More precisely, I want to display a specific EnSight part and color it by the magnitude of one of the vector variables. As far as I understand, the output of the VTK reader is a vtkMultiBlockDataSet, with one block per part. Each block is a vtkUnstructuredGrid and the variables are specific arrays in the pointdata.
The code I have so far is below. Unfortunately, it shows a uniform color (when the same file loaded in ParaView it shows some local variations).
Obviously I'm missing something, but I can't figure where. I'd be grateful for any hints.
casefile = "data/Results/exported/blahblah.case"
part_id = 0
var_id = 2
reader = vtk.vtkGenericEnSightReader()
reader.SetCaseFileName(casefile)
reader.Update()
# Color map
colormap = vtk.vtkLookupTable()
colormap.SetHueRange(0.667, 0.0)
colormap.SetVectorModeToMagnitude()
colormap.Build()
multiblock = reader.GetOutput()
ugrid = multiblock.GetBlock(part_id)
pointdata = ugrid.GetPointData()
data = pointdata.GetArray(var_id)
data_range = data.GetRange(-1)
mesh_mapper = vtk.vtkDataSetMapper()
mesh_mapper.SetInput(ugrid)
mesh_mapper.SetColorModeToDefault()
mesh_mapper.SetScalarRange(data_range)
mesh_mapper.SetScalarVisibility(True)
mesh_mapper.SetLookupTable(colormap)
#
mesh_actor = vtk.vtkActor()
mesh_actor.SetMapper(mesh_mapper)
mesh_actor.GetProperty().SetDiffuseColor(1., 1., 1.)
renderer = vtk.vtkRenderer()
renderer.AddActor(mesh_actor)
renderer.AddActor2D(colorbar)
colormap = vtk.vtkLookupTable()
colormap.SetHueRange(0.667, 0.0)
colormap.SetVectorModeToMagnitude()
colormap.Build()
Will generate a lookuptable with a range between 0 and 1. Is this the data range from your example data?
If not, set the data range to the min/max values in the data_range tuple and then call Build() - I think this should help - do you have example data?
Related
For 3D printing, we slice the digital objects into image stacks in order to stack them layer by layer using a 3D printer. And when the slice is done, how to label the inner/outer to set the solid parts?
The STL model:
The Slices:
Sample of one image stack (sliced):
but the need is to keep or label the inner/outer of contours, say the inner is black so the 3D printer will print it and skip the white outer. The goal is filled inner of contours as the following image:
Try 1
import pyvista as pv
mesh = pv.read('./haus.stl')
slices = mesh.slice_along_axis(n=20, axis='z', progress_bar=True)
# show single slice with camera setting
slices[15].plot(cpos=[0, 1, 1], line_width=5, parallel_projection=True,)
# save slices (outcome is as step.3 image stack)
for i in range(20):
p = pv.Plotter(off_screen=True)
p.add_mesh(slices[i])
p.camera_position = 'zy'
p.enable_parallel_projection()
im_name = "im_slice_" + str(i) + ".jpg"
p.screenshot(im_name)
# Try voxelize (as ans from https://stackoverflow.com/questions/75300529)
voxels = pv.voxelize(mesh, density=mesh.length / 100)
# Try pv.Plane() (not test yet)
plane=pv.Plane()
plane.compute_implicit_distance(mesh, inplace=True)
np.sign(plane.point_data['implicit_distance'])
#i_resolution=?, j_resolution=?
# Try vtk (not test yet)
# https://stackoverflow.com/questions/68191368
voxelize model:
voxelize sliced:
but voxelize sliced doesn't seem very suitable. A very fine mesh needs to be built to restore the boundaries.
Try 2 VTK example
show STL:
Just add STL reader and Mapper:
filename = './haus.stl'
reader = vtkSTLReader()
reader.SetFileName(filename)
reader.Update()
stlMapper = vtk.vtkPolyDataMapper()
stlMapper.SetInputConnection(reader.GetOutputPort())
polydata = stlMapper
print("Get GetOrigin", polydata.GetCenter())
sphereSource = reader
slice result:
Try 2 is almost done with the job, but can not figure out the SetExtent/SetOrigin effect. The output image all fit to the contours' dimensions so each output image WXH is not identical.
Try 3 3D Silcer example
Only change some code as following:
inputModelFile = "./data/haus.stl"
outputDir = "./outputs/"
...
for i in range(80,140, 10):
imageio.imwrite(f"{outputDir}/image_{i:03}.jpg", 255 - outputLabelmapVolumeArray[i]) # Inverting Colors
The result seems acceptable, but need future to revise some code to match the resolution, position, spacing, etc. So, is there a more lean and more efficient way to automate similar work?
You may want to try out the combination of vtkFeatureEdges, vtkStripper and vtkTriangleFilter, eg:
from vedo import *
msh = Mesh('https://vedo.embl.es/examples/data/cow.vtk')
slices = []
for z in np.arange(-.50, .50, .15):
line = msh.clone().cut_with_plane(origin=(0,0,z), normal='z')
cap = line.cap(True)
slices.append(cap)
show(slices, msh.alpha(0.1), axes=1)
I've wrote a code to produce cylinder objects using vtk in python. This code works fine where it produces a 3D scene where i can zoom or turn around the cylinders which i have been made. The problem is i want to export this rendered scene to paraview to view and save it for later works. How can i do this?
Here is the code that produce a Y-shape with cylinders:
import vtk
import numpy as np
'''
Adding multiple Actors to one renderer scene using VTK package with python api.
Each cylinder is an Actor with three input specifications: Startpoint, Endpoint and radius.
After creating all the Actors, the preferred Actors will be added to a list and that list will be our input to the
renderer scene.
A list or numpy array with appropriate 3*1 shape could be used to specify starting and ending points.
There are two alternative ways to apply the transform.
1) Use vtkTransformPolyDataFilter to create a new transformed polydata.
This method is useful if the transformed polydata is needed
later in the pipeline
To do this, set USER_MATRIX = True
2) Apply the transform directly to the actor using vtkProp3D's SetUserMatrix.
No new data is produced.
To do this, set USER_MATRIX = False
'''
USER_MATRIX = True
def cylinder_object(startPoint, endPoint, radius, my_color="DarkRed"):
colors = vtk.vtkNamedColors()
# Create a cylinder.
# Cylinder height vector is (0,1,0).
# Cylinder center is in the middle of the cylinder
cylinderSource = vtk.vtkCylinderSource()
cylinderSource.SetRadius(radius)
cylinderSource.SetResolution(50)
# Generate a random start and end point
# startPoint = [0] * 3
# endPoint = [0] * 3
rng = vtk.vtkMinimalStandardRandomSequence()
rng.SetSeed(8775070) # For testing.8775070
# Compute a basis
normalizedX = [0] * 3
normalizedY = [0] * 3
normalizedZ = [0] * 3
# The X axis is a vector from start to end
vtk.vtkMath.Subtract(endPoint, startPoint, normalizedX)
length = vtk.vtkMath.Norm(normalizedX)
vtk.vtkMath.Normalize(normalizedX)
# The Z axis is an arbitrary vector cross X
arbitrary = [0] * 3
for i in range(0, 3):
rng.Next()
arbitrary[i] = rng.GetRangeValue(-10, 10)
vtk.vtkMath.Cross(normalizedX, arbitrary, normalizedZ)
vtk.vtkMath.Normalize(normalizedZ)
# The Y axis is Z cross X
vtk.vtkMath.Cross(normalizedZ, normalizedX, normalizedY)
matrix = vtk.vtkMatrix4x4()
# Create the direction cosine matrix
matrix.Identity()
for i in range(0, 3):
matrix.SetElement(i, 0, normalizedX[i])
matrix.SetElement(i, 1, normalizedY[i])
matrix.SetElement(i, 2, normalizedZ[i])
# Apply the transforms
transform = vtk.vtkTransform()
transform.Translate(startPoint) # translate to starting point
transform.Concatenate(matrix) # apply direction cosines
transform.RotateZ(-90.0) # align cylinder to x axis
transform.Scale(1.0, length, 1.0) # scale along the height vector
transform.Translate(0, .5, 0) # translate to start of cylinder
# Transform the polydata
transformPD = vtk.vtkTransformPolyDataFilter()
transformPD.SetTransform(transform)
transformPD.SetInputConnection(cylinderSource.GetOutputPort())
# Create a mapper and actor for the arrow
mapper = vtk.vtkPolyDataMapper()
actor = vtk.vtkActor()
if USER_MATRIX:
mapper.SetInputConnection(cylinderSource.GetOutputPort())
actor.SetUserMatrix(transform.GetMatrix())
else:
mapper.SetInputConnection(transformPD.GetOutputPort())
actor.SetMapper(mapper)
actor.GetProperty().SetColor(colors.GetColor3d(my_color))
return actor
def render_scene(my_actor_list):
renderer = vtk.vtkRenderer()
for arg in my_actor_list:
renderer.AddActor(arg)
namedColors = vtk.vtkNamedColors()
renderer.SetBackground(namedColors.GetColor3d("SlateGray"))
window = vtk.vtkRenderWindow()
window.SetWindowName("Oriented Cylinder")
window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(window)
# Visualize
window.Render()
interactor.Start()
if __name__ == '__main__':
my_list = []
p0 = np.array([0, 0, 0])
p1 = np.array([0, 10, 0])
p2 = np.array([7, 17, 0])
p3 = np.array([-5, 15, 0])
my_list.append(cylinder_object(p0, p1, 1, "Red"))
my_list.append(cylinder_object(p1, p2, 0.8, "Green"))
my_list.append(cylinder_object(p1, p3, 0.75, "Navy"))
render_scene(my_list)
I have multiple actors where all of them are rendered together in one render scene, can i pass each actor into a vtk.vtkSTLWriter? this seems not working!
What you're looking for is subclasses of the vtkExporter class which, as per the linked doco:
vtkExporter is an abstract class that exports a scene to a file. It is very similar to vtkWriter except that a writer only writes out the geometric and topological data for an object, where an exporter can write out material properties, lighting, camera parameters etc.
As you can see from the inheritance diagram of the class there's about 15 classes that support exporting such a scene into a file that can be viewed in appropriate readers.
IMHO the one you'll have the most luck with is the vtkVRMLExporter class as it's a fairly common format. That being said I don't believe Paraview supports VRML files (at least based on some pretty ancient posts I've found) but I'm pretty sure MayaVi does.
Alternatively you could, as you mentioned, export objects into STL files but STL files simply contain triangle coordinates and info on how they connect. Such files cannot possibly describe info re the scene such as camera or lighting information. Also last I checked a single STL file can only contain a single object so your three cylinders would end up being a merged object so its probably not what you want.
I added these codes and it created a VRML file from my rendered scene.
exporter = vtk.vtkVRMLExporter()
exporter.SetRenderWindow(window)
exporter.SetFileName("cylinders.wrl")
exporter.Write()
exporter.Update()
I'm visualizing a time series of spatial data in Paraview, and I would like for my setup script to set the color tables for a given field based on the field's range over the full time series, rather than an individual snapshot. I've tried initializing the lookup table with values computed by the script, but to no avail.
The figure below shows results of running my setup script. The values in the Python Shell window are what the scales should be set to, but the color bar shows another value.
The relevant part of my setup script is here.
# get the scales for the surface fields
mag_os_xdmf = FindSource('mag_os.xdmf')
with h5py.File(mag_os_xdmf.FileName.replace('xdmf', 'h5'), 'r') as h5:
for comp in ('br', 'bt', 'bp'):
scale = np.abs(h5[comp].value).max()
print(comp, scale)
ctab = [-scale, 0.23137254901960785, 0.2980392156862745, 0.7529411764705882,
scale, 0.7058823529411765, 0.01568627450980392, 0.14901960784313725]
DataRep = GetDisplayProperties(mag_os_xdmf)
lut = GetLookupTableForArray(comp, 1, NanColor=[0.24705882352941178, 0.0, 0.0],
RGBPoints = ctab, ColorSpace='Diverging' )
DataRep.ColorArrayName = ('POINT_DATA', comp)
DataRep.LookupTable = lut
Render()
For comparison, here's the output of a python trace when I manually change the colorbar
try: paraview.simple
except: from paraview.simple import *
paraview.simple._DisableFirstRenderCameraReset()
mag_os_xdmf = GetActiveSource()
DataRepresentation6 = GetDisplayProperties(mag_os_xdmf)
a1_br_PVLookupTable = GetLookupTableForArray( "br", 1, RGBPoints=[-0.122, 0.23, 0.299, 0.754, 0.122, 0.706, 0.016, 0.15] )
DataRepresentation6.ScalarOpacityFunction = []
DataRepresentation6.ColorArrayName = ('POINT_DATA', 'br')
DataRepresentation6.LookupTable = a1_br_PVLookupTable
Render()
You should be able to do something like the following:
# get color transfer function/color map for 'br'
lut = GetColorTransferFunction('br')
# get opacity transfer function/opacity map for 'br'
opacityLut = GetOpacityTransferFunction('br')
# Rescale transfer function
lut.RescaleTransferFunction(-scale, scale)
# Rescale transfer function
opacityLut.RescaleTransferFunction(-scale, scale)
I am trying to plot radar data in bokeh from an hdf5 file. I've stored the data into a 2d array that is 1800*3600. When I try to plot the data using p.image it shows up black with some splotches which i'm assuming is where the data is greater than 0, but it doesn't conform to the palette i've specified. I'm not sure why this is occurring.
f = h5py.File(fname, 'r')
lat = f['Grid']['lat']
lon = f['Grid']['lon']
precip = f['Grid']['precipitationCal']
precip = np.transpose(precip)
d = np.empty((1800,3600))
for (x,y), value in np.ndenumerate(precip):
if value <= 0:
d[x,y]=np.nan
else:
d[x,y]=value
output_file("testimage.html", title="image.py example")
p = figure(x_range = [0, 3600], y_range=[0, 1800])
p.image(image=[d],x=[0],y=[0],dw=[3600], dh=[1800], pallete="Spectral-256")
show(p)
Two things:
First, the argument to pass to p.image is spelled "palette" not "pallete". The default palette is Grey9, which would give you the colormap you have.
Second (and the docs are sort of unclear on this), the palette argument accepts a list containing the colormap as hex values. This can be either an arbitrary list:
palette = ["#8c9494", "#8398a2", "#7c9baa"]
p.image(image=[d],x=[0],y=[0],dw=[360], dh=[180], palette=palette)
or a standard palette from Bokeh
from bokeh.palettes import Spectral6
p.image(image=[d],x=[0],y=[0],dw=[360], dh=[180], palette=Spectral6)
Note:
print(Spectral6)
> ['#3288bd', '#99d594', '#e6f598', '#fee08b', '#fc8d59', '#d53e4f']
https://docs.bokeh.org/en/latest/docs/reference/palettes.html
I have the following code that runs through the following:
Draw a number of points from a true distribution.
Use those points with curve_fit to extract the parameters.
Check if those parameters are, on average, close to the true values.
(You can do this by creating the "Pull distribution" and see if it returns
a standard normal variable.
# This script calculates the mean and standard deviation for
# the pull distributions on the estimators that curve_fit returns
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import gauss
import format
numTrials = 10000
# Pull given by (a_j - a_true)/a_error)
error_vec_A = []
error_vec_mean = []
error_vec_sigma = []
# Loop to determine pull distribution
for i in xrange(0,numTrials):
# Draw from primary distribution
mean = 0; var = 1; sigma = np.sqrt(var);
N = 20000
A = 1/np.sqrt((2*np.pi*var))
points = gauss.draw_1dGauss(mean,var,N)
# Histogram parameters
bin_size = 0.1; min_edge = mean-6*sigma; max_edge = mean+9*sigma
Nn = (max_edge-min_edge)/bin_size; Nplus1 = Nn + 1
bins = np.linspace(min_edge, max_edge, Nplus1)
# Obtain histogram from primary distributions
hist, bin_edges = np.histogram(points,bins,density=True)
bin_centres = (bin_edges[:-1] + bin_edges[1:])/2
# Initial guess
p0 = [5, 2, 4]
coeff, var_matrix = curve_fit(gauss.gaussFun, bin_centres, hist, p0=p0)
# Get the fitted curve
hist_fit = gauss.gaussFun(bin_centres, *coeff)
# Error on the estimates
error_parameters = np.sqrt(np.array([var_matrix[0][0],var_matrix[1][1],var_matrix[2][2]]))
# Obtain the error for each value: A,mu,sigma
A_std = (coeff[0]-A)/error_parameters[0]
mean_std = ((coeff[1]-mean)/error_parameters[1])
sigma_std = (np.abs(coeff[2])-sigma)/error_parameters[2]
# Store results in container
error_vec_A.append(A_std)
error_vec_mean.append(mean_std)
error_vec_sigma.append(sigma_std)
# Plot the distribution of each estimator
plt.figure(1); plt.hist(error_vec_A,bins,normed=True); plt.title('Pull of A')
plt.figure(2); plt.hist(error_vec_mean,bins,normed=True); plt.title('Pull of Mu')
plt.figure(3); plt.hist(error_vec_sigma,bins,normed=True); plt.title('Pull of Sigma')
# Store key information regarding distribution
mean_A = np.mean(error_vec_A); sigma_A = np.std(error_vec_A)
mean_mu = np.mean(error_vec_mean); sigma_mu = np.std(error_vec_mean)
mean_sigma = np.mean(error_vec_sigma); sigma_sig = np.std(error_vec_sigma)
info = np.array([[mean_A,sigma_A],[mean_mu,sigma_mu],[mean_sigma,sigma_sig]])
My problem is I don't know how to use python to format the data into a table. I have to manually go into the variables and go to google docs to present the information. I'm just wondering how I can do that using pandas or some other library.
Here's an example of the manual insertion:
Trial 1 Trial 2 Trial 3
Seed [0.2,0,1] [10,2,5] [5,2,4]
Bins for individual runs 20 20 20
Points Thrown 1000 1000 1000
Number of Runs 5000 5000 5000
Bins for pull dist fit 20 20 20
Mean_A -0.11177 -0.12249 -0.10965
sigma_A 1.17442 1.17517 1.17134
Mean_mu 0.00933 -0.02773 -0.01153
sigma_mu 1.38780 1.38203 1.38671
Mean_sig 0.05292 0.06694 0.04670
sigma_sig 1.19411 1.18438 1.19039
I would like to automate this table so If I change my parameters in my code, I get a new table with that new data.
I would go with the CSV module to generate a presentable table.
if you're not already using it, the IPython notebook is really good for rendering rich display formats. It's really good in a lot of other ways, too.
It will render pandas dataframe objects as an html table when they're either the last, unreturned value in a cell or if you explicitly call Ipython.core.display.display function instead of print.
If you're not already using pandas, I highly recommend it. It's basically a wrapper around 2D & 3D numpy arrays; it's just as fast, but it has nice naming conventions, data grouping and filtering funcitons, and some other cool stuff.
At that point, it depends on how you want to present it. You can use nbconvert to render a whole notebook as static html or a pdf. You can copy-paste the html table into Excel or PowerPoint or an E-mail.