To answer my own question - this is a rather well known issue, as it turns 
out. Datetime axes use a UNIX Timestamp, which is a number of seconds since 
the beginning of an epoch. This can be a float, where the fractional part 
would represent fractions of a second. Pandas uses nanosecond precision by 
design, so the decimal point is shifted to the left by 9 positions. I ended 
up using Numpy's datetime64[s] instead.

On Saturday, May 23, 2020 at 10:44:55 PM UTC+2, mks wrote:
>
> Hello,
>
> First of all, let me thank you for sharing PyQtGraph. It's amazing. I'm 
> very grateful.
>
> I am still learning it, I am especially interested in writing my own 
> GraphicsItems. I was following the "Custom Graphics" example, which plots 
> Candlesticks. In the example, the input data's x is a float. That works 
> fine for the sake of example, but in real world it would almost always be a 
> Timestamp/Datetime/equivalent. I was working on adopting this example to 
> pandas Timestamp and I hit a roadblock. Upon closer look it seems that 
> pandas Timestamp's nanosecond-precision is an issue, i.e. if I use the 
> float value of the timestamp, the picture's boundingRect is calculated 
> incorrectly. However, if I reduce precision to seconds by dividing the 
> float by 10**9, it works fine. That leads me to believe there is some kind 
> of overflow error somewhere along the way. I am not sure how to approach 
> this. Simply dividing by 10**9 is an ok workaround for now, but it seems 
> hacky to me. Below please find example code with two classes: 
> "CandlestickItemWorking" and "CandlestickNotWorking". You can switch 
> between them by commenting/uncommenting lines 77/78 to reproduce.
>
> Happy to hear your thoughts, perhaps it's a beginner's mistake on my part.
>
> Kind Regards,
> mks
>
> """
> Demonstrate creation of a custom graphic (a candlestick plot)
>
> """
> import initExample  ## Add path to library (just for examples; you do not 
> need this)
>
> import pyqtgraph as pg
> from pyqtgraph import QtCore, QtGui
> import pandas as pd
>
>
> class CandlestickItemWorking(pg.GraphicsObject):
>     def __init__(self, data):
>         pg.GraphicsObject.__init__(self)
>         self.data = data  ## data must have fields: time, open, close, min, 
> max
>         self.generatePicture()
>
>     def generatePicture(self):
>         self.picture = QtGui.QPicture()
>         p = QtGui.QPainter(self.picture)
>         p.setPen(pg.mkPen('w'))
>         w = (self.data[1][0] - self.data[0][0]).value / (3. * 10**9)
>
>         for (t, open, close, min, max) in self.data:
>             p.drawLine(QtCore.QPointF(t.value / 10**9, min), 
> QtCore.QPointF(t.value / 10**9, max))
>             if open > close:
>                 p.setBrush(pg.mkBrush('r'))
>             else:
>                 p.setBrush(pg.mkBrush('g'))
>             p.drawRect(QtCore.QRectF(t.value/10**9 - w, open, w * 2, close - 
> open))
>         p.end()
>
>     def paint(self, p, *args):
>         p.drawPicture(0, 0, self.picture)
>
>     def boundingRect(self):
>         return QtCore.QRectF(self.picture.boundingRect())
>
>
> class CandlestickItemNotWorking(pg.GraphicsObject):
>     def __init__(self, data):
>         pg.GraphicsObject.__init__(self)
>         self.data = data
>         self.generatePicture()
>
>     def generatePicture(self):
>         self.picture = QtGui.QPicture()
>         p = QtGui.QPainter(self.picture)
>         p.setPen(pg.mkPen('w'))
>         w = (self.data[1][0] - self.data[0][0]).value / 3.
>
>         for (t, open, close, min, max) in self.data:
>             p.drawLine(QtCore.QPointF(t.value, min), QtCore.QPointF(t.value, 
> max))
>             if open > close:
>                 p.setBrush(pg.mkBrush('r'))
>             else:
>                 p.setBrush(pg.mkBrush('g'))
>             p.drawRect(QtCore.QRectF(t.value - w, open, w * 2, close - open))
>         p.end()
>
>     def paint(self, p, *args):
>         p.drawPicture(0, 0, self.picture)
>
>     def boundingRect(self):
>         return QtCore.QRectF(self.picture.boundingRect())
>
>
> data = [  ## fields are (time, open, close, min, max).
>     (pd.Timestamp('2020-03-01 00:00:00'), 10, 13, 5, 15),
>     (pd.Timestamp('2020-03-01 00:01:00'), 13, 17, 9, 20),
>     (pd.Timestamp('2020-03-01 00:02:00'), 17, 14, 11, 23),
>     (pd.Timestamp('2020-03-01 00:03:00'), 14, 15, 5, 19),
>     (pd.Timestamp('2020-03-01 00:04:00'), 15, 9, 8, 22),
>     (pd.Timestamp('2020-03-01 00:05:00'), 9, 15, 8, 16),
> ]
>
> item = CandlestickItemWorking(data)
> # item = CandlestickItemNotWorking(data)
> plt = pg.plot()
> plt.addItem(item)
> plt.setWindowTitle('pyqtgraph example: customGraphicsItem')
>
> ## Start Qt event loop unless running in interactive mode or using pyside.
> if __name__ == '__main__':
>     import sys
>
>     if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
>         QtGui.QApplication.instance().exec_()
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pyqtgraph/50f2cca4-56e9-45fa-bb27-077ef583e77bo%40googlegroups.com.

Reply via email to