title: Are fast candlestick charts possible in Python
body: <p>I tried drawing a few thousand candles in matplotlib.
  When scrolling the chart slows down(hangs).</p>
  
  <p>Eyllanesc helped me to realize the candlestick graph in pyqt.
  The graph is beautiful and works faster than matplotlib.</p>
  
  <p>But, all the same the chart slows down when scrolling. I changed the code a little. The file data is available <a href="https://drive.google.com/file/d/1trfarfC54SeO41XN5SChJogqLwTHO6ku/view" rel="nofollow noreferrer">here</a>.</p>
  
  <p>Are relatively fast candlestick charts possible in Python, with a large amount of data?</p>
  
  <p>The fact that I have a project in C# in it tens of thousands of candles and scrolled it much faster.</p>
  
  <p>The data for drawing me offline. And I really need a lot of candles.
  Maybe there's a function to make the graph more quickly?
  (I'm not criticizing anyone, I just want to sort this out.)</p>
  
  <p>Here's how the C# chart works, with over 40,000 candles. I attach GIF animation.</p>
  
  <p><a href="https://gifyu.com/image/hnUF" rel="nofollow noreferrer">C#</a></p>
  
  <p><a href="https://gifyu.com/image/hnU0" rel="nofollow noreferrer">Python</a></p>
  
  <pre><code>from PyQt5 import QtCore, QtGui, QtWidgets, QtChart
  import math
  import numpy as np
  import pandas as pd
  
  df = pd.read_csv('file.txt',
                           index_col='DATE',
                           parse_dates=True,
                           infer_datetime_format=True)
  
  
  o = df.iloc[:, 0].values
  h = df.iloc[:, 1].values
  l = df.iloc[:, 2].values
  z = df.iloc[:, 3].values
  
  class MainWindow(QtWidgets.QMainWindow):
      def __init__(self, parent=None):
          super().__init__(parent)
  
          self.step = 0.1
          self._chart_view = QtChart.QChartView()
          self.scrollbar = QtWidgets.QScrollBar(
              QtCore.Qt.Horizontal,
              sliderMoved=self.onAxisSliderMoved,
              pageStep=self.step * 100,
          )
          self.slider = QtWidgets.QSlider(
              QtCore.Qt.Horizontal, sliderMoved=self.onZoomSliderMoved
          )
  
          central_widget = QtWidgets.QWidget()
          self.setCentralWidget(central_widget)
  
          lay = QtWidgets.QVBoxLayout(central_widget)
          for w in (self._chart_view, self.scrollbar, self.slider):
              lay.addWidget(w)
  
          self.resize(640, 480)
  
          self._chart = QtChart.QChart()
  
          self._candlestick_serie = QtChart.QCandlestickSeries()
  
  
          tm = []
  
          for i in range(0, len(z)):
              o_ = o[i]
              h_ = h[i]
              l_ = l[i]
              c_ = z[i]
              self._candlestick_serie.append(QtChart.QCandlestickSet(o_, h_, l_, c_))
              tm.append(str(i))
          min_x, max_x = 0, i
  
          self._chart.addSeries(self._candlestick_serie)
          self._chart.createDefaultAxes()
          self._chart.legend().hide()
          # self._chart.setAnimationOptions(QtChart.QChart.SeriesAnimations)
  
          self._chart.axisX(self._candlestick_serie).setCategories(tm)
          self._chart.axisX(self._candlestick_serie).setVisible(False)
  
          self._chart_view.setChart(self._chart)
          self.adjust_axes(100, 200)
          self.lims = np.array([min_x, max_x])
  
          self.onAxisSliderMoved(self.scrollbar.value())
  
      def adjust_axes(self, value_min, value_max):
          self._chart.axisX(self._candlestick_serie).setRange(
              str(value_min), str(value_max)
          )
  
          if value_min &gt; 0 and value_max &gt; 0 and value_max &lt; 10000:
              ymin = np.amin(l[int(value_min): int(value_max)])
              ymax = np.amax(h[int(value_min): int(value_max)])
              self._chart.axisY(self._candlestick_serie).setRange(ymin, ymax)
  
      @QtCore.pyqtSlot(int)
      def onAxisSliderMoved(self, value):
          r = value / ((1 + self.step) * 100)
          l1 = self.lims[0] + r * np.diff(self.lims)
          l2 = l1 + np.diff(self.lims) * self.step
          self.adjust_axes(math.floor(l1), math.ceil(l2))
  
      @QtCore.pyqtSlot(int)
      def onZoomSliderMoved(self, value):
          self.step=value/100
          self.onAxisSliderMoved(self.scrollbar.value())
          print(value)
  
  if __name__ == "__main__":
      import sys
  
      app = QtWidgets.QApplication(sys.argv)
      w = MainWindow()
      w.show()
      sys.exit(app.exec_())
  </code></pre>