相关文章推荐
打盹的地瓜  ·  【第 23 話】DKOM 隱藏 ...·  5 月前    · 
奔跑的遥控器  ·  Shell ...·  1 年前    · 
想发财的打火机  ·  Microsoft Visual C++ ...·  1 年前    · 
central_widget = QWidget() vbox=QtWidgets.QVBoxLayout(central_widget) Scroll = QScrollBar(Qt.Horizontal, central_widget) Slider = QSlider(Qt.Horizontal, central_widget) Slider.setRange(1, 100) chartview = QChartView(chart, central_widget) vbox.addWidget(chartview) vbox.addWidget(Slider) vbox.addWidget(Scroll) def scale(): step=Slider.value()/100 print(step) update() def update(evt=None): r = Scroll.value() / ((1 + step) * 100) #???????????????????? print(r) Slider.actionTriggered.connect(scale) Scroll.actionTriggered.connect(update) ui.setGeometry(70, 70, 400, 300) ui.setCentralWidget(central_widget) ui.show() sys.exit(app.exec_())

This is how I did in pyqt5+matplotlib, based on the 例子:

class ScrollableWindow(QtWidgets.QMainWindow):
    def __init__(self, fig, ax, step=0.1):
        plt.close("all")
        self.qapp = QtWidgets.QApplication([])
        QtWidgets.QMainWindow.__init__(self)
        self.widget = QtWidgets.QWidget()
        self.setCentralWidget(self.widget)
        self.vbox=QtWidgets.QVBoxLayout(self.widget)
        self.gbox = QtWidgets.QHBoxLayout(self.widget)
        self.vkl = 1
        self.ln=0
        self.ln1 = 0
        self.step = step
        self.fig = fig
        self.ax = ax
        self.canvas = FigureCanvas(self.fig)
        self.canvas.draw()
        self.scroll = QtWidgets.QScrollBar(QtCore.Qt.Horizontal)
        self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.slider.setRange(1, 100)
        self.setupSlider()
        self.nav = NavigationToolbar(self.canvas, self.widget)
        self.vbox.addWidget(self.canvas)
        self.vbox.addWidget(self.scroll)
        self.gbox.addWidget(self.slider)
        self.gbox.addWidget(self.nav)
        self.gbox.addStretch(1)
        self.vbox.addLayout(self.gbox)
        self.setLayout(self.vbox)
        self.canvas.draw()
        self.show()
        self.qapp.exec_()
    def scale(self):
        self.step = self.slider.sliderPosition()/100.0
        self.update()
    def setupSlider(self):
        self.lims = np.array(self.ax.get_xlim())
        self.scroll.setPageStep(self.step * 100)#ax.get_xlim() 
        self.scroll.actionTriggered.connect(self.update)
        self.slider.actionTriggered.connect(self.scale)
        self.update()
    def update(self, evt=None):
        r = self.scroll.value() / ((1 + self.step) * 100)
        l1 = self.lims[0] + r * np.diff(self.lims)
        l2 = l1 + np.diff(self.lims) * self.step
        self.ax.set_xlim(l1, l2) # Show only this section of the x-axis coordinate
        if l1>0 and l2>0 and l2<(len(z)-1): # auto height chart
            xmin = np.amin(z[int(l1):int(l2)])
            xmax = np.amax(z[int(l1):int(l2)])
            self.ax.set_ylim([xmin, xmax])
        self.fig.canvas.draw_idle()
x = pd.read_csv('file.txt',
                    index_col='DATE',
                    parse_dates=True,
                    infer_datetime_format=True)
z = x.iloc[:, 3].values
N = len(z)
ind = np.arange(N)
fig, ax = plt.subplots()
ax.plot(ind, z)
a = ScrollableWindow(fig,ax)
    
5 个评论
我理解你关于滚动条的问题,但不理解关于缩放的问题,我解释一下:缩放可以应用于一个轴或两个轴,也有zoomIn和zoomOut,在你的情况下是zoomIn、zoomOut还是两个轴?
我只需要在X轴(水平方向)上进行放大、缩小。我添加了GIF 动画,因为有一个水平的增加。它是pyqt5+matplotlib。
你可以提供一个最低限度的可重复的例子迄今为止,你所拥有的以及产生你在GIF中所展示的代码,将其作为我可能的解决方案的基础。
我还是在图表上另外把顶部和底部调整到窗口的高度,这样顶部和底部就没有空距离了。我把它放在主窗口里。这在我甚至从你的例子中取得。
如果你想得到帮助,请提供我所要求的东西
python
pyqt5
inquirer
inquirer
发布于 2019-08-28
2 个回答
eyllanesc
eyllanesc
发布于 2020-12-18
已采纳
0 人赞同

由于你没有解释变焦的要求(见我的评论),我不会在这个答案中实现这一部分。

QtCharts中滚动的一般逻辑是设置轴的最小和最大属性,而这些最小和最大属性取决于QXSerie和QXAxis的类型,例如,如果它是一个带有QValueAxis的QLineSeries,它们所取的值可以是所有真实的,但如果它是一个带有QCategoryAxis的QCandlestickSeries,它们只取类别名称。

假设你使用的逻辑与我之前的回答相同,那么类别对应于一串整数值,这些整数值是QLineSeries显示的值,所以当你计算极限时,你应该采用这个参考。

另一方面,在QtCharts中没有get_xlim,所以你必须手动计算它,考虑到这种情况,它与数据的数量相符。

from PyQt5 import QtCore, QtGui, QtWidgets, QtChart
import math
import numpy as np
import pandas as pd
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()
        self._line_serie = QtChart.QLineSeries()
        tm = []
        df = pd.read_csv(
            "https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv"
        name_of_columns = ("AAPL.Open", "AAPL.High", "AAPL.Low", "AAPL.Close", "mavg")
        for i, (o, h, l, c, v) in enumerate(
            zip(*(df[name] for name in name_of_columns))
            self._candlestick_serie.append(QtChart.QCandlestickSet(o, h, l, c))
            self._line_serie.append(QtCore.QPointF(i, v))
            tm.append(str(i))
        min_x, max_x = 0, i
        self._chart.addSeries(self._candlestick_serie)
        self._chart.addSeries(self._line_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)
        self._chart.axisX(self._line_serie).setRange(value_min, value_max)
    @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):
        print(value)
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._chart_view = QtChart.QChartView()
        self.scrollbar = QtWidgets.QScrollBar(
            QtCore.Qt.Horizontal, sliderMoved=self.recalculate_range, pageStep=10
        self.slider = QtWidgets.QSlider(
            QtCore.Qt.Horizontal,
            sliderMoved=self.recalculate_range,
            minimum=0,
            maximum=100,
            value=60,
        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._line_serie = QtChart.QLineSeries(name="Data")
        x = pd.read_csv(
            "file.txt", index_col="DATE", parse_dates=True, infer_datetime_format=True
        self._z = x.iloc[:, 3].values
        N = len(self._z)
        for i, v in enumerate(self._z):
            self._line_serie.append(QtCore.QPointF(i, v))
        self.lims = 0, N
        self._chart.addSeries(self._line_serie)
        self._chart.createDefaultAxes()
        # self._chart.legend().hide()
        # self._chart.setAnimationOptions(QtChart.QChart.SeriesAnimations)
        self._chart_view.setChart(self._chart)
        self.recalculate_range()
    def recalculate_range(self):
        m, M = self.lims
        step = self.slider.sliderPosition() / 100.0
        r = self.scrollbar.value() / ((1 + step) * 100.0)
        xmin = m + r * np.diff(self.lims)
        xmax = xmin + np.diff(self.lims) * step
        self._chart.axisX(self._line_serie).setRange(xmin, xmax)
        if xmin > 0 and xmax > 0 and xmax < M:
            ymin = np.amin(self._z[int(xmin) : int(xmax)])
            ymax = np.amax(self._z[int(xmin) : int(xmax)])
            self._chart.axisY(self._line_serie).setRange(ymin, ymax)
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
    
谢谢,eyllanesc!
Rémi G
Rémi G
发布于 2020-12-18
0 人赞同

为了记录在案,我写了一个依赖性较少的小函数,它的工作做得非常好(更好/更简单)。

我使用了两个滑块而不是一个滑块和一个滚动条,但这是一个细节。

有了这个,你就能放大图表,并正确地平移一切(如果你放大了2%,你就能在丢失的2%上从0%平移到100%,并且不会有一个高于你的序列最大值的最大值)。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""This function is using two QSliders to zoom and pan on a QChart"""
def zoom_and_pan(chart, max_val, slider_zoom, slider_pan):
    """Use two sliders to zoom and pan on a QChart
    :args:
    :arg chart:         Chart on which zoom and plot
    :arg max_val:       Maximum value used to plot the graph
                        (usually the last x value of your serie)
    :arg slider_zoom:   Slider [0, 1+] to zoom on the graph
    :arg slider_pan:    Slider [0, 1+] to pan the graph
    :type chart:        QChart()
    :type max_val:      Float()
    :type slider_zoom:  QSlider()
    :type slider_pan:   QSlider()"""
    zoom_ratio = slider_zoom.sliderPosition() / (
        slider_zoom.maximum() * 1.001)
    step = 1 - zoom_ratio
    pan_level = slider_pan.sliderPosition() * zoom_ratio / slider_pan.maximum()
    min_chart = pan_level * max_val
    if slider_pan.sliderPosition() == slider_pan.maximum():