Ejemplo n.º 1
0
    def __init__(self, surface):
        super(SurfaceGraph, self).__init__()

        self.m_graph = surface
        self.m_graph.setAxisX(QValue3DAxis())
        self.m_graph.setAxisY(QValue3DAxis())
        self.m_graph.setAxisZ(QValue3DAxis())

        self.m_sqrtSinProxy = QSurfaceDataProxy()
        self.m_sqrtSinSeries = QSurface3DSeries(self.m_sqrtSinProxy)
        self.fillSqrtSinProxy()

        heightMapImage = QImage(
            QFileInfo(__file__).absolutePath() + '/mountain.png')
        self.m_heightMapProxy = QHeightMapSurfaceDataProxy(heightMapImage)
        self.m_heightMapSeries = QSurface3DSeries(self.m_heightMapProxy)
        self.m_heightMapSeries.setItemLabelFormat(
            "(@xLabel, @zLabel): @yLabel")
        self.m_heightMapProxy.setValueRanges(34.0, 40.0, 18.0, 24.0)
        self.m_heightMapWidth = heightMapImage.width()
        self.m_heightMapHeight = heightMapImage.height()

        self.m_axisMinSliderX = None
        self.m_axisMaxSliderX = None
        self.m_axisMinSliderZ = None
        self.m_axisMaxSliderZ = None
        self.m_rangeMinX = 0.0
        self.m_rangeMinZ = 0.0
        self.m_stepX = 0.0
        self.m_stepZ = 0.0
Ejemplo n.º 2
0
    def __init__(self, scatter):
        super(ScatterDataModifier, self).__init__()

        self.m_graph = scatter
        self.m_inputHandler = CustomInputHandler()

        self.m_graph.activeTheme().setType(Q3DTheme.ThemeDigia)
        self.m_graph.setShadowQuality(QAbstract3DGraph.ShadowQualityMedium)
        self.m_graph.scene().activeCamera().setCameraPreset(
            Q3DCamera.CameraPresetFront)

        self.m_graph.setAxisX(QValue3DAxis())
        self.m_graph.setAxisY(QValue3DAxis())
        self.m_graph.setAxisZ(QValue3DAxis())

        self.m_graph.axisX().setRange(-10.0, 10.0)
        self.m_graph.axisY().setRange(-5.0, 5.0)
        self.m_graph.axisZ().setRange(-5.0, 5.0)

        series = QScatter3DSeries()
        series.setItemLabelFormat("@xLabel, @yLabel, @zLabel")
        series.setMesh(QAbstract3DSeries.MeshCube)
        series.setItemSize(0.15)
        self.m_graph.addSeries(series)

        self.m_animationCameraX = QPropertyAnimation(
            self.m_graph.scene().activeCamera(), 'xRotation')
        self.m_animationCameraX.setDuration(20000)
        self.m_animationCameraX.setStartValue(0.0)
        self.m_animationCameraX.setEndValue(360.0)
        self.m_animationCameraX.setLoopCount(-1)

        upAnimation = QPropertyAnimation(self.m_graph.scene().activeCamera(),
                                         'yRotation')
        upAnimation.setDuration(9000)
        upAnimation.setStartValue(5.0)
        upAnimation.setEndValue(45.0)

        downAnimation = QPropertyAnimation(self.m_graph.scene().activeCamera(),
                                           'yRotation')
        downAnimation.setDuration(9000)
        downAnimation.setStartValue(45.0)
        downAnimation.setEndValue(5.0)

        self.m_animationCameraY = QSequentialAnimationGroup()
        self.m_animationCameraY.setLoopCount(-1)
        self.m_animationCameraY.addAnimation(upAnimation)
        self.m_animationCameraY.addAnimation(downAnimation)

        self.m_animationCameraX.start()
        self.m_animationCameraY.start()

        self.m_graph.setActiveInputHandler(self.m_inputHandler)

        self.m_selectionTimer = QTimer()
        self.m_selectionTimer.setInterval(10)
        self.m_selectionTimer.timeout.connect(self.triggerSelection)
        self.m_selectionTimer.start()
Ejemplo n.º 3
0
    def __init__(self, surface):
        super(SurfaceGraph, self).__init__()

        self.m_graph = surface
        self.m_graph.setAxisX(QValue3DAxis())
        self.m_graph.setAxisY(QValue3DAxis())
        self.m_graph.setAxisZ(QValue3DAxis())
        self.m_sqrtSinProxy = QSurfaceDataProxy()
        self.m_sqrtSinSeries = QSurface3DSeries(self.m_sqrtSinProxy)
        self.fillSqrtSinProxy()
        self.m_graph.addSeries(self.m_sqrtSinSeries)
Ejemplo n.º 4
0
    def __init__(self,parent=None):
        super(Qtw.QWidget, self).__init__(parent)

        self.setWindowTitle("Equation interpreter")

        self.mainLayout=Qtw.QGridLayout(self)
        self.setLayout(self.mainLayout)

        # Create label #
        self.mainlabel = Qtw.QLabel("Type your equation here, must be a function of (x,y):")
        self.mainLayout.addWidget(self.mainlabel,0,0)

        # Create textbox #
        self.textbox = QLineEdit(self)
        self.mainLayout.addWidget(self.textbox,1,0)

        # Create LaTeX viewer # 
        self.viewer = Qtw.QLabel()
        self.viewer.setPixmap(mathTex_to_QPixmap('$ ... $', 15))
        self.mainLayout.addWidget(self.viewer,2,0)

        # Create graph visualizer #
        self.cubesize = CubeSize(4,8,8)
        self.graph = Q3DSurface()
        self.screenSize = self.graph.screen().size()
        self.graph.setAspectRatio(2.0)
        self.graph.setAxisX(QValue3DAxis())
        self.graph.setAxisY(QValue3DAxis())
        self.graph.setAxisZ(QValue3DAxis())
        self.graph.axisX().setTitle("Depth")
        self.graph.axisY().setTitle("Height")
        self.graph.axisZ().setTitle("Width")
        self.functionProxy = QSurfaceDataProxy()
        self.functionSeries = QSurface3DSeries(self.functionProxy)
        self.graphvisualizer = Qtw.QWidget.createWindowContainer(self.graph)
        self.graphvisualizer.setMinimumSize(QSize(self.screenSize.width()/3, self.screenSize.height()/2))
        self.mainLayout.addWidget(self.graphvisualizer,3,0)
        
        # Create a button in the window #
        self.button = QPushButton('Display equation', self)
        self.mainLayout.addWidget(self.button,1,1)

        # Connect button to function on_click #
        self.button.clicked.connect(self.on_click)

        # Connect the enter key to button #
        self.buttonShortcut = QShortcut(QKeySequence(QtCore.Qt.Key_Return), self.button)
        self.buttonShortcut.activated.connect(self.on_click)
Ejemplo n.º 5
0
    def setupGraph(self):
        """Load data and set up the window for the bar graph."""
        header_label = QLabel(
            "Average Monthly Temperatures in Reykjavík, Iceland 1990-2000 (˚C)"
        )
        header_label.setAlignment(Qt.AlignCenter)

        # Load the data about average temperatures in Reykjavík from the CSV file
        temperature_data = self.loadCSVFile()
        # Select 11 sample years: 1990-2000. Don't select the first and last columns
        rows, columns = temperature_data.shape
        years = temperature_data[rows - 11:rows, 1]
        monthly_temps = temperature_data[rows - 11:rows,
                                         2:columns - 1].astype(float)

        bar_graph = Q3DBars()  # Create instance for bar graph
        bar_graph.scene().activeCamera().setCameraPreset(
            Q3DCamera.CameraPresetFront)

        # Create a list of QBarDataItem objects
        data_items = []
        for row in monthly_temps:
            data_items.append([QBarDataItem(value) for value in row])

        months = [
            "January", "February", "March", "April", "May", "June", "July",
            "August", "September", "October", "November", "December"
        ]

        # Create instance of QBar3DSeries, change the base color and color of
        # selected items, and add data and labels to the series
        series = QBar3DSeries()
        series.setBaseColor(QColor("#17A4D9"))
        series.setSingleHighlightColor(QColor("#F8A307"))
        series.dataProxy().addRows(data_items)
        series.dataProxy().setRowLabels(years)  # rowLabel
        series.dataProxy().setColumnLabels(months)  # colLabel

        # Create the valueLabel. Use QValue3dAxis so we can format the axis's label
        temperature_axis = QValue3DAxis()
        temperature_axis.setRange(-10, 20)
        temperature_axis.setLabelFormat(u"%.1f \N{degree sign}C")
        bar_graph.setValueAxis(temperature_axis)

        # When items in the graph are selected, a label appears overhead with information
        # about that item. Set the format of information in the label
        series.setItemLabelFormat(
            "Reykjavík - @colLabel @rowLabel: @valueLabel")

        bar_graph.addSeries(series)  # Add the series to the bar graph

        # 3D graph classes inherit QWindow, so we must use createWindowContainer() to
        # create a holder for the 3D graph in our window since they can't be used
        # as a normal widget
        container = self.createWindowContainer(bar_graph)
        v_box = QVBoxLayout()
        v_box.addWidget(header_label)
        v_box.addWidget(container, 1)
        self.setLayout(v_box)
Ejemplo n.º 6
0
    def __init__(self, bargraph):
        super(GraphModifier, self).__init__()

        self.m_graph = bargraph

        self.m_xRotation = 0.0
        self.m_yRotation = 0.0
        self.m_fontSize = 30
        self.m_segments = 4
        self.m_subSegments = 3
        self.m_minval = -20.0
        self.m_maxval = 20.0
        self.m_temperatureAxis = QValue3DAxis()
        self.m_yearAxis = QCategory3DAxis()
        self.m_monthAxis = QCategory3DAxis()
        self.m_primarySeries = QBar3DSeries()
        self.m_secondarySeries = QBar3DSeries()
        self.m_barMesh = QAbstract3DSeries.MeshBevelBar
        self.m_smooth = False

        self.m_graph.setShadowQuality(QAbstract3DGraph.ShadowQualitySoftMedium)
        self.m_graph.activeTheme().setBackgroundEnabled(False)
        self.m_graph.activeTheme().setFont(
                QFont('Times New Roman', self.m_fontSize))
        self.m_graph.activeTheme().setLabelBackgroundEnabled(True)
        self.m_graph.setMultiSeriesUniform(True)

        self.m_temperatureAxis.setTitle("Average temperature")
        self.m_temperatureAxis.setSegmentCount(self.m_segments)
        self.m_temperatureAxis.setSubSegmentCount(self.m_subSegments)
        self.m_temperatureAxis.setRange(self.m_minval, self.m_maxval)
        self.m_temperatureAxis.setLabelFormat(u"%.1f \N{degree sign}C")

        self.m_yearAxis.setTitle("Year")
        self.m_monthAxis.setTitle("Month")

        self.m_graph.setValueAxis(self.m_temperatureAxis)
        self.m_graph.setRowAxis(self.m_yearAxis)
        self.m_graph.setColumnAxis(self.m_monthAxis)

        self.m_primarySeries.setItemLabelFormat(
                "Oulu - @colLabel @rowLabel: @valueLabel")
        self.m_primarySeries.setMesh(QAbstract3DSeries.MeshBevelBar)
        self.m_primarySeries.setMeshSmooth(False)

        self.m_secondarySeries.setItemLabelFormat(
                "Helsinki - @colLabel @rowLabel: @valueLabel")
        self.m_secondarySeries.setMesh(QAbstract3DSeries.MeshBevelBar)
        self.m_secondarySeries.setMeshSmooth(False)
        self.m_secondarySeries.setVisible(False)

        self.m_graph.addSeries(self.m_primarySeries)
        self.m_graph.addSeries(self.m_secondarySeries)

        self.m_preset = Q3DCamera.CameraPresetFront
        self.changePresetCamera()

        self.resetTemperatureData()
Ejemplo n.º 7
0
    def __init__(self, bargraph):
        super(GraphModifier, self).__init__()

        self.m_graph = bargraph  # Q3DBars 实例

        self.m_xRotation = 0.0  # 水平旋转角度
        self.m_yRotation = 0.0  # 垂直旋转角度
        self.m_fontSize = 30
        self.m_segments = 4
        self.m_subSegments = 3
        self.m_minval = -20.0
        self.m_maxval = 20.0
        self.m_temperatureAxis = QValue3DAxis()  # 温度轴
        self.m_yearAxis = QCategory3DAxis()  # 年份轴
        self.m_monthAxis = QCategory3DAxis()  # 月份轴
        self.m_primarySeries = QBar3DSeries()  # 主序列
        self.m_secondarySeries = QBar3DSeries()  # 次序列
        self.m_barMesh = QAbstract3DSeries.MeshBevelBar  # 预定义的网格类型
        self.m_smooth = False  # 是否平滑

        # 阴影以柔化的边缘高质量渲染
        self.m_graph.setShadowQuality(QAbstract3DGraph.ShadowQualitySoftMedium)
        # 当前主题Q3DTheme设置背景是否可见
        self.m_graph.activeTheme().setBackgroundEnabled(False)
        # 当前主题Q3DTheme设置字体
        self.m_graph.activeTheme().setFont(
            QFont('Times New Roman', self.m_fontSize))
        # 当前主题Q3DTheme设置标签是使用彩色背景还是使用完全透明的背景绘制
        self.m_graph.activeTheme().setLabelBackgroundEnabled(True)
        # 是否按比例将比例尺设置为单个系列比例尺来缩放比例
        self.m_graph.setMultiSeriesUniform(True)

        self.m_temperatureAxis.setTitle(
            Tr.get("Average temperature", "Average temperature"))
        # 轴上的段数。这表明绘制了多少标签。要绘制的网格线的数量使用公式计算:segments * subsegments + 1。预设默认值为5。该值不能低于1
        self.m_temperatureAxis.setSegmentCount(self.m_segments)
        # 轴上每个段内的子段数。
        # 除每个线段外,还在每个子线段之间绘制网格线。预设默认值为1。该值不能低于1。
        self.m_temperatureAxis.setSubSegmentCount(self.m_subSegments)
        self.m_temperatureAxis.setRange(self.m_minval, self.m_maxval)
        self.m_temperatureAxis.setLabelFormat(u"%.1f \N{degree sign}C")

        self.m_yearAxis.setTitle("Year")
        self.m_monthAxis.setTitle("Month")

        self.m_graph.setValueAxis(self.m_temperatureAxis)
        # 设置活动行的轴为年份
        self.m_graph.setRowAxis(self.m_yearAxis)
        # 设置活动列的轴为月份
        self.m_graph.setColumnAxis(self.m_monthAxis)

        self.m_primarySeries.setItemLabelFormat(
            "Oulu - @colLabel @rowLabel: @valueLabel")
        # 设置网格类型
        self.m_primarySeries.setMesh(QAbstract3DSeries.MeshBevelBar)
        self.m_primarySeries.setMeshSmooth(False)

        self.m_secondarySeries.setItemLabelFormat(
            "Helsinki - @colLabel @rowLabel: @valueLabel")
        self.m_secondarySeries.setMesh(QAbstract3DSeries.MeshBevelBar)
        self.m_secondarySeries.setMeshSmooth(False)
        self.m_secondarySeries.setVisible(False)

        self.m_graph.addSeries(self.m_primarySeries)
        self.m_graph.addSeries(self.m_secondarySeries)

        self.m_preset = Q3DCamera.CameraPresetFront
        self.changePresetCamera()

        self.resetTemperatureData()
Ejemplo n.º 8
0
    def setupWindow(self):
        """The window is comprised of two main parts: A Q3DBars graph on the left, and QToolBox
        on the right containing different widgets for tweaking different settings in the Q3DBars graph."""
        header_label = QLabel(
            "Comparison of Average Monthly Temperatures of Select U.S. Cities 1990-2000 (˚C)"
        )
        header_label.setAlignment(Qt.AlignCenter)

        # Load and prepare the data for the three datasets
        data_files = [
            "LasVegas_temp.csv", "Spokane_temp.csv", "Richmond_temp.csv"
        ]
        temperature_data = {}
        # Create a dictionary with key, value pairs pertaining to each city and dataset
        for f in data_files:
            data_name = f.split(
                "_")[0] + "_data"  # Create a dictionary key for each city
            data = self.loadCSVFile("files/" + f)

            # Select 11 years: 1990-2000; the first column in each file is the years
            rows, columns = data.shape
            self.years = data[:, 0]
            monthly_temps = data[:, 1:columns].astype(float)
            temperature_data[data_name] = monthly_temps

        bar_graph = Q3DBars()  # Create instance for bar graph
        bar_graph.setMultiSeriesUniform(
            True)  # Bars are scaled proportionately
        bar_graph.scene().activeCamera().setCameraPreset(
            Q3DCamera.CameraPresetFront)

        # Create lists of QBarDataItem objects for each city
        vegas_data_items = []
        for row in temperature_data["LasVegas_data"]:
            vegas_data_items.append([QBarDataItem(value) for value in row])

        spokane_data_items = []
        for row in temperature_data["Spokane_data"]:
            spokane_data_items.append([QBarDataItem(value) for value in row])

        richmond_data_items = []
        for row in temperature_data["Richmond_data"]:
            richmond_data_items.append([QBarDataItem(value) for value in row])

        self.months = [
            "January", "February", "March", "April", "May", "June", "July",
            "August", "September", "October", "November", "December"
        ]

        # Create instances of QBar3DSeries for each set of data; dataProxy() handles
        # modifying data in the series
        vegas_series = QBar3DSeries()
        vegas_series.dataProxy().addRows(vegas_data_items)
        vegas_series.dataProxy().setRowLabels(self.years)  # rowLabel
        vegas_series.dataProxy().setColumnLabels(self.months)  # colLabel

        spokane_series = QBar3DSeries()
        spokane_series.dataProxy().addRows(spokane_data_items)

        richmond_series = QBar3DSeries()
        richmond_series.dataProxy().addRows(richmond_data_items)

        # Create the valueLabel
        temperature_axis = QValue3DAxis()
        temperature_axis.setRange(-10, 40)
        temperature_axis.setLabelFormat(u"%.1f \N{degree sign}C")
        bar_graph.setValueAxis(temperature_axis)

        # Set the format for the labels that appear when items are clicked on
        vegas_series.setItemLabelFormat(
            "LasVegas - @colLabel @rowLabel: @valueLabel")
        spokane_series.setItemLabelFormat(
            "Spokane - @colLabel @rowLabel: @valueLabel")
        richmond_series.setItemLabelFormat(
            "Richmond - @colLabel @rowLabel: @valueLabel")

        # Add the three series to the bar graph
        bar_graph.setPrimarySeries(vegas_series)
        bar_graph.addSeries(spokane_series)
        bar_graph.addSeries(richmond_series)

        # Create a QWidget to hold only the graph
        graph_container = QWidget.createWindowContainer(bar_graph)
        main_h_box = QHBoxLayout()  # Main layout for the entire window
        graph_v_box = QVBoxLayout()  # Layout that holds the graph
        graph_v_box.addWidget(header_label)
        graph_v_box.addWidget(graph_container, 1)

        ##############################################################################
        # The following section creates the QToolBox that appears on the
        # right of the window and contains widgets for interacting with the graph
        self.modifier = GraphModifier(self,
                                      bar_graph)  # Create modifier instance

        settings_toolbox = QToolBox()
        settings_toolbox.setFixedWidth(300)
        settings_toolbox.setCurrentIndex(0)  # Show the first tab

        # The first tab - Widgets for rotating the bar graph and changing the camera
        horizontal_rotation_slider = QSlider(Qt.Horizontal)
        horizontal_rotation_slider.setTickInterval(20)
        horizontal_rotation_slider.setRange(-180, 180)
        horizontal_rotation_slider.setValue(0)
        horizontal_rotation_slider.setTickPosition(QSlider.TicksBelow)
        horizontal_rotation_slider.valueChanged.connect(
            self.modifier.rotateHorizontal)

        vertical_rotation_slider = QSlider(Qt.Horizontal)
        vertical_rotation_slider.setTickInterval(20)
        vertical_rotation_slider.setRange(-180, 180)
        vertical_rotation_slider.setValue(0)
        vertical_rotation_slider.setTickPosition(QSlider.TicksBelow)
        vertical_rotation_slider.valueChanged.connect(
            self.modifier.rotateVertical)

        # QPushButton for changing the camera's view point
        camera_view_button = QPushButton("Change Camera View")
        camera_view_button.clicked.connect(self.modifier.changeCameraView)

        # Layout for the View tab (first tab)
        view_tab_container = QWidget()
        view_tab_v_box = QVBoxLayout()
        view_tab_v_box.setAlignment(Qt.AlignTop)
        view_tab_v_box.addWidget(QLabel("Rotate Horizontally"))
        view_tab_v_box.addWidget(horizontal_rotation_slider)
        view_tab_v_box.addWidget(QLabel("Rotate Vertically"))
        view_tab_v_box.addWidget(vertical_rotation_slider)
        view_tab_v_box.addWidget(camera_view_button)
        view_tab_container.setLayout(view_tab_v_box)

        settings_toolbox.addItem(view_tab_container, "View")

        # The second tab - Widgets for changing the appearance of the graph. Recheck the
        # background and grid checkboxes if the theme has changed
        show_background_cb = QCheckBox("Show Background")
        show_background_cb.setChecked(True)
        show_background_cb.stateChanged.connect(
            self.modifier.showOrHideBackground)
        self.modifier.background_selected.connect(
            show_background_cb.setChecked)

        show_grid_cb = QCheckBox("Show Grid")
        show_grid_cb.setChecked(True)
        show_grid_cb.stateChanged.connect(self.modifier.showOrHideGrid)
        self.modifier.grid_selected.connect(show_grid_cb.setChecked)

        smooth_bars_cb = QCheckBox("Smoothen Bars")
        smooth_bars_cb.stateChanged.connect(self.modifier.smoothenBars)

        # QComboBox for selecting the Qt theme
        themes = [
            "Qt", "Primary Colors", "Digia", "Stone Moss", "Army Blue",
            "Retro", "Ebony", "Isabelle"
        ]
        select_theme_combo = QComboBox()
        select_theme_combo.addItems(themes)
        select_theme_combo.setCurrentIndex(0)
        select_theme_combo.currentIndexChanged.connect(
            self.modifier.changeTheme)

        # QComboBox for selecting the visual style of the bars
        bar_style_combo = QComboBox()
        bar_style_combo.addItem("Bar", QAbstract3DSeries.MeshBar)
        bar_style_combo.addItem("Pyramid", QAbstract3DSeries.MeshPyramid)
        bar_style_combo.addItem("Cylinder", QAbstract3DSeries.MeshCylinder)
        bar_style_combo.addItem("Sphere", QAbstract3DSeries.MeshSphere)
        bar_style_combo.setCurrentIndex(0)
        bar_style_combo.currentIndexChanged.connect(
            self.modifier.changeBarStyle)

        # Layout for the Style tab (second tab)
        style_tab_container = QWidget()
        style_tab_v_box = QVBoxLayout()
        style_tab_v_box.setAlignment(Qt.AlignTop)
        style_tab_v_box.addWidget(show_background_cb)
        style_tab_v_box.addWidget(show_grid_cb)
        style_tab_v_box.addWidget(smooth_bars_cb)
        style_tab_v_box.addWidget(QLabel("Select Qt Theme"))
        style_tab_v_box.addWidget(select_theme_combo)
        style_tab_v_box.addWidget(QLabel("Select Bar Style"))
        style_tab_v_box.addWidget(bar_style_combo)
        style_tab_container.setLayout(style_tab_v_box)

        settings_toolbox.addItem(style_tab_container, "Style")

        # The third tab - Widgets for hiding/showing different series and changing how
        # items are viewed and selected
        second_series_cb = QCheckBox("Show Second Series")
        second_series_cb.setChecked(True)
        second_series_cb.stateChanged.connect(self.modifier.showOrHideSeries)

        third_series_cb = QCheckBox("Show Third Series")
        third_series_cb.setChecked(True)
        third_series_cb.stateChanged.connect(self.modifier.showOrHideSeries)

        # QComboBox for changing how items in the bar graph are selected
        selection_mode_combo = QComboBox()
        selection_mode_combo.addItem("None", QAbstract3DGraph.SelectionNone)
        selection_mode_combo.addItem("Bar", QAbstract3DGraph.SelectionItem)
        selection_mode_combo.addItem("Row", QAbstract3DGraph.SelectionRow)
        selection_mode_combo.addItem("Column",
                                     QAbstract3DGraph.SelectionColumn)
        selection_mode_combo.addItem(
            "Item, Row, Column", QAbstract3DGraph.SelectionItemRowAndColumn)
        selection_mode_combo.setCurrentIndex(1)
        selection_mode_combo.currentIndexChanged.connect(
            self.modifier.changeSelectionStyle)

        # QComboBox for selecting which years to view
        select_year_combo = QComboBox()
        select_year_combo.addItems(self.years)
        select_year_combo.addItem("All Years")
        select_year_combo.setCurrentIndex(len(self.years))
        select_year_combo.currentIndexChanged.connect(
            self.modifier.selectYears)

        # QComboBox for selecting which months to view
        select_month_combo = QComboBox()
        select_month_combo.addItems(self.months)
        select_month_combo.addItem("All Months")
        select_month_combo.setCurrentIndex(len(self.months))
        select_month_combo.currentIndexChanged.connect(
            self.modifier.selectMonths)

        # Layout for the Selection tab (third tab)
        selection_tab_container = QWidget()
        selection_tab_v_box = QVBoxLayout()
        selection_tab_v_box.addWidget(second_series_cb)
        selection_tab_v_box.addWidget(third_series_cb)
        selection_tab_v_box.addWidget(QLabel("Choose Selection Mode"))
        selection_tab_v_box.addWidget(selection_mode_combo)
        selection_tab_v_box.addWidget(QLabel("Select Year"))
        selection_tab_v_box.addWidget(select_year_combo)
        selection_tab_v_box.addWidget(QLabel("Select Month"))
        selection_tab_v_box.addWidget(select_month_combo)
        selection_tab_container.setLayout(selection_tab_v_box)

        settings_toolbox.addItem(selection_tab_container, "Selection")

        # Set up the layout for the settings toolbox
        settings_v_box = QVBoxLayout()
        settings_v_box.addWidget(settings_toolbox, 0, Qt.AlignTop)

        main_h_box.addLayout(graph_v_box)
        main_h_box.addLayout(settings_v_box)

        main_widget = QWidget()
        main_widget.setLayout(main_h_box)
        self.setCentralWidget(main_widget)