Я пытаюсь добавить метки осей x и y к некоторым графикам, но я терпел неудачу при каждой попытке того, что я пробовал.Есть некоторые фундаментальные вещи, которые мне не хватает.
В этом (сокращенном) приложении у меня есть два графических виджета для отображения на основе классов graphicsView и graphicsScene.Когда вы смотрите на мою последнюю попытку создания осей, вы видите:
- Числа растягиваются очень сильно, когда их вообще не нужно масштабировать
- Если я не используюстрока self.scene (). setSceneRect (QtCore.QRectF (self.viewport (). rect ())) тогда один граф имеет огромное количество пустого пространства над и под ним, graphicsScene, кажется, намного больше, чем область просмотра.
На обоих графиках не должно быть пробелов и вертикальных полос прокрутки.Я пытался получить (0, 0), чтобы быть в левом нижнем углу и все позиции относительно него.Если я использую эту линию, то она масштабируется, хотя я не хочу этого. - Оси масштабируются.Они должны иметь фиксированное положение и размер.
- Какой бы график я ни устанавливал для возможности масштабирования (в отличие от минимального и максимального размеров), ДРУГОЙ график масштабируется.
Я пытался установитьфлаги, чтобы игнорировать масштабирование.Я попытался установить NoAnchor, чтобы все было правильно.В конце концов я помещу все элементы оси в QGraphicsItemGroup, но мне нужно понять, как масштабировать и позиционировать в graphicsScene.
Что я здесь не так делаю?Как я могу достичь этих вещей?Можно ли стилизовать всю графическую сцену с помощью CSS?Я просто хочу хорошо выглядящие оси, которые не масштабируются, но будут перерисовываться всякий раз, когда человек увеличивает или уменьшает график.
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
class GraphItem(QtWidgets.QGraphicsPixmapItem):
def __init__(self, xdata, ydata, width, height, parent=None):
super(GraphItem, self).__init__(parent)
self._xdata = xdata
self._ydata = ydata
self._size = QtCore.QSize(width, height)
self.redraw()
def redraw(self):
x_final = self._xdata[-1]
pixmap = QtGui.QPixmap(self._size)
pixmap_height = pixmap.height()
pixmap.fill(QtGui.QColor("lightblue"))
painter = QtGui.QPainter(pixmap)
pen = QtGui.QPen(QtGui.QColor("green"))
pen.setWidth(.5)
painter.setPen(pen)
for i, (x, y) in enumerate(
zip(self._xdata, self._ydata / np.max(np.abs(self._ydata)))
):
x_pos = int(x * self._size.width() / x_final)
y_pos = abs(int(y * pixmap_height))
painter.drawLine(x_pos, 0, x_pos, y_pos)
painter.end()
self.setPixmap(pixmap)
class AxisLabelItem(QtWidgets.QGraphicsRectItem):
def __init__(self, parent=None):
axis_width, axis_height = 3000, 300 # make up some numbers
super(AxisLabelItem, self).__init__(parent)
self.setPen(QtGui.QPen(QtGui.QColor("purple"), 1))
self.setBrush(QtGui.QColor("orange"))
if False:
self.setFlags(
self.flags()
| QtWidgets.QGraphicsItem.ItemIgnoresTransformations
)
class VerticalRectangleItem(QtWidgets.QGraphicsRectItem):
def __init__(self, parent=None):
super(VerticalRectangleItem, self).__init__(parent)
def itemChange(self, change, value):
if change == QtWidgets.QGraphicsItem.ItemPositionChange and self.scene():
newPos = self.pos()
newPos.setX(value.x())
return newPos
return super(VerticalRectangleItem, self).itemChange(change, value)
class GraphicsView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
from random import randint, shuffle
super(GraphicsView, self).__init__(parent)
self.verticalScrollBar().hide()
super(GraphicsView, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
self.setScene(scene)
self.scale(1, -1)
self.can_rescale = True
self.setMinimumHeight(200)
for i in range(1):
r = QtCore.QRectF(
QtCore.QPointF(0, -10),
QtCore.QSizeF(2200, 30),
)
it = AxisLabelItem(r)
it.setPen(QtGui.QPen(QtGui.QColor("yellow"), 1))
it.setBrush(QtGui.QColor(0, 0, 255, 127))
self.scene().addItem(it)
it.setFlags(
it.flags()
| QtWidgets.QGraphicsItem.ItemSendsGeometryChanges
)
font = QtGui.QFont('Hevletica')
font.setPointSize(10)
for i in range(60):
l = QtWidgets.QGraphicsTextItem(str(i))
l.setFont(font)
l.setFlags(
l.flags()
| QtWidgets.QGraphicsItem.ItemIgnoresTransformations
)
l.setZValue(100)
l.setPos(i*50, 230)
self.scene().addItem(l)
#self.resizeAnchor(QtWidgets.QGraphicsView.NoAnchor)
def setRescale(self, can_rescale=True):
self.can_rescale = can_rescale
def resizeEvent(self, event):
if self.can_rescale:
h = self.mapToScene(self.viewport().rect()).boundingRect().height()
r = self.sceneRect()
r.setHeight(h)
self.setSceneRect(r)
else:
self.scene().setSceneRect(QtCore.QRectF(self.viewport().rect()))
#self.scene().setSceneRect()
pass
#self.scene().setSceneRect(QtCore.QRectF())
height = self.viewport().height()
for item in self.items():
item_height = item.boundingRect().height()
tr = QtGui.QTransform()
tr.scale(1, height / item_height)
item.setTransform(tr)
super(GraphicsView, self).resizeEvent(event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
tab_widget_top = QtWidgets.QTabWidget(tabPosition=QtWidgets.QTabWidget.West)
tab_widget_bottom = QtWidgets.QTabWidget(tabPosition=QtWidgets.QTabWidget.West)
self.graphics_view_top = GraphicsView()
self.graphics_view_bottom = GraphicsView()
# Comment out this below line
self.graphics_view_top.setRescale(False)
#self.graphics_view_bottom.setRescale(False)
container = QtWidgets.QWidget()
self.setCentralWidget(container )
lay = QtWidgets.QVBoxLayout(container)
lay.addWidget(tab_widget_top)
lay.addWidget(tab_widget_bottom)
container.setLayout(lay)
tab_widget_top.addTab(self.graphics_view_top, "main")
tab_widget_bottom.addTab(self.graphics_view_bottom, "main")
self.resize(800, 600)
side, offset, height = 50, 200, 400
np.random.seed(777)
x_time = np.linspace(0, 12.56, 3000)
rand_data = np.random.uniform(0.0, 1.0, 3000)
data = 0.45 * (np.sin(2 * x_time) + rand_data) - 0.25 * (np.sin(3 * x_time))
graph_item_top = GraphItem(x_time, data, 3000, height)
graph_item_top.setPos(QtCore.QPoint(0, 30))
self.graphics_view_top.scene().addItem(graph_item_top)
graph_item_bottom = GraphItem(x_time, data, 3000, height)
graph_item_bottom.setPos(QtCore.QPoint(0, 30))
self.graphics_view_bottom.scene().addItem(graph_item_bottom)
for i in range(2):
r = QtCore.QRectF(
QtCore.QPointF((i + 1) * offset + i * 2 * side, 30),
QtCore.QSizeF(side, height),
)
it = VerticalRectangleItem(r)
it.setPen(QtGui.QPen(QtGui.QColor("red"), 2))
it.setBrush(QtGui.QColor(255, 0, 0, 127))
self.graphics_view_top.scene().addItem(it)
it.setFlags(
it.flags()
| QtWidgets.QGraphicsItem.ItemIsMovable
| QtWidgets.QGraphicsItem.ItemSendsGeometryChanges
)
axis_top = AxisLabelItem()
axis_bottom = AxisLabelItem()
self.graphics_view_top.scene().addItem(axis_top)
self.graphics_view_top.scene().addItem(axis_bottom)
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
ret = app.exec_()
sys.exit(ret)
if __name__ == "__main__":
main()