Getting the exact data index from a click on pyqt5graph image (not just pixel value) - pyqtgraph

I am new to PyqtGraph ( Infact this is my first time)
I have a Qt designer file which I import in my python code. I 6 windows in which I plot a 42x22 (different sizes) as an inmage, these have been promoted the graphicview.
I have a data set which is 6x42x22 and so I use a for loop to plot the 6 images
for n in range(imageStackSize):
self.glayout = pg.GraphicsLayout()
self.vb = self.glayout.addViewBox()
self.vb.setAspectLocked(lock=True, ratio=self.aspect_ratio)
img_temp = image[n, :, :]
and...
``
img = pg.ImageItem(img_temp, lut=self.jet_lut)
if n == 0:
self.ui.Channel1_img.setCentralItem(self.glayout)
self.vb.addItem(img)
elif n == 1:
self.ui.Channel2_img.setCentralItem(self.glayout)
self.vb.addItem(img)
elif n == 2:
self.ui.Channel3_img.setCentralItem(self.glayout)
self.vb.addItem(img)
elif n == 3:
self.ui.Channel4_img.setCentralItem(self.glayout)
self.vb.addItem(img)
elif n == 4:
self.ui.Channel5_img.setCentralItem(self.glayout)
self.vb.addItem(img)
elif n == 5:
self.ui.Channel6_img.setCentralItem(self.glayout)
self.vb.addItem(img)
After this I am trying to click on one of the image (ideally I would like to make it such that I can click any of the six images) to get the (6,x,y) coordinated the first dimension does not matter. In order to achieve this I did
self.ui.Channel1_img.scene().sigMouseClicked.connect(self.onClick)
#self.ui.Channel2_img.scene().sigMouseClicked.connect(self.onClick)
#self.ui.Channel3_img.scene().sigMouseClicked.connect(self.onClick)
#self.ui.Channel4_img.scene().sigMouseClicked.connect(self.onClick)
#self.ui.Channel5_img.scene().sigMouseClicked.connect(self.onClick)
#self.ui.Channel6_img.scene().sigMouseClicked.connect(self.onClick)
#self.ui.PMTVoltage_plt.scene().sigMouseClicked.connect(self.onClick)
def onClick(self, event):
print("clicked")
and then I tried
items = self.ui.Channel1_img.imageItem.mapFromViewToItem(event.pos())
and
items = self.ui.Channel1_img.imageItem.mapFromSceneToView(event.pos())
but the prog just crashes. I read somewhere that the coordinates are in the viewbox, but I cant seem to find the viewbox or vb in the self.ui.Channel1_img
I went through the entire ui variable in debug to look for vb or image Item and could not find it.
infact the only thing I found was,
items = {dict} {<pyqtgraph.graphicsItems.ViewBox.ViewBox.ViewBox
object at 0x000001CF73888CA8>: [(0, 0)]}
<pyqtgraph.graphicsItems.ViewBox.ViewBox.ViewBox object at
0x000001CF73888CA8> (1990508186792) = {list} <class 'list'>: [(0, 0)]
0 = {tuple} <class 'tuple'>: (0, 0)
0 = {int} 0
1 = {int} 0
__len__ = {int} 2
__len__ = {int} 1
__len__ = {int} 1
what am I missing? Any help is appreciated

Ok I figured it out, here is my solution for some who may have same question
I plot the data using it as imageItem
vb = pg.ViewBox()
self.ui.PMTVoltage_plt.useOpenGL()
self.ui.PMTVoltage_plt.setCentralItem(vb)
self.img = pg.ImageItem(pmtImage)
vb.addItem(self.img)
and then in other function I recover the vb using getViewBox() and then use mapFromViewtoItem()
vb = self.ui.PMTVoltage_plt.getViewBox()
items = vb.mapSceneToView(event.scenePos())
pixels = vb.mapFromViewToItem(self.img, items)
print(items)
Hope this helps

Related

Max Recursion Depth Error With Grid Search Problem

I've written out a potential solution to a Leetcode problem but I get this error involving maximum recursion depth. I'm really unsure what I'm doing wrong. Here's what I've tried writing:
def orangesRotting(grid):
R,C = len(grid), len(grid[0])
seen = set()
min_time = 0
def fresh_search(r,c, time):
if ((r,c,time) in seen or r < 0 or c < 0 or r >= R or c >= C or grid[r][c] == 0):
return
elif grid[r][c] == 2:
seen.add((r,c,0))
elif grid[r][c] == 1:
seen.add((r,c, time + 1))
fresh_search(r+1,c,time+1)
fresh_search(r-1,c,time+1)
fresh_search(r,c+1,time+1)
fresh_search(r,c-1,time+1)
for i in range(R):
for j in range(C):
if grid[i][j] == 2:
fresh_search(i,j,0)
for _,_,t in list(seen):
min_time = max(min_time,t)
return min_time
Even on a simple input like grid = [[2,1,1], [1,1,0], [0,1,1]]. The offending line always appears to be at the if statement
if ((r,c,time) in seen or r < 0 or c < 0 or r >= R or c >= C or grid[r][c] == 0):
Please note, I'm not looking for help in solving the problem, just understanding why I'm running into this massive recursion issue. For reference, here is the link to the problem. Any help would be appreciated.
So let's trace through what you are doing here. You iterate through the entire grid and if the value for that cell is 2 you call fresh_search for that cell. We'll start with [0,0]
In fresh_search you then add the cell with times seen = 0 to your set.
Now for all neighboring cells you call fresh_search so we'll just look at r+1. For r+1 your method fresh_search adds the cell to your set with times seen = 1 and then calls fresh_search again with all neighboring cells.
Next we'll just look at r-1 which is our origin and now fresh_search is being called with this cell and times seen = 2. Now this value isn't in the set yet because (0,0,0) != (0,0,2) so it adds it to the set and again calls fresh_search with the r+1 cell but now times seen = 3
and so on and so forth until max recursion.

Minimum number of steps to convert the matrix by swapping

I stumbled upon the below question and was unable to solve it, can someone tell whats the approach here
There's no way to do this except by brute force, recursively. For each tile that's not in the right position, there are at most 4 possible swaps to make. You make a swap, then add this new position to the list of ones you haven't tried, making sure not to go back to any position you've seen before. Track the depth of the recursion, and when you get a final position, the depth is the answer.
incoming = (7,3,2,4,1,5,6,8,9)
answer = (1,2,3,4,5,6,7,8,9)
primes = (2,3,5,7,11,13,17)
def solve(base, depth):
seen = set()
untried = [(base,0)]
while untried:
array,depth = untried.pop(0)
print(depth, array)
if array == answer:
print( "ANSWER!", depth )
return depth
if array in seen:
print("seen")
continue
seen.add( array )
for n in range(9):
if array[n] == n+1:
continue
for dx in (-1, -3, 1, 3):
if 0 <= n+dx < 9 and array[n]+array[n+dx] in primes:
# attempt a swap.
a = list(array)
a[n],a[n+dx] = a[n+dx],a[n]
untried.append((tuple(a),depth+1))
print( "fail" )
return -1
solve( incoming, 0 )

DFS to get all possible solutions?

I have these Circles:
I want to get the list of all possible solution of maximum non-intersecting circles. This is the illustration of the solution I wanted from node A.
Therefore the possible solutions from node A:
1 = [A,B,C], 2 = [A,B,E], 3 = [A,C,B], 4 = [A,E,B] ..etc
I want to store all of the possibilities into a list, which the will be used for weighting and selecting the best result. However, I'm still trying to create the list of all possibilities.
I've tried to code the structure here, however I still confused about backtracking and recursive. Anyone could help here?
# List of circle
# List of circle
list_of_circle = ['A','B','C','D','E']
# List of all possible solutions
result = []
# List of possible nodes
ways = []
for k in list_of_circle:
if len(list_of_circle)==0:
result.append(ways)
else:
ways.append[k]
list_of_circle.remove(k)
for j in list_of_circle:
if k.intersects(j):
list_of_circle.remove(j)
return result
Here is a possible solution (pseudocode).
def get_max_non_intersect(selected_circles, current_circle_idx, all_circles):
if current_circle_idx == len(all_circles): # final case
return selected_circles
# we recursively get the biggest selection of circles if the current circle is not selected
list_without_current_circle = get_max_non_intersect(selected_circles, current_circle_idx + 1, all_circles)
# now we check if we can add the current circle to the ones selected
current_intersects_selected = false
current_circle = all_circles[current_circle_idx]
for selected_circle in selected_circles:
if intersects(current_circle, selected_circle):
current_intersects_selected = true
break
if current_intersects_selected is true: # we cannot add the current circle
return list_without_current_circle
else: # we can add the current circle
list_with_current_circle = get_max_non_intersect(selected_circles + [current_circle], current_circle_idx + 1, all_circles)
return list_with_current_circle + list_without_current_circle

How do I refactor this function in ELM?

I am trying to pick up functional programming and decided to start with Problem 1 on Project Euler: basically add all numbers less than 1000 divisible by 3 or 5 (link: a link).
This is the code that I have written. It outputs a list of factors of 3 or 5 (still need to figure out how to sum).
import Html exposing (text)
import Array
main =
text (
toString
[findSum_maxZ 3 5 1000]
)
findSum_maxZ x y max_z =
Array.filter isDivisible_x_or_y (Array.initialize max_z identity)
isDivisible_x_or_y x =
if x % 3 == 0 || x % 5 == 0 then True else False
My issue is that I reference 3 and 5 twice but I cannot call isDivisible with the additional parameters of the more abstract 'x' and'y'. My goal is to determine effective methods of removing these artificially mutable values so the end user only has to modify each input value once. Any advice?
I apologize if this question is dumb, there is not a lot of information on ELM available (especially compared to python, c, c++, java, etc which I have used) and I am still not fully comfortable with the functional programming jargon. Any and all help is appreciated.
The cool thing about ML languages is that you are pretty much free to build your own "dialect" to solve problems.
You can use currying to apply just the x and y arguments to your function, creating a new function where the supplied values are already set.
import Html exposing (text)
import Array
main = [findSum 3 5 1000]
|>toString
|>text
findSum x y maxZ =
let
isDivisibleByX = isDivisible x
isDivisibleByY = isDivisible y
in
Array.initialize maxZ identity
|>Array.filter isDivisibleByX
|>Array.filter isDivisibleByY
--as you can see, it is possible to use a list instead of creating
--new functions, it is up to you to check which abstraction works
--the best
isDivisible a b =
b % a == 0
You can also work with a single function, without resorting to currying:
import Html exposing (text)
import Array
main = [findSum 3 5 1000]
|>toString
|>text
findSum x y maxZ =
Array.initialize maxZ identity
|>Array.filter (\n-> isDivisible x n ) --or just (isDivisible x)
|>Array.filter (\n-> isDivisible y n)
isDivisible a b =
b % a == 0
If you want to filter the array with just one line, you can do this:
import Html exposing (text)
main = findSum 3 5 1000
|>toString
|>text
findSum x y maxZ =
let
divisibles = \n-> isDivisible x n && isDivisible y n
in
List.range 0 maxZ
|>List.filter divisibles
isDivisible a b =
b % a == 0
The most direct answer to your question is that you can have isDivisible_x_or_y take the two factors, and then use currying to pass the partially applied function to Array.filter.
That is, you can define isDivisible_x_or_y like this (I also removed the if True then True else False syntax and just return the expression directly):
isDivisible_x_or_y x y val =
val % x == 0 || val % y == 0
Currying is the ability to only supply some of the parameters to a function, and get back a function that takes the rest of the parameters. So, the type definition of isDivisible_x_or_y is Int -> Int -> Int -> Bool (that is, it takes in three Int values and returns a Bool). If we supply values for the x and y arguments (e.g. isDivisible_x_y 3 5), we now get a function with the type definition of Int -> Bool. This is the type expected by Array.filter.
You can see a working example at https://ellie-app.com/sdxWFL9ynka1
Another couple of notes:
List is much more common than Array in Elm. You would only use Array if you need to get items at specific indexes. Instead of Array.initialize, you can use List.range
Using the pipeline operator |> can often make your code a lot simpler to read. Instead of text (toString (getValue)), you have getValue |> toString |> text, which is now in the order that the operations occur, and doesn't have extra parenthesis. This whole program could be one simple pipeline (in a lot of scenarios putting everything into one pipeline can be excessive, though):
main =
List.range 0 max_z
|> List.filter (isDivisible_x_or_y 3 5)
|> toString
|> text
isDivisible_x_or_y x y val =
val % x == 0 || val % y == 0

Pyqt bind function to dinamically generated push buttons

Using the PyQT library I am currently having issues with binding a function to the dinamically generated pushbuttons resulting from a loop.
So far I have managed to generate the buttons and bind a function to them with the lambda command. The problem is that since I need every single button to open a different file I find myself in an odd situation as all the button do open the same one. The last value assigned to the variable.
Any idea on how to fix the situation? As a last note, sorry in case of stupid mistakes. I am new to OOP and PyQT.
def searchTheStuff(self):
found = 0
data = MainWindow.intermediateCall()
f1 = open('Path.txt', 'r')
path = f1.read()
f1.close()
Yinc = 25
Y = 40
X = 20
results = 0
for path, dirs, files in os.walk(path, topdown=True):
for name in files:
if name.endswith('.txt'):
fullpath = os.path.join(path, name)
mail = open_close(fullpath)
if mail.find(data) != -1 and results<3:
found = 1
self.buttons.append(QtGui.QPushButton(self))
print fullpath
command = lambda : webbrowser.open()
self.buttons[-1].clicked.connect(command)
self.buttons[-1].setText(_translate("self", name, None))
self.buttons[-1].setGeometry(QtCore.QRect(X, Y, 220, 20))
results = results+1
if results == 33:
X = 260
Y = 15
Y = Y + Yinc
if found == 0:
self.label = QtGui.QLabel(self)
self.label.setGeometry(QtCore.QRect(20, 40, 321, 21))
self.label.setText(_translate("self", "No templates have been found:", None))

Resources