biolab / orange3

🍊 :bar_chart: :bulb: Orange: Interactive data analysis
https://orangedatamining.com
Other
4.72k stars 993 forks source link

"CN2Classifier object has no attribute params" shows if I press "report" menu of an OWRuleViewer #6299

Closed madainigun14 closed 1 year ago

madainigun14 commented 1 year ago

Here is my environment: Python 3.9 PyQt5 Orange3

here is my code, you can run this code directly

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *

import Orange
from Orange.widgets.visualize.owruleviewer import OWRuleViewer
from Orange.classification import CN2Learner

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1200, 800)
        self.MainWindow = MainWindow

        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.pushButton_showOrange = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_showOrange.setObjectName("pushButton_showOrange")
        self.horizontalLayout.addWidget(self.pushButton_showOrange)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem1)
        self.pushButton_closeOrange = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_closeOrange.setObjectName("pushButton_closeOrange")
        self.horizontalLayout.addWidget(self.pushButton_closeOrange)
        spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem2)
        self.verticalLayout.addLayout(self.horizontalLayout)
        spacerItem3 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.verticalLayout.addItem(spacerItem3)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        spacerItem4 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem4)

        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
        self.tabWidget.setObjectName("tabWidget")
        self.tab_added = QtWidgets.QWidget()
        self.tab_added.setObjectName("tab_added")

        current_verticalLayout = QtWidgets.QVBoxLayout(self.tab_added)
        current_verticalLayout.setObjectName("current_verticalLayout")

        spacerItem2 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        current_verticalLayout.addItem(spacerItem2)

        ###############################Python 3.9 + PyQt5 + Orange 3 ######################################

        data = Orange.data.Table(r"D:\Software\Orange3\Orange\Lib\site-packages\Orange\datasets\heart_disease.tab")
        learner = Orange.classification.CN2Learner()
        model = learner(data)
        model.instances = data

        self.ow = OWRuleViewer()   # 1. create an instance
        self.ow.set_classifier(model)
        self.ow.show()

        ####################################################################################################

        self.ow.setParent(self.tab_added)  # 2. add "ow" to the "tab" of the QTabWidget
        ####################################################################################################

        spacerItem3 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        current_verticalLayout.addItem(spacerItem3)

        current_verticalLayout.addWidget(self.ow)  # 3. add "ow" to the vertical layout
        ####################################################################################################

        self.tabWidget.addTab(self.tab_added, "")

        self.horizontalLayout_2.addWidget(self.tabWidget)

        spacerItem5 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem5)
        self.verticalLayout.addLayout(self.horizontalLayout_2)
        self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1200, 23))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.pushButton_closeOrange.clicked.connect(self.close_orange)
        self.pushButton_showOrange.clicked.connect(self.show_orange)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton_showOrange.setText(_translate("MainWindow", "Open"))
        self.pushButton_closeOrange.setText(_translate("MainWindow", "Close"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_added), _translate("MainWindow", "tab_added"))

    def close_orange(self):
        self.ow.close()

    def show_orange(self):
        self.ow.show()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Then, click the "report" at the bottom left of the OWRuleViewer 1 (1)

then "CN2Classifier object has no attribute params" shows 1 (2)

but, if I comment line 177 in Python\Lib\site-packages\Orange\widgets\visualize\owruleviewer.py as below 1 (3)

def send_report(self):
    if self.classifier is not None:
        self. report_domain("Data domain", self.classifier.original_domain)
        #self. report_items("Rule induction algorithm", self.classifier.params)
        self. report_table("Induced rules", self.view)

then error will not occur and it works correctly: 1 (4)

so, is this a bug? or do I forget a neccesary step (call some method or set some attribute?) after creating an instance of OWRuleViewer?

        data = Orange.data.Table(r"D:\Software\Orange3\Orange\Lib\site-packages\Orange\datasets\heart_disease.tab")
        learner = Orange.classification.CN2Learner()
        model = learner(data)
        model.instances = data

        self.ow = OWRuleViewer()   # 1. create an instance
        self.ow.set_classifier(model)
        self.ow.show()
janezd commented 1 year ago

There has been a change in how learners work, and the viewer wasn't adapted. In #6306 I did essentially the same as you here: I removed the line from the report because learner's parameters should be reported in Rule Learner, not here.

Thanks for exploring and reporting this.