Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I'm trying to add custom
AxisItem
in pyqtgraph to existing
PlotWidget
that was generated by Qt Designer. There is related topic
here
, but there is no exact answer with code example and I cannot comment, so I've created a new topic.
This is my custom
AxisItem
(based on
this
code):
import pyqtgraph as pg
import datetime
def int2td(ts):
return(datetime.timedelta(seconds=float(ts)/1e6))
class TimeAxisItem(pg.AxisItem):
def __init__(self, *args, **kwargs):
super(TimeAxisItem, self).__init__(*args, **kwargs)
def tickStrings(self, values, scale, spacing):
return [int2dt(value).strftime("%H:%M:%S") for value in values]
This is my main QtPlotter class:
from pyqtgraph.Qt import QtGui
from template_pyqt import Ui_Form # Ui_Form is generated by Qt Designer
class QtPlotter:
def __init__(self):
self.app = QtGui.QApplication([])
self.win = QtGui.QWidget()
self.ui = Ui_Form()
self.ui.setupUi(self.win)
self.win.show()
self.ui_plot = self.ui.plot
self.ui_plot.showGrid(x=True, y=True)
And then I'm trying to add my custom AxisItem:
self.ui_plot.getPlotItem().axes['bottom']['item'] = TimeAxisItem(orientation='bottom')
I have no errors, but this does not give any effect.
It was so easy. The PlotItem class does not have a setAxis method. Instead of that there is a method named setAxisItems. this code worked for me.
date_axis = pg.graphicsItems.DateAxisItem.DateAxisItem(orientation = 'bottom')
self.mainSoundPlot.setAxisItems(axisItems = {'bottom': date_axis})
I know this is an old post but I am encountering a similar issue and came across a solution in this gist example, which is an AxisItem subclass that implements an attachToPlotItem
method.
So regarding the original post, instead of
self.ui_plot.getPlotItem().axes['bottom']['item'] = TimeAxisItem(orientation='bottom')
you need the following method (copied from the example linked above) in your TimeAxisItem subclass:
def attachToPlotItem(self, plotItem):
"""Add this axis to the given PlotItem
:param plotItem: (PlotItem)
self.setParentItem(plotItem)
viewBox = plotItem.getViewBox()
self.linkToView(viewBox)
self._oldAxis = plotItem.axes[self.orientation]['item']
self._oldAxis.hide()
plotItem.axes[self.orientation]['item'] = self
pos = plotItem.axes[self.orientation]['pos']
plotItem.layout.addItem(self, *pos)
self.setZValue(-1000)
It even retains the original AxisItem so that it could be re-instated if needed.
Then in your QtPlotter constructor, you'd add
axis = TimeAxisItem(orientation='bottom')
axis.attactToPlotItem(self.ui_plot.getPlotItem())
The PlotItem
class does not have a setAxis
method, only a getAxis
method to get the current axis. You can specify a dictionary with axis items in the axisItems
parameter of the PlotItem
constructor, but it doesn't seem possible to update an AxisItem
of an existing PlotItem
.
Even though the PlotItem.axes
dictionary is a public attribute, it is undocumented and just using it is therefore a bit risky. There is a possibility that the author of PyQtGraph will alter its behavior, or rename it (although the chance of this happening is small). IMHO it should have been made a private attribute.
In any case, by looking at the source of the PlotItem
constructor you can see how the axis items from axisItem
parameter are added to the plot item:
## Create and place axis items
if axisItems is None:
axisItems = {}
self.axes = {}
for k, pos in (('top', (1,1)), ('bottom', (3,1)), ('left', (2,0)), ('right', (2,2))):
if k in axisItems:
axis = axisItems[k]
else:
axis = AxisItem(orientation=k, parent=self)
axis.linkToView(self.vb)
self.axes[k] = {'item': axis, 'pos': pos}
self.layout.addItem(axis, *pos)
axis.setZValue(-1000)
axis.setFlag(axis.ItemNegativeZStacksBehindParent)
Perhaps you can make it work by looking at the code above. Again, this is undocumented behavior, use at your own risk! Furthermore, you should properly remove and unlink the old AxisItem
when setting a new one to prevent memory leaks. Perhaps this is tricky and this could be the reason why the PlotItem.setAxis
method does not exist.
I looked into the source of the PlotItem
constructor for a complete day, but I couldn't get it to work.
In the end, I found that QtDesigner/QtCreator only outputs three lines on the PlotWidget. Instead of trying to add a TimeAxisItem to the existing PlotWidget, it is easier (but definitely not nicer) to just delete the existing PlotWidget and then make a new one with a TimeAxisItem, as described here.
from PyQt5 import QtCore
import pyqtgraph as pg
parent = self.ui_plot.parent()
geom_object = self.ui_plot.frameGeometry()
geometry = QtCore.QRect(geom_object.left(), geom_object.top(), geom_object.width(), geom_object.height())
object_name = self.ui_plot.objectName()
del self.ui_plot
time_axis = TimeAxisItem(orientation='bottom')
self.ui_plot = pg.PlotWidget(parent, axisItems={'bottom': time_axis})
self.ui_plot.setGeometry(geometry)
self.ui_plot.setObjectName(object_name)
Since there are people that try to find something here, I will post my simple but not elegant workaround.
After converting my template generated by Qt Designer to python template file with pyuic, I'm adding my custom AxisItem directly to python template file by replacing corresponding PlotWidget. This all can be done with simple bash script:
pyuic4 template.ui -o template.py
match="from PyQt4 import QtCore, QtGui"
insert_class="from timeaxisitem_class import TimeAxisItem"
match_widget="self.plot = PlotWidget(Form)"
insert_timeaxis="self.plot = PlotWidget(Form, axisItems={'bottom': TimeAxisItem(orientation='bottom')})"
file="template.py"
sed -i "s/$match/$match\n$insert_class/" $file
sed -i "s/$match_widget/$insert_timeaxis/" $file
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.