How to scale a QGraphicsItem without changing its position - qt

I have a QGraphicsRect that changes its height dynamically. I want to normalize its height to 1 after its height changed. If I try to apply a QTransform or the scale() function, the y position of the QGraphicsRect changes as well if its y position is not 0.
I tried to move the QGraphicsRect back to the origin of the scene before applying the scaling, but it did not help. Any ideas?
Minimal working example below. (Press the button to change the height of the QRectItem). If the problem is solved, the QGraphicsRect upper and lower edge should always lay on the red lines.
import sys
import numpy as np
from PySide import QtCore, QtGui
class Test(QtGui.QMainWindow):
def __init__(self):
super(Test, self).__init__()
self.setupUi(self)
self.setupGV()
self.connectElements()
self.rectY = 3
self.initRect()
self.show()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gv_center = QtGui.QGraphicsView(self.centralwidget)
self.gv_center.setGeometry(QtCore.QRect(100, 60, 561, 331))
self.gv_center.setObjectName("gv_center")
self.pb_debug = QtGui.QPushButton(self.centralwidget)
self.pb_debug.setGeometry(QtCore.QRect(540, 500, 94, 24))
self.pb_debug.setObjectName("pb_debug")
self.pb_debug.setText("push !")
MainWindow.setCentralWidget(self.centralwidget)
def connectElements(self):
self.pb_debug.clicked.connect(self.buttonClick)
def setupGV(self):
self.overviewScene = QtGui.QGraphicsScene(self)
self.overviewScene.setSceneRect(0, -0.5, 1, 7)
self.gv_center.setScene(self.overviewScene)
self.gv_center.fitInView(0, -0.5, 1, 7)
def initRect(self):
self.overviewScene.addLine(-5, self.rectY, 5, self.rectY, QtGui.QPen(QtGui.QColor(255, 0, 0)))
self.overviewScene.addLine(-5, self.rectY + 1, 5, self.rectY + 1, QtGui.QPen(QtGui.QColor(255, 0, 0)))
self.rect = self.overviewScene.addRect(0, self.rectY, 1, 1, QtGui.QPen(QtGui.QColor(0, 0, 0)))
def buttonClick(self):
newHeight = np.random.randint(1, 10)
print(newHeight)
geo = self.rect.rect()
geo.setHeight(newHeight)
self.rect.setRect(geo)
self.normalizeSubplot(self.rect, newHeight, self.rectY)
def normalizeSubplot(self, subplotItem, accH, y):
subplotItem.prepareGeometryChange()
if accH != 0:
height = 1.0 / accH
else:
height = 0
trans = subplotItem.transform()
trans.setMatrix(1, trans.m12(), trans.m13(),
trans.m21(), height, trans.m23(),
trans.m31(), trans.m32(), 1)
subplotItem.setTransform(trans)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = Test()
sys.exit(app.exec_())

After a couple of days I found the solution with help of some guy from IRC. The transformation matrix has to be:
trans.setMatrix(1, trans.m12(), trans.m13(),
trans.m21(), height, trans.m23(),
trans.m31(), -height * self.rectY + self.rectY, 1)

Related

Plot Gaze Heat Map on PNG

With this code I want to plot a heat map from eye tracking gaze data (x, y coordinates on screen) on top of a png. I got really close with other posts here in the forum. The only problem left are some dots/blurry patches on the output image (see link). Maybe somebody can help?
import numpy as np
import matplotlib.pyplot as plt
from scipy.ndimage import gaussian_filter
import pandas as pd
from PIL import Image
with Image.open("/Users/florianteichmann/Desktop/Gaze_Scratch_Paradigm/stimuli_current/trial_image/32space_drop.png") as img3:
w = img3.width
h = img3.height
def myplot(x, y, s, bins=1000):
heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
heatmap = gaussian_filter(heatmap, sigma=s)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
return heatmap.T, extent
def transparent_cmap(cmap, N=255):
mycmap = cmap
mycmap._init()
mycmap._lut[:,-1] = np.linspace(0, 1, N+4)
return mycmap
# Generate some test data
df = pd.read_csv('file-path')
x = (df['X'])
y = (df['Y'])
mycmap = transparent_cmap(plt.cm.Greens)
img2 = plt.imread('file-path')
#sigmas = [0, 16, 32, 64]
s = 64
fig, ax = plt.subplots()
plt.axis([0, w, 0, h])
img, extent = myplot(x, y, s)
ax.imshow(img2, extent=[0, w, 0, h])
#ax.plot(img) #cmap=cm.jet)
ax.imshow(img, extent=[0, w, 0, h], origin='lower', cmap=mycmap) #cmap=cm.jet) origin='lower'
plt.show()
output image

How to solve this : Calculated padded input size per channel: (3 x 3). Kernel size: (4 x 4). Kernel size can't be greater than actual input size

I have problem : Calculated padded input size per channel: (3 x 3). Kernel size: (4 x 4). Kernel size can't be greater than actual input size
def conv(c_in, c_out, batch_norm=True, activation="lrelu"):
return conv_block(c_in, c_out, kernel=4, stride=2, pad=1, bias=False, batch_norm=batch_norm, activation=activation, pool_type=None)
def tconv(c_in, c_out, batch_norm=True, activation="lrelu"):
return tconv_block(c_in, c_out, kernel=4, stride=2, pad=1, bias=False, batch_norm=batch_norm, activation=activation, pool_type=None)
def __init__(self):
super().__init__()
self.conv = nn.Sequential(
conv(3, 32, batch_norm=False),
conv(32, 64),
conv(64, 128),
conv(128, 256),
conv_block(256, 1, kernel=4, stride=1, pad=0, bias=False, activation=None, pool_type=None),
nn.Flatten()
)
def forward(self, x):
x = self.conv(x)
return x
def clip_weights(self, vmin=-0.01, vmax=0.01):
for p in self.parameters():
p.data.clamp_(vmin, vmax)
class Generator(nn.Module):
def __init__(self, z_dim):
super().__init__()
self.z_dim = z_dim
self.tconv = nn.Sequential(
tconv_block(z_dim, 512, kernel=4, stride=2, pad=1, bias=False, activation="lrelu", pool_type=None),
tconv(512, 256),
tconv(256, 128),
tconv(128, 64),
tconv(64, 32),
tconv(32, 3, activation="tanh", batch_norm=False)
)
def forward(self, x):
return self.tconv(x)
def generate(self, n, device):
z = torch.randn((n, self.z_dim, 1, 1), device=device)
return self.tconv(z)```
z = torch.randn((n, self.z_dim, 1, 1), device=device)
The code above generates input noise tensor with (1,1) size, which is too small for the model.
z = torch.randn((n, self.z_dim, 10, 10), device=device)
Increasing the size of the input tensor, as in the code above, should solve the error.

How to embed plot inside wx.SplitterWindow (right panel)?

I'm trying to embed plot inside right panel of Splitter window, how to add plot inside splitter window. please find here the link for the dataset.
https://www.dropbox.com/s/ncy6dlpm79p578s/Dataset.zip?dl=0.
The file contains rows and columns of wavelength and reflectance.
import wx
from pylab import *
import asciitable
import matplotlib.pyplot as plt
import os
from wxmplot import ImageMatrixFrame
class RandomObj(object):
def __init__(self, name):
self.name = name
class SLI(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, size=(820, 450))
splitter = wx.SplitterWindow(self, style = wx.SP_BORDER)
leftPanel = wx.Panel(splitter, size=(400,100))
rightPanel = wx.Panel(splitter, size=(400,100))
####Tree Widget#####
self.tree = wx.TreeCtrl(leftPanel)
leftSizer = wx.BoxSizer(wx.VERTICAL)
leftSizer.Add(self.tree, 1, wx.EXPAND | wx.ALIGN_CENTER)
leftPanel.SetSizer(leftSizer)
rightSizer = wx.BoxSizer(wx.VERTICAL)
self.display = wx.StaticText(rightPanel, -1, '', (10, 10),
style=wx.ALIGN_CENTRE)
rightSizer.Add(self.display, -1, wx.EXPAND)
rightPanel.SetSizer(rightSizer)
splitter.SplitVertically(leftPanel, rightPanel)
##### Splitter ends ####
root = self.tree.AddRoot('Database')
self.tree.AppendItem(root, 'USGS')
files = []
self.dname = []
self.test = []
for dirname, dirnames, filenames in os.walk('.\USGS'):
for filename in filenames:
files.append(os.path.join(dirname, filename))
self.test.append(filename)
self.tree.AppendItem(self.tree.GetLastChild(root), filename)
self.dname = files[:]
self.tree.AppendItem(root,'ASTER')
for dirname, dirnames, filenames in os.walk('.\ASTER'):
for filename in filenames:
files.append(os.path.join(dirname, filename))
self.test.append(filename)
self.tree.AppendItem(self.tree.GetLastChild(root), filename)
self.dname = files[:]
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.ASTER, self.tree)
def ASTER(self, event):
self.item = event.GetItem()
value1 = self.tree.GetItemText(self.item)
value2 = 0
value3 = 1
self.item=None
for k in self.test:
if value1 == k:
value2 +=1
break
else:
value2 +=1
for i in self.dname:
if value3 == value2:
array =[]
f=open(i, 'r')
for j in xrange(27):
f.next()
for line in f:
array.append(line)
data = asciitable.read(array)
plot(data.col1, data.col2)
title(value1)
show()
break
else:
value3 +=1
app = wx.App(None)
frame = ImageMatrixFrame()
SLI().Show()
app.MainLoop()
how to insert plot window inside right panel of splitter.
I am not 100% sure I understand your code - there are some formatting and indentation problems for sure. I also am not familiar with asciitable. But, that said, a wxmplot.PlotPanel or ImagePanel can be embedded in a wxPython Frame that uses a Splitter. An example might look like the code below. I tried to make it short, but also tried to make it complete and using plain wxPython. For a more complete application, you'd probably want to put the reading of the datafiles into a separate class, etc. Anyway, this uses your Dataset folder, and should mostly work to show the concepts:
#!/usr/bin/env python
import os
import wx
from wxmplot import PlotPanel
# see https://gist.github.com/newville/e805a6454c4e4c0e010bf0b3cc796d52
from asciifile import read_ascii
LEFTSTYLE = wx.ALIGN_LEFT|wx.GROW|wx.ALL
def pack(window, sizer, expand=1.1):
"simple wxPython pack function"
tsize = window.GetSize()
msize = window.GetMinSize()
window.SetSizer(sizer)
sizer.Fit(window)
nsize = (int(1.1*max(msize[0], tsize[0])),
int(1.1*max(msize[1], tsize[1])))
window.SetSize(nsize)
class SpectraPlotterFrame(wx.Frame):
def __init__(self, data_folder):
wx.Frame.__init__(self, None, size=(800, 450))
self.SetTitle("Data File Plotter: {:s}".format(data_folder))
self.data_folder = data_folder
self.current_filename = None
splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
splitter.SetMinimumPaneSize(200)
# left side: ListBox of File Names
l_panel = wx.Panel(splitter)
l_sizer = wx.BoxSizer(wx.VERTICAL)
self.filelist = wx.ListBox(l_panel)
self.filelist.Bind(wx.EVT_LISTBOX, self.onFileChoice)
l_sizer.Add(self.filelist, 1, LEFTSTYLE, 5)
pack(l_panel, l_sizer)
# right side: Panel to choose plot array labels, make plot
r_panel = wx.Panel(splitter)
r_sizer = wx.GridBagSizer(3, 3)
self.xarr = wx.Choice(r_panel, choices=[], size=(175, -1))
self.yarr = wx.Choice(r_panel, choices=[], size=(175, -1))
xlabel = wx.StaticText(r_panel, label='X:', style=LEFTSTYLE)
ylabel = wx.StaticText(r_panel, label='Y:', style=LEFTSTYLE)
plot_btn = wx.Button(r_panel, label='Show Plot', size=(125, -1))
plot_btn.Bind(wx.EVT_BUTTON, self.onPlot)
self.plotpanel = PlotPanel(r_panel, size=(650, 450))
r_sizer.Add(xlabel, (0, 0), (1, 1), LEFTSTYLE, 2)
r_sizer.Add(self.xarr, (0, 1), (1, 1), LEFTSTYLE, 2)
r_sizer.Add(ylabel, (0, 2), (1, 1), LEFTSTYLE, 2)
r_sizer.Add(self.yarr, (0, 3), (1, 1), LEFTSTYLE, 2)
r_sizer.Add(plot_btn, (0, 4), (1, 1), LEFTSTYLE, 2)
r_sizer.Add(self.plotpanel, (1, 0), (1, 6), LEFTSTYLE, 2)
pack(r_panel, r_sizer)
splitter.SplitVertically(l_panel, r_panel, 1)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(splitter, 1, LEFTSTYLE, 5)
pack(self, sizer)
wx.CallAfter(self.read_datafiles)
self.Show()
self.Raise()
def read_datafiles(self):
self.datasets = {}
dfolder = os.path.abspath(self.data_folder)
for fname in sorted(os.listdir(self.data_folder)):
try:
self.datasets[fname] = read_ascii(os.path.join(dfolder, fname))
except:
print("Could not read file {:s}".format(fname))
self.filelist.Append(fname)
def onFileChoice(self, event=None):
self.current_filename = fname = event.GetString()
for choice, default in ((self.xarr, 0), (self.yarr, 1)):
choice.Clear()
choice.AppendItems(self.datasets[fname].array_labels)
choice.SetSelection(default)
def onPlot(self, event=None):
x = self.xarr.GetSelection()
y = self.yarr.GetSelection()
xlab = self.xarr.GetStringSelection()
ylab = self.yarr.GetStringSelection()
if self.current_filename is not None:
dset = self.datasets[self.current_filename]
self.plotpanel.plot(dset.data[x], dset.data[y], xlabel=xlab,
ylabel=ylab, label=self.current_filename,
show_legend=True)
class SpectraPlotterApp(wx.App):
def __init__(self, data_folder='.', **kws):
self.data_folder = data_folder
wx.App.__init__(self, **kws)
def createApp(self):
frame = SpectraPlotterFrame(data_folder=self.data_folder)
self.SetTopWindow(frame)
def OnInit(self):
self.createApp()
return True
if __name__ == '__main__':
SpectraPlotterApp(data_folder='Dataset').MainLoop()

python 'str' object has no attribute 'config'

I tried to create a Gui with a grid like label, the label will randomly fill with number in random label with a click on the start button. I cannot get the code to recognize the random label and set text to it. The labels are create in a loop for the grid of '3 X 5'.
from tkinter import *
import random
lbl1 = {}
lbl2 = {}
lbl3 = {}
def fill_auto():
for i in range(1, 6):
rd_row = random.randrange(1, 6)
rd_col = random.randrange(1, 4)
rd_num = random.randrange(1, 16)
print(rd_row, rd_col, rd_num)
pos = str(rd_col) + str(rd_row)
box = 'lbl' + str(pos)
print(box)
box.config(text=rd_num)
root = Tk()
root.geometry('+0+0')
root.configure(bg='black')
for y in range(1, 6):
lbl1[str(y)] = Label(root, width=5, relief='solid')
lbl1[str(y)].grid(row=y, column=0)
lbl2[str(y)] = Label(root, width=5, relief='solid')
lbl2[str(y)].grid(row=y, column=1)
lbl3[str(y)] = Label(root, width=5, relief='solid')
lbl3[str(y)].grid(row=y, column=2)
btn = Button(root, text='start', command=fill_auto)
btn.grid(row=6, column=1)
root.mainloop()
If you want a grid of buttons, it would make sense to use a 2d list:
from tkinter import *
import random
# Create variables for these for the grid width/height
width = 3
height = 5
def fill_auto():
for i in range(1, 6):
rd_row = random.randrange(0, height)
rd_col = random.randrange(0, width)
rd_num = random.randrange(1, 16)
# Set the label text
matrix[rd_row][rd_col].config(text = str(rd_num))
root = Tk()
root.geometry('+0+0')
root.configure(bg='black')
# Helper function to create a label
def make_label(x, y):
l = Label(root, width=5, relief='solid')
l.grid(column=x, row=y)
return l;
# Using list comprehension to create 2d list
matrix = [[make_label(x,y) for x in range(width)] for y in range(height)]
btn = Button(root, text='start', command=fill_auto)
btn.grid(row=6, column=1)
root.mainloop()

Pyqtgraph plotting is slow

It seems window redraws everything each time new rect is added, although setUpdatesEnabled is set to False, for win and plt. How to disable updates?
def f(n):
import pyqtgraph as pg
pg.setConfigOption('background', '#a0f0ff')
win = pg.GraphicsWindow()
win_size = 1000
win.setGeometry(500, 30, win_size, win_size)
plt = win.addPlot()
win.setUpdatesEnabled = False
plt.setUpdatesEnabled = False
y = range(n)
x = range(n)
plt.showGrid(x=True, y=True)
empty_pen = pg.mkPen((0, 0, 0, 0))
brush = pg.mkBrush((255, 255, 255))
for i1 in range(n):
for i0 in range(n):
print("i1, i0 =", i1, i0)
rect = pg.QtGui.QGraphicsRectItem(i0, i1, 0.5, 0.5)
rect.setPen(empty_pen)
rect.setBrush(brush)
plt.addItem(rect)
pg.QtGui.QApplication.exec_()
f(40)
Add
plt.disableAutoRange()
before drawing and
plt.autoRange()
after it. See Plotting large arrays in pyqtgraph

Resources