8000 Merge pull request #7507 from QuLogic/qt5agg_hidpi · matplotlib/matplotlib@a468e31 · GitHub
[go: up one dir, main page]

Skip to content

Commit a468e31

Browse files
authored
Merge pull request #7507 from QuLogic/qt5agg_hidpi
[MRG+1] Qt5Agg HiDPI support
2 parents 6afa9ce + 001eaf9 commit a468e31

File tree

3 files changed

+54
-24
lines changed

3 files changed

+54
-24
lines changed

lib/matplotlib/backends/backend_qt5.py

Lines changed: 25 additions & 17 deletions
8000
Original file line numberDiff line numberDiff line change
@@ -243,17 +243,33 @@ def __init__(self, figure):
243243
w, h = self.get_width_height()
244244
self.resize(w, h)
245245

246+
@property
247+
def _dpi_ratio(self):
248+
# Not available on Qt4 or some older Qt5.
249+
try:
250+
return self.devicePixelRatio()
251+
except AttributeError:
252+
return 1
253+
254+
def get_width_height(self):
255+
w, h = FigureCanvasBase.get_width_height(self)
256+
return int(w / self._dpi_ratio), int(h / self._dpi_ratio)
257+
246258
def enterEvent(self, event):
247259
FigureCanvasBase.enter_notify_event(self, guiEvent=event)
248260

249261
def leaveEvent(self, event):
250262
QtWidgets.QApplication.restoreOverrideCursor()
251263
FigureCanvasBase.leave_notify_event(self, guiEvent=event)
252264

265+
def mouseEventCoords(self, pos):
266+
x = pos.x() * self._dpi_ratio
267+
# flip y so y=0 is bottom of canvas
268+
y = self.figure.bbox.height - pos.y() * self._dpi_ratio
269+
return x, y
270+
253271
def mousePressEvent(self, event):
254-
x = event.pos().x()
255-
# flipy so y=0 is bottom of canvas
256-
y = self.figure.bbox.height - event.pos().y()
272+
x, y = self.mouseEventCoords(event.pos())
257273
button = self.buttond.get(event.button())
258274
if button is not None:
259275
FigureCanvasBase.button_press_event(self, x, y, button,
@@ -262,9 +278,7 @@ def mousePressEvent(self, event):
262278
print('button pressed:', event.button())
263279

264280
def mouseDoubleClickEvent(self, event):
265-
x = event.pos().x()
266-
# flipy so y=0 is bottom of canvas
267-
y = self.figure.bbox.height - event.pos().y()
281+
x, y = self.mouseEventCoords(event.pos())
268282
button = self.buttond.get(event.button())
269283
if button is not None:
270284
FigureCanvasBase.button_press_event(self, x, y,
@@ -274,16 +288,12 @@ def mouseDoubleClickEvent(self, event):
274288
print('button doubleclicked:', event.button())
275289

276290
def mouseMoveEvent(self, event):
277-
x = event.x()
278-
# flipy so y=0 is bottom of canvas
279-
y = self.figure.bbox.height - event.y()
291+
x, y = self.mouseEventCoords(event)
280292
FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event)
281293
# if DEBUG: print('mouse move')
282294

283295
def mouseReleaseEvent(self, event):
284-
x = event.x()
285-
# flipy so y=0 is bottom of canvas
286-
y = self.figure.bbox.height - event.y()
296+
x, y = self.mouseEventCoords(event)
287297
button = self.buttond.get(event.button())
288298
if button is not None:
289299
FigureCanvasBase.button_release_event(self, x, y, button,
@@ -292,9 +302,7 @@ def mouseReleaseEvent(self, event):
292302
print('button released')
293303

294304
def wheelEvent(self, event):
295-
x = event.x()
296-
# flipy so y=0 is bottom of canvas
297-
y = self.figure.bbox.height - event.y()
305+
x, y = self.mouseEventCoords(event)
298306
# from QWheelEvent::delta doc
299307
if event.pixelDelta().x() == 0 and event.pixelDelta().y() == 0:
300308
steps = event.angleDelta().y() / 120
@@ -324,8 +332,8 @@ def keyReleaseEvent(self, event):
324332
print('key release', key)
325333

326334
def resizeEvent(self, event):
327-
w = event.size().width()
328-
h = event.size().height()
335+
w = event.size().width() * self._dpi_ratio
336+
h = event.size().height() * self._dpi_ratio
329337
if DEBUG:
330338
print('resize (%d x %d)' % (w, h))
331339
print("FigureCanvasQt.resizeEvent(%d, %d)" % (w, h))

lib/matplotlib/backends/backend_qt5agg.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ def __init__(self, figure):
6767
self._agg_draw_pending = False
6868

6969
def drawRectangle(self, rect):
70-
self._drawRect = rect
70+
if rect is not None:
71+
self._drawRect = [pt / self._dpi_ratio for pt in rect]
72+
else:
73+
self._drawRect = None
7174
self.update()
7275

7376
def paintEvent(self, e):
@@ -101,6 +104,9 @@ def paintEvent(self, e):
101104
qImage = QtGui.QImage(stringBuffer, self.renderer.width,
102105
self.renderer.height,
103106
QtGui.QImage.Format_ARGB32)
107+
if hasattr(qImage, 'setDevicePixelRatio'):
108+
# Not available on Qt4 or some older Qt5.
109+
qImage.setDevicePixelRatio(self._dpi_ratio)
104110
# get the rectangle for the image
105111
rect = qImage.rect()
106112
p = QtGui.QPainter(self)
@@ -111,7 +117,9 @@ def paintEvent(self, e):
111117

112118
# draw the zoom rectangle to the QPainter
113119
if self._drawRect is not None:
114-
p.setPen(QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.DotLine))
120+
pen = QtGui.QPen(QtCore.Qt.black, 1 / self._dpi_ratio,
121+
QtCore.Qt.DotLine)
122+
p.setPen(pen)
115123
x, y, w, h = self._drawRect
116124
p.drawRect(x, y, w, h)
117125
p.end()
@@ -136,18 +144,24 @@ def paintEvent(self, e):
136144
stringBuffer = reg.to_string_argb()
137145
qImage = QtGui.QImage(stringBuffer, w, h,
138146
QtGui.QImage.Format_ARGB32)
147+
if hasattr(qImage, 'setDevicePixelRatio'):
148+
# Not available on Qt4 or some older Qt5.
149+
qImage.setDevicePixelRatio(self._dpi_ratio)
139150
# Adjust the stringBuffer reference count to work
140151
# around a memory leak bug in QImage() under PySide on
141152
# Python 3.x
142153
if QT_API == 'PySide' and six.PY3:
143154
ctypes.c_long.from_address(id(stringBuffer)).value = 1
144155

156+
origin = QtCore.QPoint(l, self.renderer.height - t)
145157
pixmap = QtGui.QPixmap.fromImage(qImage)
146-
p.drawPixmap(QtCore.QPoint(l, self.renderer.height-t), pixmap)
158+
p.drawPixmap(origin / self._dpi_ratio, pixmap)
147159

148160
# draw the zoom rectangle to the QPainter
149161
if self._drawRect is not None:
150-
p.setPen(QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.DotLine))
162+
pen = QtGui.QPen(QtCore.Qt.black, 1 / self._dpi_ratio,
163+
QtCore.Qt.DotLine)
164+
p.setPen(pen)
151165
x, y, w, h = self._drawRect
152166
p.drawRect(x, y, w, h)
153167

@@ -198,9 +212,11 @@ def blit(self, bbox=None):
198212
bbox = self.figure.bbox
199213

200214
self.blitbox.append(bbox)
201-
l, b, w, h = bbox.bounds
215+
216+
# repaint uses logical pixels, not physical pixels like the renderer.
217+
l, b, w, h = [pt / self._dpi_ratio for pt in bbox.bounds]
202218
t = b + h
203-
self.repaint(l, self.renderer.height-t, w, h)
219+
self.repaint(l, self.renderer.height / self._dpi_ratio - t, w, h)
204220

205221
def print_figure(self, *args, **kwargs):
206222
FigureCanvasAgg.print_figure(self, *args, **kwargs)
@@ -226,6 +242,11 @@ def __init__(self, figure):
226242
super(FigureCanvasQTAgg, self).__init__(figure=figure)
227243
self._drawRect = None
228244
self.blitbox = []
245+
# We don't want to scale up the figure DPI more than once.
246+
# Note, we don't handle a signal for changing DPI yet.
247+
if not hasattr(self.figure, '_original_dpi'):
248+
self.figure._original_dpi = self.figure.dpi
249+
self.figure.dpi = self._dpi_ratio * self.figure._original_dpi
229250
self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent)
230251

231252

lib/matplotlib/figure.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,8 @@ def set_size_inches(self, w, h=None, forward=True):
713713
self.bbox_inches.p1 = w, h
714714

715715
if forward:
716-
dpival = self.dpi
716+
ratio = getattr(self.canvas, '_dpi_ratio', 1)
717+
dpival = self.dpi / ratio
717718
canvasw = w * dpival
718719
canvash = h * dpival
719720
manager = getattr(self.canvas, 'manager', None)

0 commit comments

Comments
 (0)
0