Align 3D object to direction vector - python-3.x

I represent a vtk poly data object that I read with vtkPlyReader and want to align it to given normalized direction vector, so that its orientation matches with that vector.
directionVector = np.array([-0.1134, -0.0695, 0.9911])
plyReader = vtk.vtkPLYReader()
plyReader.SetFileName(filePath)
transform = vtk.vtkTransform()
transform.RotateWXYZ(-90, 0, 0, 1) #initial rotation
transformFilter = vtk.vtkTransformPolyDataFilter()
transformFilter.SetTransform(transform)
transformFilter.SetInputConnection(plyReader.GetOutputPort())
transformFilter.Update()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(transformFilter.GetOutputPort())
mapper.ScalarVisibilityOn()
mapper.Update()
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.Modified()
renderer.AddActor(actor)
I know that I should use the Rotate() function from vtkTransform but don't know how to align it.

You can try something like:
rotation = 0 # around new axis
initaxis = [0,0,1] # old object's axis
crossvec = np.cross(initaxis, newaxis)
angle = np.arccos(np.dot(initaxis, newaxis))
T = vtk.vtkTransform()
T.PostMultiply()
T.Translate(-pos)
if rotation:
T.RotateWXYZ(rotation, initaxis)
T.RotateWXYZ(np.rad2deg(angle), crossvec)
T.Translate(pos)
E.g. vedo uses the above
from vedo import Cube, show
c0 = Cube(side=2).lw(1)
c1 = c0.clone().alpha(0.2).c('tomato')
c1.orientation([1,1,1], rotation=20).pos([2,2,0])
show(c0, c1, axes=1)

Related

How could I edit my code to plot 4D contour something similar to this example in python?

Similar to many other researchers on stackoverflow who are trying to plot a contour graph out of 4D data (i.e., X,Y,Z and their corresponding value C), I am attempting to plot a 4D contour map out of my data. I have tried many of the suggested solutions in stackover flow. From all of the plots suggested this, and this were the closest to what I want but sill not quite what I need in terms of data interpretation. Here is the ideal plot example: (source)
Here is a subset of the data. I put it on the dropbox. Once this data is downloaded to the directory of the python file, the following code will work. I have modified this script from this post.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
#####Importing the data
df = pd.read_csv('Data_4D_plot.csv')
do_random_pt_example = False;
index_x = 0; index_y = 1; index_z = 2; index_c = 3;
list_name_variables = ['x', 'y', 'z', 'c'];
name_color_map = 'seismic';
if do_random_pt_example:
number_of_points = 200;
x = np.random.rand(number_of_points);
y = np.random.rand(number_of_points);
z = np.random.rand(number_of_points);
c = np.random.rand(number_of_points);
else:
x = df['X'].to_numpy();
y = df['Y'].to_numpy();
z = df['Z'].to_numpy();
c = df['C'].to_numpy();
#end
#-----
# We create triangles that join 3 pt at a time and where their colors will be
# determined by the values of their 4th dimension. Each triangle contains 3
# indexes corresponding to the line number of the points to be grouped.
# Therefore, different methods can be used to define the value that
# will represent the 3 grouped points and I put some examples.
triangles = mtri.Triangulation(x, y).triangles;
choice_calcuation_colors = 2;
if choice_calcuation_colors == 1: # Mean of the "c" values of the 3 pt of the triangle
colors = np.mean( [c[triangles[:,0]], c[triangles[:,1]], c[triangles[:,2]]], axis = 0);
elif choice_calcuation_colors == 2: # Mediane of the "c" values of the 3 pt of the triangle
colors = np.median( [c[triangles[:,0]], c[triangles[:,1]], c[triangles[:,2]]], axis = 0);
elif choice_calcuation_colors == 3: # Max of the "c" values of the 3 pt of the triangle
colors = np.max( [c[triangles[:,0]], c[triangles[:,1]], c[triangles[:,2]]], axis = 0);
#end
#----------
###=====adjust this part for the labeling of the graph
list_name_variables[index_x] = 'X (m)'
list_name_variables[index_y] = 'Y (m)'
list_name_variables[index_z] = 'Z (m)'
list_name_variables[index_c] = 'C values'
# Displays the 4D graphic.
fig = plt.figure(figsize = (15,15));
ax = fig.gca(projection='3d');
triang = mtri.Triangulation(x, y, triangles);
surf = ax.plot_trisurf(triang, z, cmap = name_color_map, shade=False, linewidth=0.2);
surf.set_array(colors); surf.autoscale();
#Add a color bar with a title to explain which variable is represented by the color.
cbar = fig.colorbar(surf, shrink=0.5, aspect=5);
cbar.ax.get_yaxis().labelpad = 15; cbar.ax.set_ylabel(list_name_variables[index_c], rotation = 270);
# Add titles to the axes and a title in the figure.
ax.set_xlabel(list_name_variables[index_x]); ax.set_ylabel(list_name_variables[index_y]);
ax.set_zlabel(list_name_variables[index_z]);
ax.view_init(elev=15., azim=45)
plt.show()
Here would be the output:
Although it looks brilliant, it is not quite what I am looking for (the above contour map example). I have modified the following script from this post in the hope to reach the required graph, however, the chart looks nothing similar to what I was expecting (something similar to the previous output graph). Warning: the following code may take some time to run.
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
df = pd.read_csv('Data_4D_plot.csv')
x = df['X'].to_numpy();
y = df['Y'].to_numpy();
z = df['Z'].to_numpy();
cc = df['C'].to_numpy();
# convert to 2d matrices
Z = np.outer(z.T, z)
X, Y = np.meshgrid(x, y)
C = np.outer(cc.T,cc)
# fourth dimention - colormap
# create colormap according to cc-value
color_dimension = C # change to desired fourth dimension
minn, maxx = color_dimension.min(), color_dimension.max()
norm = matplotlib.colors.Normalize(minn, maxx)
m = plt.cm.ScalarMappable(norm=norm, cmap='jet')
m.set_array([])
fcolors = m.to_rgba(color_dimension)
# plot
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X,Y,Z, rstride=1, cstride=1, facecolors=fcolors, vmin=minn, vmax=maxx, shade=False)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.show()
Now I was wondering from our kind community and experts if you can help me to plot a contour figure similar to the example graph (image one in this post), where the contours are based on the values within the range of C?

vtk: why the world point from vtkPropPicker and vtkCoordinate is different

I am using vtk in my project, and I need to convert the display & world coordinate. I find vtk provide vtkPropPicker and vtkCoordinate, and both of them can convert the display coordinate to world coordinate. However, I find the result is different.
The test code is:
import vtk
cone = vtk.vtkConeSource()
cone.SetCenter(150, 150, 0)
cone.SetHeight(100)
cone.SetRadius(50)
cone.Update()
coneMapper = vtk.vtkPolyDataMapper()
coneMapper.SetInputData(cone.GetOutput())
coneMapper.Update()
coneActor = vtk.vtkActor()
coneActor.SetMapper(coneMapper)
ren = vtk.vtkRenderer()
ren.AddActor(coneActor)
ren.SetBackground(0.1, 0.2, 0.4)
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(ren)
renWin.SetSize(400, 400)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
renWin.Render()
X = 100
Y = 100
picker = vtk.vtkPropPicker()
picker.Pick(X, Y, 0, ren)
pickerWorld = picker.GetPickPosition()
print('world point from vtkPropPicker: ', pickerWorld)
coordinate = vtk.vtkCoordinate()
coordinate.SetCoordinateSystemToDisplay()
coordinate.SetValue(X, Y)
coorWorld = coordinate.GetComputedWorldValue(ren)
print('world point from vtkCoordinate: ', coorWorld)
Please have a look for the above code. I print the world point from vtkPropPicker and vtkCoordinate, and the result is different:
world point from vtkPropPicker: (108.0365506828649, 108.0365506828649, 7.141902959080343)
world point from vtkCoordinate: (119.0534474476644, 119.0534474476644, 89.37313989502613)
Why there are different? And which one is correct?
GetComputedWorldValue seems to be picking some bounding box:
# ...
from vedo import *
show(coneActor,
Point(pickerWorld, c='green'),
Point(coorWorld, c='red'),
axes=1,
)
although the two points are not on the same vertical (not sure why so).

What is equivalent of seaborn's hue in Matplotlib?

May I ask what is the equivalent of hue in Matplotlib? I have a line of seaborn code and would need to convert it into Matplotlib format. Each box corresponds to 1 ID at that time. How do i create a legend as well? The dataframe dataset_filtered has 3 columns: time_window (x axis), id and LagTime which is y axis.
sns.catplot(x='time_window', hue='ID', y='LagTime', data= dataset_filtered, kind="box",showfliers=False)
This is what I have written so far but it is not working...
# Generate a color dictionary using RGB for each Id
colors = []
for num in range(len(unique_id)):
num = num + 1
color = (1/num, 1/num, 1/num)
colors.append(color)
color_dictionary = dict(zip(unique_id, colors))
plt.figure(figsize=(30,15))
for time_window in dataset_filtered.index.unique():
dataset_plot = dataset_filtered.loc[time_window]
box = dataset_plot.boxplot('LagTime',patch_artist=True,boxprops=dict(facecolor=color_dictionary['id']),medianprops=dict(color='black'),labels='id')
plt.xlim(-0.5,8)
plt.xticks(np.arange(0.2,10,0.5),dataset_filtered.index.unique())
handles, labels = plt.gca().get_legend_handles_labels()
by_label = OrderedDict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())
plt.xticklabels()

how to adjust width of bokeh heatmap and remove white space around

I would like to change the width of the heatmap cell so that its dimensions are square (even). Ideally, the cells are small and square so that I can fit several heatmaps with just one column of data. I want to reproduce something like this:
My current code makes one heatmap that is too wide and there is lots of white space, as well as a strange y position that cuts off the bottom cell. Not sure what's going on. Thanks.
def genHeatMap():
colours = ['#67d33d',
'#76d74f',
'#84da5f',
'#91de6e',
'#9ce17b',
'#a6e488',
'#b1e795',
'#bbeaa1',
'#91de6e',
'#9ce17b']
values = [1.0,
0.17647058823529413,
0.08021390374331551,
0.04054054054054054,
0.06,
0.07894736842105263,
0.07317073170731707,
0.05813953488372093,
0.1320754716981132,
0.0]
y_labels=['103', '134', '140', '185', '235', '292', '299', '431', '566', '659']
y = list(range(10))
x = ['a'] * 10
df = {'xs':x,'ys':y,'value':values,'colour':colours,'labels':y_labels}
p = figure(x_range='a',y_range=y_labels,plot_width=300,plot_height=300,
tooltips = [('CSID', f'#labels-103'), ('Tanimoto', '#value')])
p.rect('xs', 'ys', width=1, height=1, source=df,color='colour', line_color="black")
p.toolbar.logo = None
p.min_border_bottom = 20
p.min_border_left = 0
p.min_border_right = 0
p.min_border_top = 0
p.xaxis.major_tick_line_color = None
p.xaxis.minor_tick_line_color = None
p.xaxis.major_label_text_font_size = '0pt'
return p
Set p.x_range.range_padding = 0
https://docs.bokeh.org/en/latest/docs/reference/models/ranges.html#bokeh.models.ranges.FactorRange.range_padding

How to find superpixels' centroid using masked region?

Newbie here! I'm working with python plus opencv and skimage packages. I've segmented an image in superpixels using:
segments = slic(image, n_segments=numSegments, sigma=1, convert2lab=True)
I can access every superpixel with:
#FOR-LOOP-1
for v in np.unique(segments):
#create a mask to access one region at the time
mask = np.ones(image.shape[:2])
mask[segments == v] = 0
#my function to calculate mean of A channel in LAB color space
A = mean_achannel(img, mask)
Now I'd like to get the coordinates associated with each superpixel's centroid, how can I do that?
I tried using:
from skimage.measure import regionprops
#FOR-LOOP-2
regions = regionprops(segments)
for props in regions:
cx, cy = props.centroid # centroid coordinates
But I can't understand how to link each region in the "FOR-LOOP-2" with the right one in the "FOR-LOOP-1". How can I calculate each region centroid inside "FOR-LOOP-1"?
All the desired values can be found using regionprops in for-loop-2:
from skimage.measure import regionprops
#FOR-LOOP-2
regions = regionprops(segments,
intensity_image=img[..., 1])
for props in regions:
cx, cy = props.centroid # centroid coordinates
v = props.label # value of label
mean_a = props.mean_intensity

Resources