Plot text in 3d-plot that does not scale or move - python-3.x

Hello Pyqtgraph community,
I want to be able to create a "fixed" text window in a 3D interactive plot generated in PyQtGraph.
This text window will contain simulation-related information and should be visible at all times, regardless if you zoom in/out or pan to the left or right; and the location of the window should not change.
So far all the solutions I have found, create a text object that moves as the scaling of the axes changes. For example, the code below prints text on 3D axis, but once you zoom in/out the text moves all over the place. Any ideas would be greatly appreciated.
Thanks in advance
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.opengl as gl
from pyqtgraph.opengl.GLGraphicsItem import GLGraphicsItem
class GLTextItem(GLGraphicsItem):
"""
Class for plotting text on a GLWidget
"""
def __init__(self, X=None, Y=None, Z=None, text=None):
GLGraphicsItem.__init__(self)
self.setGLOptions('translucent')
self.text = text
self.X = X
self.Y = Y
self.Z = Z
def setGLViewWidget(self, GLViewWidget):
self.GLViewWidget = GLViewWidget
def setText(self, text):
self.text = text
self.update()
def setX(self, X):
self.X = X
self.update()
def setY(self, Y):
self.Y = Y
self.update()
def setZ(self, Z):
self.Z = Z
self.update()
def paint(self):
self.GLViewWidget.qglColor(QtCore.Qt.white)
self.GLViewWidget.renderText(self.X, self.Y, self.Z, self.text)
if __name__ == '__main__':
# Create app
app = QtGui.QApplication([])
w1 = gl.GLViewWidget()
w1.resize(800, 800)
w1.show()
w1.setWindowTitle('Earth 3D')
gl_txt = GLTextItem(10, 10, 10, 'Sample test')
gl_txt.setGLViewWidget(w1)
w1.addItem(gl_txt)
while w1.isVisible():
app.processEvents()

So I was finally able to find a solution. What needs to be done is the following:
Subclass the GLViewWidget
From the derived class, overload the paintGL() so that it uses the member function renderText() to render text on the screen every time the paingGL() is called.
renderText() is overloaded to support both absolute screen coordinates, as well as axis-based coordinates:
i) renderText(int x, int y, const QString &str, const QFont &font = QFont()): plot based on (x, y) window coordinates
ii) renderText(double x, double y, double z, const QString &str, const QFont &font = QFont()): plot on (x, y, z) scene coordinates
You might want to use the QtGui.QFontMetrics() class to get the dimensions of the rendered text so you can place it in a location that makes sense for your application, as indicated in the code below.
from pyqtgraph.opengl import GLViewWidget
import pyqtgraph.opengl as gl
from PyQt5.QtGui import QColor
from pyqtgraph.Qt import QtCore, QtGui
class GLView(GLViewWidget):
"""
I have implemented my own GLViewWidget
"""
def __init__(self, parent=None):
super().__init__(parent)
def paintGL(self, *args, **kwds):
# Call parent's paintGL()
GLViewWidget.paintGL(self, *args, **kwds)
# select font
font = QtGui.QFont()
font.setFamily("Tahoma")
font.setPixelSize(21)
font.setBold(True)
title_str = 'Screen Coordinates'
metrics = QtGui.QFontMetrics(font)
m = metrics.boundingRect(title_str)
width = m.width()
height = m.height()
# Get window dimensions to center text
scrn_sz_width = self.size().width()
scrn_sz_height = self.size().height()
# Render text with screen based coordinates
self.qglColor(QColor(255,255,0,255))
self.renderText((scrn_sz_width-width)/2, height+5, title_str, font)
# Render text using Axis-based coordinates
self.qglColor(QColor(255, 0, 0, 255))
self.renderText(0, 0, 0, 'Axis-Based Coordinates')
if __name__ == '__main__':
# Create app
app = QtGui.QApplication([])
w = GLView()
w.resize(800, 800)
w.show()
w.setWindowTitle('Earth 3D')
w.setCameraPosition(distance=20)
g = gl.GLGridItem()
w.addItem(g)
while w.isVisible():
app.processEvents()

Related

Select points from a scattr plot using mouse cross hair - PyQt

I am new to PyQt and Im developing a utility where a user can import data from an excel file and plot its X and Y in a 2d scatter plot using below code:
def plot_2d_scatter(graphWidget,x,z,color=(66, 245, 72)):
graphWidget.clear()
brush = pg.mkBrush(color)
scatter = pg.ScatterPlotItem(size=5, brush=brush)
scatter.addPoints(x,z)
graphWidget.addItem(scatter)
Now I want a functionality which will allow the user to move his mouse over the scatter plot points using a cross hair / pointer / etc and select points on the scatter plot.
Whenever the user does a left click on the crosshair / marker on the scatter plot, I want its x,y coordinates to be saved for further use.
I have already tried the below snippet from somewhere on internet for using mouse events and getting my scatter points , but this didnt give me a cross hair that falls on my scatter points
def mouseMoved(self, evt):
pos = evt
if self.plotWidget.sceneBoundingRect().contains(pos):
mousePoint = self.plotWidget.plotItem.vb.mapSceneToView(pos)
mx = np.array([abs(float(i) - float(mousePoint.x())) for i in self.plotx])
index = mx.argmin()
if index >= 0 and index < len(self.plotx):
self.cursorlabel.setHtml(
"<span style='font-size: 12pt'>x={:0.1f}, \
<span style='color: red'>y={:0.1f}</span>".format(
self.plotx[index], self.ploty[index])
)
self.vLine.setPos(self.plotx[index])
self.hLine.setPos(self.ploty[index])
Any guidance is thankfully appreciated
my best fast effort, never used pg untill today:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDesktopWidget, QWidget
from PyQt5.QtCore import Qt
from PyQt5 import QtGui, QtCore, QtWidgets
import pyqtgraph as pg
import numpy as np
class MyApp(QMainWindow):
def __init__(self, parent=None):
super(MyApp, self).__init__(parent)
self.resize(781, 523)
self.graphWidget = pg.PlotWidget()
self.setCentralWidget(self.graphWidget)
self.show()
self.x = [1,2,3,4,5,6,7,8,9,5,6,7,8]
self.y = [1,2,3,4,5,6,7,8,9,5,6,7,8]
# self.y.reverse()
self.plot_2d_scatter(self.graphWidget, self.x, self.y)
self.cursor = Qt.CrossCursor
# self.cursor = Qt.BlankCursor
self.graphWidget.setCursor(self.cursor)
# Add crosshair lines.
self.crosshair_v = pg.InfiniteLine(angle=90, movable=False)
self.crosshair_h = pg.InfiniteLine(angle=0, movable=False)
self.graphWidget.addItem(self.crosshair_v, ignoreBounds=True)
self.graphWidget.addItem(self.crosshair_h, ignoreBounds=True)
self.cursorlabel = pg.TextItem()
self.graphWidget.addItem(self.cursorlabel)
self.proxy = pg.SignalProxy(self.graphWidget.scene().sigMouseMoved, rateLimit=60, slot=self.update_crosshair)
self.mouse_x = None
self.mouse_y = None
def plot_2d_scatter(self,graphWidget,x,z,color=(66, 245, 72)):
# graphWidget.clear()
brush = pg.mkBrush(color)
scatter = pg.ScatterPlotItem(size=5, brush=brush)
scatter.addPoints(x,z)
graphWidget.addItem(scatter)
def update_crosshair(self, e):
pos = e[0]
if self.graphWidget.sceneBoundingRect().contains(pos):
mousePoint = self.graphWidget.plotItem.vb.mapSceneToView(pos)
mx = np.array([abs(float(i) - float(mousePoint.x())) for i in self.x])
index = mx.argmin()
if index >= 0 and index < len(self.x):
self.cursorlabel.setText(
str((self.x[index], self.y[index])))
self.crosshair_v.setPos(self.x[index])
self.crosshair_h.setPos(self.y[index])
self.mouse_x = self.crosshair_v.setPos(self.x[index])
self.mouse_y = self.crosshair_h.setPos(self.y[index])
self.mouse_x = (self.x[index])
self.mouse_y = (self.y[index])
def mousePressEvent(self, e):
if e.buttons() & QtCore.Qt.LeftButton:
print('pressed')
# if self.mouse_x in self.x and self.mouse_y in self.y:
print(self.mouse_x, self.mouse_y)
if __name__ == '__main__':
app = QApplication(sys.argv)
myapp = MyApp()
# myapp.show()
try:
sys.exit(app.exec_())
except SystemExit:
print('Closing Window...')
it just prints out the coordinate of pressed point in graph
copied from https://www.pythonguis.com/faq/pyqt-show-custom-cursor-pyqtgraph/ and your piece of code result looks like:
there are other examples on SO like Trying to get cursor with coordinate display within a pyqtgraph plotwidget in PyQt5 and others

Undo functionality for QPainter drawEllipse() function

I'm new to PyQt and started playing around with some online code. The drawEllipse() function found in QPainter class draws an ellipse based on defined parameters. My question is once we call the function and it draws it on our scene, how do I undo this operation? There seems to be no such function that can do this in the documentation.
Example drawing code:
def draw(self, x, y):
painter = QPainter()
painter.begin(self.image)
painter.setPen(QPen(Qt.red, 5, Qt.SolidLine))
painter.drawEllipse(QPoint(y,x),10,10)
painter.end()
self.scene.addPixmap(QPixmap.fromImage(self.image))
So if a keystroke of Ctrl+Z is pressed this drawn circle should disappear, is this possible?
I do not understand why you use QImage because if you want to graph circles you should use QGraphicsEllipseItem.
To implement the undo method we must store the items in a list, then when you call the undo method you get the last element and remove it from the QGraphicsScene using removeItem().
In the following example, a circle is added each time you click.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
lay = QtWidgets.QVBoxLayout(self)
self.gv = QtWidgets.QGraphicsView()
lay.addWidget(self.gv)
self.scene = QtWidgets.QGraphicsScene(0, 0, 400, 400)
self.gv.setScene(self.scene)
self.gv.installEventFilter(self)
self.items = []
shortcut = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+Z"), self)
shortcut.activated.connect(self.undo)
def eventFilter(self, obj, event):
if obj == self.gv and event.type() == QtCore.QEvent.MouseButtonPress:
p = self.gv.mapToScene(event.pos())
self.draw(p)
return QtWidgets.QWidget.eventFilter(self, obj, event)
def draw(self, p):
it = QtWidgets.QGraphicsEllipseItem(0, 0, 10, 10)
it.setPen(QtGui.QPen(QtCore.Qt.red, 5, QtCore.Qt.SolidLine))
self.scene.addItem(it)
it.setPos(p)
self.items.append(it)
def undo(self):
if self.items:
it = self.items.pop()
self.scene.removeItem(it)
del it
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

How to use matplotlib blitting to add matplot.patches to an matplotlib plot in wxPython?

I am making a plot using the matplotlib library and showing it in my wxPython GUI. I am plotting a massive amount of data points from a LIDAR instrument. The thing is, I would like to draw rectangles in this plot to indicate interesting areas. But when I draw a rectangle on the same axes as the plot, the whole plot gets replotted which takes lots of time. This is because of the self.canvas.draw(), a function which replots everything.
The code gets displayed as follows in the GUI:
Printscreen of GUI
Here is a minimal working example of the problem. U can draw rectangles by holding the right mouse button. Once you plot the NetCDF data using the button on the left, the drawing of rectangles gets really slow. I tried some things with blitting using the examples provided by ImportanceOfBeingErnest but after a lot of tries, I still have not managed to get it to work.
To make the minimal working example work, you will have to specify the path to the NetCDF file under the plot_Data() function. I provided the NetCDF file which to download here:
Download NetCDF file
How can I blit the self.square to the self.canvas in the onselect function?
import netCDF4 as nc
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.widgets
import time
import wx
class rightPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER)
self.initiate_Matplotlib_Plot_Canvas()
self.add_Matplotlib_Widgets()
def initiate_Matplotlib_Plot_Canvas(self):
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
self.colorbar = None
self.canvas = FigureCanvas(self, -1, self.figure)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas, proportion=1, flag=wx.ALL | wx.GROW)
self.SetSizer(self.sizer)
self.Fit()
self.canvas.draw()
def add_Matplotlib_Widgets(self):
self.rectangleSelector = matplotlib.widgets.RectangleSelector(self.axes, self.onselect,
drawtype="box", useblit=True,
button=[3], interactive=False
)
def onselect(self, eclick, erelease):
tstart = time.time()
x1, y1 = eclick.xdata, eclick.ydata
x2, y2 = erelease.xdata, erelease.ydata
height = y2-y1
width = x2-x1
self.square = matplotlib.patches.Rectangle((x1,y1), width,
height, angle=0.0, edgecolor='red',
fill=False
#blit=True gives Unknown property blit
)
self.axes.add_patch(self.square)
self.canvas.draw()
# =============================================================================
# self.background = self.canvas.copy_from_bbox(self.axes.bbox)
#
#
# self.canvas.restore_region(self.background)
#
# self.axes.draw_artist(self.square)
#
# self.canvas.blit(self.axes.bbox)
# =============================================================================
tend = time.time()
print("Took " + str(tend-tstart) + " sec")
def plot_Data(self):
"""This function gets called by the leftPanel onUpdatePlot. This updates
the plot to the set variables from the widgets"""
path = "C:\\Users\\TEST_DATA\\cesar_uvlidar_backscatter_la1_t30s_v1.0_20100501.nc"
nc_data = self.NetCDF_READ(path)
print("plotting......")
vmin_value = 10**2
vmax_value = 10**-5
combo_value = nc_data['perp_beta']
self.axes.clear()
plot_object = self.axes.pcolormesh(combo_value.T, cmap='rainbow',
norm=colors.LogNorm(vmin=vmin_value, vmax=vmax_value))
self.axes.set_title("Insert title here")
if self.colorbar is None:
self.colorbar = self.figure.colorbar(plot_object)
else:
self.colorbar.update_normal(plot_object)
self.colorbar.update_normal(plot_object)
print('canvas draw..............')
self.canvas.draw()
print("plotting succesfull")
###############################################################################
###############################################################################
"""BELOW HERE IS JUST DATA MANAGEMENT AND FRAME/PANEL INIT"""
###############################################################################
###############################################################################
def NetCDF_READ(self, path):
in_nc = nc.Dataset(path)
list_of_keys = in_nc.variables.keys()
nc_data = {} #Create an empty dictionary to store NetCDF variables
for item in list_of_keys:
variable_shape = in_nc.variables[item].shape
variable_dimensions = len(variable_shape)
if variable_dimensions > 1:
nc_data[item] = in_nc.variables[item][...] #Adding netCDF variables to dictonary
return nc_data
class leftPanel(wx.Panel):
def __init__(self, parent, mainPanel):
wx.Panel.__init__(self, parent)
button = wx.Button(self, -1, label="PRESS TO PLOT")
button.Bind(wx.EVT_BUTTON, self.onButton)
self.mainPanel = mainPanel
def onButton(self, event):
self.mainPanel.rightPanel.plot_Data()
class MainPanel(wx.Panel):
def __init__(self, parent):
"""Initializing the mainPanel. This class is called by the frame."""
wx.Panel.__init__(self, parent)
self.SetBackgroundColour('red')
"""Acquire the width and height of the monitor"""
width, height = wx.GetDisplaySize()
"""Split mainpanel into two sections"""
self.vSplitter = wx.SplitterWindow(self, size=(width,(height-100)))
self.leftPanel = leftPanel(self.vSplitter, self)
self.rightPanel = rightPanel(self.vSplitter)
self.vSplitter.SplitVertically(self.leftPanel, self.rightPanel,102)
class UV_Lidar(wx.Frame):
"""Uppermost class. This class contains everything and calls everything.
It is the container around the mainClass, which on its turn is the container around
the leftPanel class and the rightPanel class. This class generates the menubar, menu items,
toolbar and toolbar items"""
def __init__(self, parent, id):
print("UV-lidar> Initializing GUI...")
wx.Frame.__init__(self, parent, id, 'UV-lidar application')
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
self.mainPanel = MainPanel(self)
def OnCloseWindow(self, event):
self.Destroy()
if __name__ == '__main__':
app = wx.App()
frame = UV_Lidar(parent=None, id=-1)
frame.Show()
print("UV-lidar> ")
print("UV-lidar> Initializing GUI OK")
app.MainLoop()
I have found the solution myself:
In order to blit a matplotlib patch, you will have to first add the patch to the axes. Then draw the patch on the axes and then you can blit the patch to the canvas.
square = matplotlib.patches.Rectangle((x1,y1), width,
height, angle=0.0, edgecolor='red',
fill=False)
self.axes.add_patch(square)
self.axes.draw_artist(square)
self.canvas.blit(self.axes.bbox)
If you do not want to use self.canvas.draw but still use matplotlib widgets which have useblit=True, you can save the plot as a background image: self.background = self.canvas.copy_from_bbox(self.axes.bbox) and restore it later by using: self.canvas.restore_region(self.background). This is a lot faster than drawing everything over!
When using the matplotlib's RectangleSelector widget with useblit=True, it will create another background instance variable, which interferes with your own background instance variable. To fix this problem, you will have to set the background instance variable of the RectangleSelector widget to be equal to your own background instance variable. However, this should only be done after the RectangleSelector widget is no longer active. Otherwise it will save some of the drawing animation to the background. So once the RectangleSelector has become inactive, you can update its background using: self.rectangleSelector.background = self.background
The code that had to be edited is given below. wx.CallLater(0, lambda: self.tbd(square)) is used so that the background instance variable of the RectangleSelector widget is updated only when it has become inactive.
def add_Matplotlib_Widgets(self):
"""Calling these instances creates another self.background in memory. Because the widget classes
restores their self-made background after the widget closes it interferes with the restoring of
our leftPanel self.background. In order to compesate for this problem, all background instances
should be equal to eachother. They are made equal in the update_All_Background_Instances(self)
function"""
"""Creating a widget that serves as the selector to draw a square on the plot"""
self.rectangleSelector = matplotlib.widgets.RectangleSelector(self.axes, self.onselect,
drawtype="box", useblit=True,
button=[3], interactive=False
)
def onselect(self, eclick, erelease):
self.tstart = time.time()
x1, y1 = eclick.xdata, eclick.ydata
x2, y2 = erelease.xdata, erelease.ydata
height = y2-y1
width = x2-x1
square = matplotlib.patches.Rectangle((x1,y1), width,
height, angle=0.0, edgecolor='red',
fill=False
#blit=True gives Unknown property blit
)
"""In order to keep the right background and not save any rectangle drawing animations
on the background, the RectangleSelector widget has to be closed first before saving
or restoring the background"""
wx.CallLater(0, lambda: self.tbd(square))
def tbd(self, square):
"""leftPanel background is restored"""
self.canvas.restore_region(self.background)
self.axes.add_patch(square)
self.axes.draw_artist(square)
self.canvas.blit(self.axes.bbox)
"""leftPanel background is updated"""
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
"""Setting all backgrounds equal to the leftPanel self.background"""
self.update_All_Background_Instances()
print('Took '+ str(time.time()-self.tstart) + ' s')
def update_All_Background_Instances(self):
"""This function sets all of the background instance variables equal
to the lefPanel self.background instance variable"""
self.rectangleSelector.background = self.background

Draw line: retrieve the covered pixels

I want to draw a line on a widget:
from PyQt4 import QtGui, QtCore
class LineLabel(QtGui.QLabel):
def __init__(self,parent=None):
super(LineLabel,self).__init__(parent)
self.setMinimumSize(100,100)
self.setMaximumSize(100,100)
def paintEvent(self,e):
painter=QtGui.QPainter(self)
pen = QtGui.QPen()
pen.setWidth(5)
painter.setPen(pen)
painter.drawLine(10,10,90,90)
painter.end()
def test():
form = QtGui.QWidget()
label = LineLabel(form)
form.show()
return form
import sys
app = QtGui.QApplication(sys.argv)
window =test()
sys.exit(app.exec_())
What is the best way to get a list of the pixels that are covered by the line?
Update from the comments:
I don't need to know the pixels directly in between the start and end point but all those pixels that are changed to black (which are more pixels because the line has a certain width).
My overall goal is a fast way to know which pixels on the widget are black. Iterating over the pixels of the image and querying the color is much slower than reading the color value from a list in which the colors are stored: For me 1.9 seconds for an image with 1 million pixels to 0.23 seconds for a list with 1 million entries. Therefore I must update that list after every change of the image on the widget such as by drawing a line.
Answers that refer to a QGraphicsItem in a QGraphicsScene are also helpful.
You may use a linear equation to find the point you want in the line. I think that there is no reference to a draw line.
from PyQt4 import QtGui
from PyQt4.QtGui import QColor, QPaintEvent
m_nInitialX = 0.0
m_nInitialY = 0.0
# my line abstraction
class MyLine:
x1, y1, x2, y2 = .0, .0, .0, .0
width = .0
px, py = (.0, .0)
draw_point = False
def __init__(self, x1, y1, x2, y2, width):
self.x1, self.y1, self.x2, self.y2 = (x1, y1, x2, y2)
self.width = width
def is_in_line(self, x, y):
# mark a position in the line
m = (self.y2 - self.y1) / (self.x2 - self.x1)
print(m*(x-self.x1)-(y-self.y1))
if abs((m*(x-self.x1) - (y-self.y1))) <= self.width/2:
self.draw_point = True
return True
else:
return False
def add_red_point(self, x, y):
self.px, self.py = (x, y)
def draw(self, widget):
painter = QtGui.QPainter(widget)
pen = QtGui.QPen()
pen.setWidth(self.width)
painter.setPen(pen)
painter.drawLine(self.x1, self.y1, self.y2, self.y2)
if self.draw_point:
pen.setColor(QColor(255, 0, 0))
painter.setPen(pen)
painter.drawPoint(self.px, self.py)
painter.end()
line = MyLine(10, 10, 90, 90, width=10) # <-- my line abstraction
class LineLabel(QtGui.QLabel):
def __init__(self, parent=None):
super(LineLabel, self).__init__(parent)
self.setMinimumSize(100, 100)
self.setMaximumSize(100, 100)
# always redraw when needed
def paintEvent(self, e):
print("draw!")
line.draw(self)
def mousePressEvent(self, event):
# mark clicked position in line
m_nInitialX = event.pos().x()
m_nInitialY = event.pos().y()
if line.is_in_line(m_nInitialX, m_nInitialY):
line.add_red_point(m_nInitialX, m_nInitialY)
self.repaint()
def test():
form = QtGui.QWidget()
label = LineLabel(form)
form.show()
return form
import sys
app = QtGui.QApplication(sys.argv)
window = test()
sys.exit(app.exec_())

Set dimensions of an SVG image in fullscreen using QSvgWidget in PyQT?

I am lost with my PyQT programm. I want to display SVG image on full screen, but I need to be able to set the scale and position of the image and rest of the screen fill with black colour.
I use QSvgWidget and regular QWidget on top of each other, but It is not a good solution, because it runs as two processes and two separate windows.
Could you tell me how to make this with only one widget
import sys, os
from PyQt4 import QtGui, QtSvg
class Display(QtSvg.QSvgWidget):
def __init__(self, parent=None):
super(Display, self).__init__(parent)
def main():
app = QtGui.QApplication(sys.argv)
black = QtGui.QWidget() #setting background with widget
black.showFullScreen()
form = Display()
form.setWindowTitle("Display SVG Layer")
form.showFullScreen()
form.setStyleSheet("background-color:black;")
form.load("E:\example.svg")
form.move(100,0)
form.resize(1900,1000)
app.exec_()
if __name__ == '__main__':
main()
perhaps You can use QGraphicsView and QGraphicsScene:
class MyGraphicsView(QGraphicsView):
def __init__(self, w, h, parent=None):
QGraphicsView.__init__(self, parent)
self.setGeometry(0, 0, w, h) # screen size
class MyGraphicsScene(QGraphicsScene):
def __init__(self, w, h, parent = None):
QGraphicsScene.__init__(self,parent)
self.setSceneRect(0, 0, w, h) # screen size
self.backgroundPen = QPen(QColor(Qt.black))
self.backgroundBrush = QBrush(QColor(Qt.black))
self.textPen = QPen(QColor(Qt.lightGray))
self.textPen.setWidth(1)
self.textBrush = QBrush(QColor(Qt.lightGray))
self.textFont = QFont("Helvetica", 14, )
# paint the background
self.addRect(0,0,self.width(), self.height(), self.backgroundPen, self.backgroundBrush)
# paint the svg-title
self.svgTitle = self.addSimpleText('Display SVG Layer', self.textFont)
self.svgTitle.setPen(self.textPen)
self.svgTitle.setBrush(self.textBrush)
self.svgTitle.setPos(200,75)
# paint the svg
self.svgItem = QGraphicsSvgItem('./example.svg')
'''
edit:
if necessary, get the size of the svgItem to calculate
scale factor and position
'''
self.svgSize = self.svgItem.renderer().defaultSize()
self.svgItem.setScale(0.25) # scale the svg to an appropriate size
self.addItem(self.svgItem)
self.svgItem.setPos(200, 125)
if __name__ == '__main__':
app = QApplication(sys.argv)
screen_size = app.primaryScreen().size()
width = screen_size.width()
height = screen_size.height()
graphicsScene = MyGraphicsScene(width, height)
graphicsView = MyGraphicsView(width, height)
graphicsView.setScene(graphicsScene)
graphicsView.show()
app.exec_()

Resources