The Foundry Nuke – Issues with `elif` and `else` statements - python

So to make it simple, I'm writing a script in NUKE which aligns the selected nodes in the node graph into one straight line in the Y-axis. I'm having issues where I'm writing the elif statement which is either not functioning as I want to or it is giving me a syntax error.
So the basis of the function is:
ELSE STATEMENT - when selected only one node - error message pops up saying user has to select more than one node
ELIF STATEMENT - when selected two or more nodes which are in the same Y-axis - message showing they are already aligned
IF STATEMENT - when selected two or more nodes in different Y-axis - it should properly align all the nodes in a straight line
# Getting selected nodes and making them into a list
selNodes = nuke.selectedNodes()
list = []
for node in selNodes:
n = node['ypos'].value()
list.append(n)
# Defining the actual function
def alignY():
# Aligning the selected nodes using average position of every node.
# Must select more than one node in order to get an average.
if len(selNodes) > 1:
total = sum(list)
average = total / len(selNodes)
for node in selNodes:
n = node['ypos'].setValue(average)
# Getting the position of a single node from the list
firstNodePostion = list[0]
# Checking position of the single node is equivalent to the average
# To prevent nodes aligning again)
elif average == firstNodePostion:
nuke.message("Nodes already Aligned")
# When no nodes or only one node is selected this message pops up
else:
nuke.message("Select Two or more Nodes")
alignY()

You have to indent the lines of you code according to Python rules.
So you need to use 4 spaces per indentation level – look at PEP 8.
import nuke
selNodes = nuke.selectedNodes()
list = []
for node in selNodes:
n = node['ypos'].value()
list.append(n)
def alignY():
if len(selNodes) > 1:
total = sum(list)
average = total / len(selNodes)
for node in selNodes:
n = node['ypos'].setValue(average)
firstNodePostion = list[0]
elif average == firstNodePostion:
nuke.message("Nodes already Aligned")
else:
nuke.message("Select Two or more Nodes")
alignY()
Now alignY() method works as expected.

Your problem is that you have a statement that is sitting between the if and the elif, which can cause a syntax error.
It's hard to tell though, because you have not provided the exact error message, but from a syntactical point, there shouldn't be another statement separating the if and the elif.

Related

Why my solution is unable to solve 8puzzle problem for boards that require more than 1 move?

I am trying to solve 8 puzzle problem in python given here in this assignment -https://www.cs.princeton.edu/courses/archive/fall12/cos226/assignments/8puzzle.html
My goal state is a little different from what is mentioned in the assignment -
#GOAL STATE
goal_state = [[0,1,2],[3,4,5],[6,7,8]]
The buggy part, it seems, is the isSolvable function. It is implemented correctly but while testing the board, it considers the goal state to be the one in which relative order is maintained and blank can be anywhere. So it might be the case that a board is solvable but it might not lead to the current defined goal state. So I am unable to think of a method in which I can test for all the possible goal states while running the solver function *
Also, my solver function was wrongly implemented. I was only considering the neighbor which had the minimum manhattan value and when I was hitting a dead end, I was not considering other states. This can be done by using a priority queue. I am not exactly sure as to how to proceed to implement it. I have written a part of it(see below) which is also kind of wrong as I not pushing the parent into the heap. Kindly provide me guidance for that.
Here is my complete code -
https://pastebin.com/q7sAKS6a
Updated code with incomplete solver function -
https://pastebin.com/n4CcQaks
I have used manhattan values to calculate heuristic values and hamming value to break the tie.
my isSolvable function, manhattan function and solver function:
isSolvable function -
#Conditions for unsolvability -->
#https://www.geeksforgeeks.org/check-instance-8-puzzle-solvable/
def isSolvable(self):
self.one_d_array = []
for i in range(0,len(self.board)):
for j in range(0,len(self.board)):
self.one_d_array.append(self.board[i][j])
inv_count = 0
for i in range(0,len(self.one_d_array)-1):
for j in range(i+1, len(self.one_d_array)):
if (self.one_d_array[i] != 0 and self.one_d_array[j] != 0 and self.one_d_array[i] > self.one_d_array[j]):
inv_count = inv_count + 1
if(inv_count % 2 == 0):
print("board is solvable")
return True
else:
print("board is not solvable")
return False
Manhattan function
def manhattan_value(self,data=None):
manhattan_distance = 0
for i in range(0,len(data)):
for j in range(0,len(data)):
if(data[i][j] != self.goal_state[i][j] and data[i][j] != 0):
#correct position of the element
x_goal , y_goal = divmod(data[i][j],3)
manhattan_distance = manhattan_distance + abs(i-x_goal) + abs(j-y_goal)
return manhattan_distance
Updated Solver function
#implement A* algorithm
def solver(self):
moves = 0
heuristic_value = []
prev_state = []
curr_state = self.board
output = []
heap_array = []
store_manhattan_values = []
if(curr_state == self.goal_state):
print("goal state reached!")
print(curr_state)
print("number of moves required to reach goal state --> {}".format(moves))
else:
while(True):
min_heuristic_value = 99999999999
min_pos = None
moves = moves + 1
output = self.get_neighbours(curr_state)
for i in range(len(output)):
store_manhattan_values.append([self.manhattan_value(output[i]),i])
#print(store_manhattan_values)
for i in range(len(store_manhattan_values)):
heapq.heappush(heap_array,store_manhattan_values[i])
#print(heap_array)
#print(heapq.heappop(heap_array)[1])
#if(moves > 1):
# return
return
Please refer to the PASTEBIN link for complete code and all the references (https://pastebin.com/r7TngdFc).
Updated code with incomplete solver function -
https://pastebin.com/n4CcQaks
In the given link for my code (based on my tests and debugging so far) -
These functions are working correctly - manhatten_value, hamming_value, append_in_list, get_neighbours
What does these functions do -
isSolvable - tells if the board can be solved or not
manhattan_value - calculates the manhattan value of the board passed to it.
hamming_value - calculates the hamming value of the board passed to it.
append_in_list - helper function for getting neighbours. It swaps values then save the resultant state in an array and then reswaps them to return to original position for further swapping and getting other possible states.
get_neighbours - gets all the possible neighbors which can be formed by swapping places with blank element(0 element).
solver - implements the A* algorithm
I am unable to find my mistake. Kindly guide me in this problem. Thank you in advance for your help!
I am apologizing in advance as I am unable to produce a minimal version of my code for this problem. I can not think of any way to use all the functions and produce a minimal version of the code.
(Note, this answer is different than the earlier revision about which many of the comments below were relating to.)
I don't see how the current code implements a queue. It seems like the while loop in the solver picks one new board state each time from a list of possible moves, then considers the next list generated by this new board state.
On the other hand, a priority queue, from what I understand, would have all the (valid) neighbours from the current board state inserted into it and prioritised such that the next chosen board state to be removed from the queue and examined will be the one with highest priority.
(To be completely sure in debugging, I might add a memoisation to detect if the code ends up also revisiting board states -- ah, on second thought, I believe the stipulation in the assignment description that the number of current moves be added to the priority assignment would rule out the same board state being revisited if the priority queue is correctly observed, so memoisation may not be needed.)

Variable table width with .format

I'm trying to display data from a csv in a text table. I've got to the point where it displays everything that I need, however the table width still has to be set, meaning if the data is longer than the number set then issues begin.
I currently print the table using .format to sort out formatting, is there a way to set the width of the data to a variable that is dependant on the length of the longest piece of data?
for i in range(len(list_l)):
if i == 0:
print(h_dashes)
print('{:^1s}{:^26s}{:^1s}{:^26s}{:^1s}{:^26s}{:^1s}{:^26s}{:^1s}'.format('|', (list_l[i][0].upper()),'|', (list_l[i][1].upper()),'|',(list_l[i][2].upper()),'|', (list_l[i][3].upper()),'|'))
print(h_dashes)
else:
print('{:^1s}{:^26s}{:^1s}{:^26s}{:^1s}{:^26s}{:^1s}{:^26s}{:^1s}'.format('|', list_l[i][0], '|', list_l[i][1], '|', list_l[i][2],'|', list_l[i][3],'|'))
I realise that the code is far from perfect, however I'm still a newbie so it's piecemeal from various tutorials
You can actually use a two-pass approach to first get the correct lengths. As per your example with four fields per line, the following shows the basic idea you can use.
What follows is an example of the two-pass approach, first to get the maximum lengths for each field, the other to do what you're currently doing (with the calculated rather than fixed lengths):
# Can set MINIMUM lengths here if desired, eg: lengths = [10, 0, 41, 7]
lengths = [0] * 4
fmtstr = None
for pass in range(2):
for i in range(len(list_l)):
if pass == 0:
# First pass sets lengths as per data.
for field in range(4):
lengths[field] = max(lengths[field], len(list_l[i][field])
else:
# Second pass prints the data.
# First, set format string if not yet set.
if fmtstr is None:
fmtstr = '|'
for item in lengths:
fmtstr += '{:^%ds}|' % (item)
# Now print item (and header stuff if first item).
if i == 0: print(h_dashes)
print(fmtstr.format(list_l[i][0].upper(), list_l[i][1].upper(), list_l[i][2].upper(), list_l[i][3].upper()))
if i == 0: print(h_dashes)
The construction of the format string is done the first time you process an item in pass two.
It does so by taking a collection like [31,41,59] and giving you the string:
|{:^31s}|{:^41s}|{:^59s}|
There's little point using all those {:^1s} format specifiers when the | is not actually a varying item - you may as well code it directly into the format string.

Index Out Of Range When Artificially Limited

when I run this program, sometimes I receive an error.This error however is not possible as I am using an 8x8 grid and I limit the inputs so that they can only be numbers from 0-7, to obey the fact that list indexes start at 0.
The user must input coordinates (1-8),(A-H) and the program will check to see if those coordinates are correct, by systematically going through the CompShips list and repeatedly comparing those coordinates to ones given by the user. If the cords match, then a message will appear and a "Z" will change to an "X" on those coordinates, indicating a HIT. If the guess does not match, a "Z" will change to an "M" on those coordinates indicating a MISS.
CompShips=[[1,0],[1,1],[2,2],[2,3],[2,4],[3,0],[3,1],[3,2],[5,4],[5,5],[5,6],[5,7],[1,7],[2,7],[3,7],[4,7],[5,7]]
FRow1=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow2=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow3=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow4=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow5=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow6=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow7=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow8=["Z","Z","Z","Z","Z","Z","Z","Z",]
def PrintFireBoard():
print(Index)
print(FRow1)
print(FRow2)
print(FRow3)
print(FRow4)
print(FRow5)
print(FRow6)
print(FRow7)
print(FRow8)
FireBoard=[FRow1,FRow2,FRow3,FRow4,FRow5,FRow6,FRow7,FRow8]
while len(CompShips) !=0 or CompSuccess==17:
FireRow=input("Please Choose The Row That You Wish To Fire Upon (1-8) ")
FireIndex=input("Please Choose The Column That You Wish To Fire Upon (A-H) ")
#As Lists start at 0
FireRow=int(FireRow)-1
if FireIndex==("A"):
FireIndex=0
elif FireIndex==("B"):
FireIndex=1
elif FireIndex==("C"):
FireIndex=2
elif FireIndex==("D"):
FireIndex=3
elif FireIndex==("E"):
FireIndex=4
elif FireIndex==("F"):
FireIndex=5
elif FireIndex==("G"):
FireIndex=6
elif FireIndex==("H"):
FireIndex=7
Guess=[FireRow,FireIndex]
#Check To See If Correct
UserSuccess=0
for i in CompShips:
if Guess==i:
CompShips.remove(Guess)
UserSuccess=1
else:
pass
if UserSuccess==1:
print("HIT")
print(FireRow)
print(FireIndex)
FireBoard[[FireRow][FireIndex]]=("H")
PrintFireBoard()
else:
print("MISS")
print(FireRow)
print(FireIndex)
FireBoard[[FireRow][FireIndex]]=("M")
PrintFireBoard()
I receive the error:
IndexError: string index out of range
Looks like these two lines
FireBoard[[FireRow][FireIndex]]=("H")
FireBoard[[FireRow][FireIndex]]=("M")
should be
FireBoard[FireRow][FireIndex]="H"
FireBoard[FireRow][FireIndex]="M"
Explanation: In your old code, FireBoard[[FireRow][FireIndex]]=("H")
[FireRow][FireIndex] means, given a list [FireRow] (which contains just one element), get the FireIndex-th element. This is not what you're trying to do.
For example [3][0] returns 3, and [3][1] gives IndexError.
Take a look at How to define a two-dimensional array in Python
Also note that ("H") is the same as the string "H". There is no need to add parentheses.
Here is a much cleaner code!
CompShips=[[1,0],[1,1],[2,2],[2,3],
[2,4],[3,0],[3,1],[3,2],
[5,4],[5,5],[5,6],[5,7],
[1,7],[2,7],[3,7],[4,7],
[5,7]]
FRow=[["Z"]*8]*8 #1 More Pythonic
def PrintFireBoard():
#print(Index)
for i in range(0,8):
print(FRow[i])
FireBoard=FRow[:] #NOTE THIS ONE!!!
mydict = {}
for i,key in enumerate(["A","B","C","D","E","F","G","H"]): #2 More Pythonic
mydict[key] = i
while len(CompShips) !=0 or CompSuccess==17:
FireRow=input("Please Choose The Row That You Wish To Fire Upon (1-8) ")
FireIndex=input("Please Choose The Column That You Wish To Fire Upon (A-H) ")
FireRow=int(FireRow)-1
FireIndex = mydict[FireIndex]
Guess=[FireRow,FireIndex]
print(Guess)
UserSuccess=0
for i in CompShips:
if Guess==i:
CompShips.remove(Guess)
UserSuccess=1
else:
pass
if UserSuccess==1:
print("HIT")
print(FireRow,FireIndex)
FireBoard[FireRow][FireIndex]="H" #3 your problem here
PrintFireBoard()
else:
print("MISS")
print(FireRow,FireIndex)
FireBoard[FireRow][FireIndex]="M"
PrintFireBoard()
1) As explained in the comments that's just a more nicer way to create a list of lists!. Remember DRY principle! Do Not Repeat yourself!
2) Instead of having all that if else to convert the 'A' to 0. You can use a dictionary lookup instead!
3) Your problem seems to be here! correct this to FireBoard[FireRow][FireIndex]="H"
PS: NOTE THIS ONE!!!: I'm not just making FireBoard as an alias to FRow! I'm copying it into a FireBoard as a new list! There's a subtle difference read about it here. I'm doing this incase you don't want your original FRow list to be modified!
The indentation in your question was off. I think that all the code from
Guess=[FireRow,FireIndex]
until the end should be preceded by 4 spaces.
I've removed print(Index) since it was not defined.
To access FireBoard use:
FireBoard[FireRow][FireIndex]
Instead of
FireBoard[[FireRow][FireIndex]]
This should be working
CompShips=[[1,0],[1,1],[2,2],[2,3],[2,4],[3,0],[3,1],[3,2],[5,4],
[5,5],[5,6],[5,7],[1,7],[2,7],[3,7],[4,7],[5,7]]
FRow1=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow2=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow3=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow4=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow5=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow6=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow7=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow8=["Z","Z","Z","Z","Z","Z","Z","Z",]
def PrintFireBoard():
print(FRow1)
print(FRow2)
print(FRow3)
print(FRow4)
print(FRow5)
print(FRow6)
print(FRow7)
print(FRow8)
FireBoard=[FRow1,FRow2,FRow3,FRow4,FRow5,FRow6,FRow7,FRow8]
while len(CompShips) !=0 or CompSuccess==17:
FireRow=input("Please Choose The Row That You Wish To Fire Upon (1-8) ")
FireIndex=input("Please Choose The Column That You Wish To Fire Upon (A-H) ")
#As Lists start at 0
FireRow=int(FireRow)-1
if FireIndex==("A"):
FireIndex=0
elif FireIndex==("B"):
FireIndex=1
elif FireIndex==("C"):
FireIndex=2
elif FireIndex==("D"):
FireIndex=3
elif FireIndex==("E"):
FireIndex=4
elif FireIndex==("F"):
FireIndex=5
elif FireIndex==("G"):
FireIndex=6
elif FireIndex==("H"):
FireIndex=7
Guess=[FireRow,FireIndex]
#Check To See If Correct
UserSuccess=0
for i in CompShips:
if Guess==i:
CompShips.remove(Guess)
UserSuccess=1
else:
pass
if UserSuccess==1:
print("HIT")
print(FireRow)
print(FireIndex)
FireBoard[FireRow][FireIndex]=("H")
PrintFireBoard()
else:
print("MISS")
print(FireRow)
print(FireIndex)
FireBoard[FireRow][FireIndex]=("M")
PrintFireBoard()

Perfect Binary Tree with correct data

I am having a problem trying to fill the data a perfect binary tree with a known number of nodes with the correct data. Basically, I have an implementation that creates this:
7
5 6
1 2 3 4
However, I am looking to create a tree like this:
7
3 6
1 2 4 5
My current implementation for inserting the nodes of a tree is as follows.
def _add_node(self, val, ref = None):
# reference to root of tree
ref = self.root if ref is None else ref
if ref.right is None:
ref.right = Node(val, ref)
return
elif ref.left is None:
ref.left = Node(val, ref)
return
else:
parent = (val - 1) / 2
if parent % 2 == 0:
self._add_node(val, ref.left)
else:
self._add_node(val, ref.right)
Given x nodes I create a tree using range(x) and calling add_node(i) for each iteration. This works fine except its order is incorrect.
For the life of me I cannot figure out an easy way to set the values to represent the bottom layout rather than the top. Can anyone help me out?
This seems to be an issue with the order that you are entering data in. How are you passing in the data?
Also think about your implementation. You check to see whether the right child is empty and if it is you place the node there. However, if it isn't you move on to the left node. This is where the issue is happening.
Assuming you are passing in the data in reverse chronological order you start with 7 at the root. Then you move to 6 which you place in the right node. Then move on to 5; you check to see whether the right node is empty, which is isn't because it is filled with 6, so you move on to check if the left node is empty and find that it is. So you place 5 there.
Do you see the issue?
You need to figure out a way to get around this issue, but hopefully this was good in helping you debug.
Good Luck!

Python - How to track (add/remove) lots of class instances over mulitple iterations?

I am building a dynamic map of earthquakes, using the vtk library.
I've already made a static one, (see here: https://github.com/yacobuk/QuakeCloud and here: http://www.youtube.com/watch?v=4HVdTcI_ozI) so I know the basic idea works, but now I want to try and show the quakes over time.
I have some code examples that show me how to update the frame, and how to add / remove objects, but I'm stuck on figuring out how to spin up an instance, track it for a few periods, then remove it.
The basic add/ remove code looks like this:
for point_and_mag in pm.points_mag:
time.sleep(0.5)
mag = point_and_mag[1]
point = point_and_mag[0]
if mag > 2:
pointCloud = VtkPointCloud(pm)
pointCloud.addPoint(point, math.log(mag)*10)
renderer.AddActor(pointCloud.vtkActor)
renderer.ResetCamera()
renderWindow.Render()
time.sleep(0.3)
renderer.RemoveActor(pointCloud.vtkActor)
renderer.ResetCamera()
renderWindow.Render()
But of course, this only allows one object at a time (an instance of pointCloud.vtkActor via renderer.AddActor(pointCloud.vtkActor) waits a while, then removes it with renderer.RemoveActor(pointCloud.vtkActor)
How can I add a number of actors (I'm going to use 10 min interval, and there was as many as 5 quakes in that time), tag it with a counter, increment the counter at every loop iteration, and when it reaches 5 iterations, remove the actor?
There is some more context to this question here: Python/vtk - set each point size individually in a vtkPolyData object?
A possible(untested) solution might be:
from collections import deque
# The number 5 indicates for how many iterations the actors should be rendered.
rendered_actors = deque([None] * 5, maxlen=5)
for point_and_mag in pm.points_mag:
if rendered_actors[-1] is not None:
renderer.removeActor(rendered_actors[-1])
renderer.ResetCamera()
renderWindow.Render()
time.sleep(0.5)
mag = point_and_mag[1]
point = point_and_mag[0]
if mag > 2:
pointCloud = VtkPointCloud(pm)
pointCloud.addPoint(point, math.log(mag)*10)
rendered_actors.appendleft(pointcloud.vtkActor)
renderer.AddActor(pointCloud.vtkActor)
renderer.ResetCamera()
renderWindow.Render()
else:
rendered_actors.appendleft(None)
This code creates a deque(which is a double-linked list) of length 5. The actors are inserted at the left of this deque and at each iteration the rightmost value, if it is an "actor", it is removed from the scene and the scene is re-rendered.
Note that I don't have vtk so I cannot test this code.
A small style note: this is really unpythonic code-style:
for point_and_mag in pm.points_mag:
mag = point_and_mag[1]
point = point_and_mag[0]
Use tuple-unpacking:
for point, mag in pm.points_mag:
# ...
if mag > 2:
# ...

Categories