Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Continuously Updating BarPlot (QtCharts)



  • Hi to everybody, i'm new in this forum and i'm relatively new to Qt for Python.

    Up untill now i have been always capable of solving the problems googling or using the official documentation, but now i'm facing an obstacle than I cannot solve by myself.

    I'm using a QTimer() with a 20Hz update clock.
    At every timeout, some operations are executed. Among them i need to plot a barplot that takes the values from the Numpy array (converted to a list) self.z_coeff.

    I designed the interface with Qt Designer and I draw a QWidget for the barplot (object name: zernike_bar_plot).

    The .ui is converted to python code using the pyside2-uic command, and what i'm doing in the separate file that I use to add all the functionality is pretty standard:

    class MainWindow(QMainWindow):
        def __init__(self):
            super(MainWindow, self).__init__()
            self.ui = Ui_MainWindow()
            self.ui.setupUi(self)
    

    When the program starts i draw the bar chart for the first time using this function:

    def set_zernike_plot(self):
    
        self.zernike_barset = QtCharts.QBarSet('zernike_bp')
        self.zernike_barset.append(self.z_coeff.tolist())
        self.zernike_barset.setColor(QColor(0, 230, 0))
    
        self.zernike_series = QtCharts.QBarSeries()
        self.zernike_series.append(self.zernike_barset)
        self.zernike_series.setBarWidth(1)
    
        self.zernike_plot_chart = QtCharts.QChart()
        self.zernike_plot_chart.addSeries(self.zernike_series) 
    
        self.zernike_plot_chart.createDefaultAxes()
        self.zernike_plot_chart.legend().hide()
    
        self.zernike_plot_chart.axisX(self.zernike_series).setVisible(False)
        self.zernike_plot_chart.axisY(self.zernike_series).setVisible(False)
    
        self.zernike_chartview = QtCharts.QChartView(self.zernike_plot_chart)
    
        self.ui.zernike_bar_plot.setContentsMargins(0, 0, 0, 0)
        self.zernike_layout = QHBoxLayout(self.ui.zernike_bar_plot)
    
        self.zernike_layout.setContentsMargins(0, 0, 0, 0)
        self.zernike_layout.addWidget(self.zernike_chartview)
    

    Here the first problem: I'm not able to limit the y axis to be in some range, say [-1,1].

    Then what I want is to update this plot with che continuously changing values of self.z_coeff.
    For this purpose, i connected the QTimer timeout to another function:

    def update_zernike_coefficient_plot(self):
        self.zernike_plot_chart.removeSeries(self.zernike_series)
    
        self.zernike_barset = QtCharts.QBarSet('zernike_set')
        self.zernike_barset.append(self.z_coeff.tolist())
        self.zernike_barset.setColor(QColor(0, 230, 0))
    
        self.zernike_series = QtCharts.QBarSeries()
        self.zernike_series.append(self.zernike_barset)
        self.zernike_series.setBarWidth(1)
    
        self.zernike_plot_chart.addSeries(self.zernike_series) 
    
        self.zernike_chartview.setChart(self.zernike_plot_chart)
    
        self.zernike_layout.insertWidget(0,self.zernike_chartview)
    

    This is working, but i think that is overkilling to reassign all this variables and rewrite all this code just to update the plot. Moreover to me this adds unnecessary load for the processor.

    I will thank everyone that can help me ❤️



  • Hi there,

    See the minimal example below (uses PyQt5 or PySide2) that hopefully addresses your issues/questions:

    try:
        from PyQt5.QtCore import QTimerEvent
        from PyQt5.QtGui import QColor
        from PyQt5.QtWidgets import QMainWindow
        from PyQt5.QtChart import QChartView, QBarSet, QBarSeries, QChart
    
    except ImportError:
        from PySide2.QtCore import QTimerEvent
        from PySide2.QtGui import QColor
        from PySide2.QtWidgets import QMainWindow
        from PySide2.QtCharts import QtCharts
    
        QBarSet=QtCharts.QBarSet
        QBarSeries=QtCharts.QBarSeries
        QChart=QtCharts.QChart
        QChartView=QtCharts.QChartView
    
    class MainWindow(QMainWindow):
        def __init__(self, parent=None, **kwargs):
            super().__init__(parent, **kwargs)
    
            self._data=[
                [1,2,3,4,5,4,3,2,1],
                [5,4,3,2,1,2,3,4,5]
            ]
            self._currentDataIdx=0
    
            self._barSet=QBarSet("Bar Set")
            self._barSet.setColor(QColor(0,230,0))
            self._barSet.append(self._data[self._currentDataIdx])
    
            self._barSeries=QBarSeries()
            self._barSeries.setBarWidth(1)
            self._barSeries.append(self._barSet)
    
            self._chart=QChart()
            self._chart.addSeries(self._barSeries)
            self._chart.createDefaultAxes()
            self._chart.legend().hide()
            self._chart.axisX(self._barSeries).setVisible(False)
            self._chart.axisY(self._barSeries).setVisible(False)
    
            # Set the Y-axis range/limits 0 to 6
            self._chart.axisY(self._barSeries).setRange(0,6)
    
            self._chartView=QChartView(self._chart)
    
            self.setCentralWidget(self._chartView)
    
            self._timerId=self.startTimer(1000)
    
        def timerEvent(self, event:QTimerEvent):
            if self._timerId!=event.timerId(): return
    
            # Replace the data in the existing series
            self._currentDataIdx=1 if not self._currentDataIdx else 0
            for i,n in enumerate(self._data[self._currentDataIdx]):
                self._barSet.replace(i,n)
    
    if __name__=="__main__":
        from sys import arg, exit
        try: from PyQt5.QtWidgets import QApplication
        except ImportError: from PySide2.QtWidgets import QApplication
    
        a=QApplication(argv)
        m=MainWindow()
        m.show()
        m.resize(640,480)
        exit(a.exec_())
    

    Hope this helps :o)



  • This works! THANKS!

    But, i don't know why, if i call the function set_zernike_plot inside the __init__ of the class MainWindow, it doen't work, while if i put the same code of the function in the __init__, than it works 🤔



  • Glad it works.

    I'm not sure about your other issue, I would need a more complete minimal example to try and trace the issue.


  • Banned

    @TommasoFurieri first off I would strongly suggest you learn to create Python-Qt GUIs as they were meant to be created -- aka not using the designer. I say this because there are numerous issues that occur when you use these UI files that you do not experience by doing it the proper way. Further in the long run you end up using more effort to implement your GUI with code using the UI versus doing it properly.

    That being said the issue that you are having could relate somewhat to this UI file (I have not looked at it since you did not include it) or the fact that you are using super( ) rather than explicitly defining your class -- as super( ) has issues in Python

    Lastly my current project uses this concept of updating graphs and I do not have the issues you are experiencing but then I did not implement it using UIs nor super( ) which makes the code function dramatically different.

    I am not sure why @jazzycamel chose to use the QTimerEvent versus just employing a more simplistic QTimer object as this shortcut creates a lot of questions about what is going on behind the scenes that you are not aware of where employing the QTimer makes all of that visible and straightforward but perhaps they will chime in and explain the concept in more detail

    As a final note -- I have taught numerous students how to get away from using the Designer and everyone of them has found that doing it the proper way is actually as easy or easier than using the Designer to do it -- and they understand what their code is doing now and how to augment it to do more.



  • @Denni-0

    +1 for stepping away from designer, causes way more problems than it solves!

    I used startTimer out of habit more than anything and because it makes for (IMHO) cleaner code, but I take your point and here, for completeness, is my example using QTimer instead:

    try:
        from PyQt5.QtCore import QTimer, pyqtSlot
        from PyQt5.QtGui import QColor
        from PyQt5.QtWidgets import QMainWindow
        from PyQt5.QtChart import QChartView, QBarSet, QBarSeries, QChart
    
    except ImportError:
        from PySide2.QtCore import QTimer, Slot as pyqtSlot
        from PySide2.QtGui import QColor
        from PySide2.QtWidgets import QMainWindow
        from PySide2.QtCharts import QtCharts
    
        QBarSet=QtCharts.QBarSet
        QBarSeries=QtCharts.QBarSeries
        QChart=QtCharts.QChart
        QChartView=QtCharts.QChartView
    
    class MainWindow(QMainWindow):
        def __init__(self, parent=None, **kwargs):
            super().__init__(parent, **kwargs)
    
            self._data=[
                [1,2,3,4,5,4,3,2,1],
                [5,4,3,2,1,2,3,4,5]
            ]
            self._currentDataIdx=0
    
            self._barSet=QBarSet("Bar Set")
            self._barSet.setColor(QColor(0,230,0))
            self._barSet.append(self._data[self._currentDataIdx])
    
            self._barSeries=QBarSeries()
            self._barSeries.setBarWidth(1)
            self._barSeries.append(self._barSet)
    
            self._chart=QChart()
            self._chart.addSeries(self._barSeries)
            self._chart.createDefaultAxes()
            self._chart.legend().hide()
            self._chart.axisX(self._barSeries).setVisible(False)
            self._chart.axisY(self._barSeries).setVisible(False)
            self._chart.axisY(self._barSeries).setRange(0,6)
    
            self._chartView=QChartView(self._chart)
    
            self.setCentralWidget(self._chartView)
    
            self._timer=QTimer()
            self._timer.timeout.connect(self.onTimeout)
            self._timer.start(1000)
    
        @pyqtSlot()
        def onTimeout(self):
            self._currentDataIdx=1 if not self._currentDataIdx else 0
            for i,n in enumerate(self._data[self._currentDataIdx]):
                self._barSet.replace(i,n)
    
    if __name__=="__main__":
        from sys import argv, exit
        try: from PyQt5.QtWidgets import QApplication
        except ImportError: from PySide2.QtWidgets import QApplication
    
        a=QApplication(argv)
        m=MainWindow()
        m.show()
        m.resize(640,480)
        exit(a.exec_())
    

  • Banned

    By the way that code did not work as posted (however upon testing the above a second time I do not get the error so not sure why it did not work initially) did you try running it and if you did under which PyQt5 or PySide2 as I use PyQt5 -- I went through and tweaked your code a bit and explained some of the changes I feel would help enhance it I hope this is helpful

    try:
        from PyQt5.QtCore    import QTimer, pyqtSlot
        from PyQt5.QtGui     import QColor
        from PyQt5.QtWidgets import QApplication, QMainWindow
        from PyQt5.QtChart   import QChartView, QBarSet, QBarSeries, QChart
    
    except ImportError:
        from PySide2.QtCore    import QTimer, Slot as pyqtSlot
        from PySide2.QtGui     import QColor
        from PySide2.QtWidgets import QApplication, QMainWindow
        from PySide2.QtCharts  import QtCharts
      # Renaming these to mirror PyQt5
        QChartView=QtCharts.QChartView
        QBarSet=QtCharts.QBarSet
        QBarSeries=QtCharts.QBarSeries
        QChart=QtCharts.QChart
    
    # Always declare all your Imports at the top so other programmers can easily 
    # see what this code is dependent upon
    #from sys import argv, exit
    from sys import exit as sysExit  #I rename this for numerous reason but you do not have to
    
    class MainWindow(QMainWindow):
       # Not sure why you do this considering unless you plan to make this a stand alone
       # class to be imported into something else parent will always be None and there are
       # no kwargs -- always K.I.S.S. your code (Keep It Simple and Smart) do not add more
       # complexity than is needed as this only introduces more potential issues
       #
       # def __init__(self, parent=None, **kwargs):
        def __init__(self):
          # Next do not use super( ) unless you are fully aware of what 4 major issues 
          # you must code for in conjunction with using it and the actual rare issue 
          # that it is meant to solve. And the fact they you are introducing potential
          # bugs into your program because super( ) in Python still has bugs. You should
          # also be aware that the issue for super () is extremely rare and unless you are 
          # doing some complicated inheritance you will most likely never run into that
          # issue -- however those 4 major issues it creates by using it you are much more 
          # likely to run into. Be very careful what you pick up on the internet there are
          # many misguided proponents of super( ) for python but most them are not even 
          # aware of the 4 issues 
          #
          # super().__init__(parent, **kwargs)
            QMainWindow.__init__(self)
          # Handle your QMainWindow adjustments inside your QMainWindow class
          # aka keep like things grouped
          # m.resize(640,480)
            self.resize(640, 480)
    
          # Okay not sure if you are aware but "_variable" is normally used to 
          # indicate a private class variable which in Python does not actually 
          # exist they just slap a hider prefix onto the variable and as such it 
          # can still be accessed
            self.Data={ 0:[1,2,3,4,5,4,3,2,1], 1:[5,4,3,2,1,2,3,4,5] }
            self.CurDataIdx = 0
    
            self.bstBarGrph = QBarSet("Bar Set")
            self.bstBarGrph.setColor(QColor(0,230,0))
            self.bstBarGrph.append(self.Data[self.CurDataIdx])
    
            self._barSeries = QBarSeries()
            self._barSeries.setBarWidth(1)
            self._barSeries.append(self.bstBarGrph)
    
            self._chart = QChart()
            self._chart.addSeries(self._barSeries)
            self._chart.createDefaultAxes()
            self._chart.legend().hide()
            self._chart.axisX(self._barSeries).setVisible(False)
            self._chart.axisY(self._barSeries).setVisible(False)
            self._chart.axisY(self._barSeries).setRange(0,6)
    
            self._chartView = QChartView(self._chart)
    
            self.setCentralWidget(self._chartView)
    
            self._timer = QTimer()
            self._timer.timeout.connect(self.onTimeout)
            self._timer.start(1000)
    
        @pyqtSlot()
        def onTimeout(self):
          # self._currentDataIdx = 1 if not self._currentDataIdx else 0
          # Okay new version below does this - if its 0 > -1 > 1 or if 1 > 0 
          # In anything that might not be 100% straight forward make a 
          # comment denoting what you are doing and/or why
          # This alternates the Index between 0 and 1
            self.CurDataIdx = abs((self.CurDataIdx - 1))
    
          # It is considered bad coding practice to use non-descriptive variables
          # such as single characters "i" and/or "n" give it some substance so that
          # it is easily understood what it is supposed to represent otherwise you
          # are being extremely lazy and lazy coding is dangerous coding. Also using 
          # enumerate to handle incrementing an Index is more complicated. I had to
          # stop and decipher what you were doing with it as it is not a simple and
          # straight forward process -- simpler is almost always better
          #  for i, n in enumerate(self.Data[self.CurDataIdx]):
            idx = 0
            for num in self.Data[self.CurDataIdx]:
              # Not wanting to dig deeply into what you are doing I want to let you
              # know that when I update a graph/chart I am passing it the entire List
              # not changing each element within the graph/chart. So you might want to
              # see if you can do this with your version
                self.bstBarGrph.replace(idx, num)
                idx += 1
    
    if __name__=="__main__":
      # You are not using Command Line arguments here or at least not
      # handling them as such they are not needed. Further if you do
      # plan to use Command Line arguments I strongly suggest you look
      # into the argparser library as it handles them much cleaner and
      # more intuitively
      #  a=QApplication(argv)
        MainEventHandler = QApplication([])
    
        MainApp = MainWindow()
        MainApp.show()
    
        sysExit(MainEventHandler.exec_())
    
      # If anyone wants more extensive free help I run an online lab-like classroom-like 
      # message server feel free and drop by you will not be able to post until I clear 
      # you as a student as this prevents spammers so if interested here is the invite
      # https://discord.gg/3D8huKC
    


  • @Denni-0
    With all due respect, please don't be condescending.

    My code worked perfectly for both PyQt5 and PySide2, I tested it before posting as I always do.

    I don't know why you feel the need to correct my example, most of what you said is either personal taste or in fact incorrect. I am a python dev with decades of experience, I know what I'm doing. Your post will not help people learn, it is simply insulting.


  • Banned

    @jazzycamel okay well when I copied/pasted your original code and ran it in PyQt5 -- it failed. This is why I stated it did not work but it is also why I asked if you had ran it in PySide2 or PyQt5 as well as denoting I use PyQt5. So absolutely no condescending aspect to the post at all

    Further the number of years you have been programming is not a measure of the quality of code you have been producing and I think in the years department I have more but again that is unimportant. Quality is simply quality and not using good coding practices even in throw away examples does not attest to producing quality code. Lastly I think I even mistook you for the OP and all I was trying to do was be helpful and point out the areas that are not considered to be good coding practices in general. If something I stated is wrong you could have denoted that but you did not.

    As for the rest of you comments I will let the moderators sort it out because you make accusations without substance as such you are actually the one being disrespectful and insulting.



  • @Denni-0
    In which case, I would be interested to see the traceback from the failure for my own learning, as I have it working right here now in front of me (both with PyQt5 and PySide2).

    I'm not sure why moderators are required; I have in no way insulted you or made any 'accusations' and I did my best to be respectful. However, if I have unintentionally caused you offence, then please accept my apologies. However, my comments regarding the opinions you inserted as comments in to my code stand; most of it is personal taste and some of it is incorrect.

    For example, here are just some of the ways you have broken PEP-8 conventions in your modified version of my example.

    Further, I pass argv to QApplication because there are somethings that can me modified from the command line in every (Py)Qt5 program (should the user wish to) such as the application style (-style=plastique).

    The long and the short of it is, I really don't know why you felt it necessary to comment so heavily on someone elses post. It is condescending to assume you have the right to mark everyone elses work and, as you were quick to point out, we have moderators to moderate forums, we don't need you to police them too.


  • Banned

    First I accept your apology and I extend mine in return -- nothing was meant to be or seem condescending -- I was simply outlining good coding practices to help I thought the OP (newbie or newer) programmer

    Next I do not recall what the error was and my comment was just to outline the copied/pasted version did not work for me -- now perhaps it was some copy/paste error as when copied and pasted it again it now does not produce the error I got previously -- but had this been the only issue I would have gladly double re-checked things on my end -- now frankly I did not dive into the error because I saw various minor issues that I was going to speak to and figured letting the OP know that the code did not run on PyQt5 was sufficient if they were a PySide2 only platform -- I do not assume someone has both platforms

    So as it stands the current version of the code you have posted does run fine -- I will tweak my original post to indicate this as such as well

    Imports should not be aligned (extraneous whitespace)?
    Okay I do not think I commented on that as a good or not good practice -- I do it because it makes it easier to read -- and from my understanding whitespace extreaneous or not is totally meaningless to how the code works as it gets ignored -- adding extra whitespace to help make the code more easily readable by-the-way is no different than putting code on more than one line to help it be more readable such as you do here:

    self._data=[
                [1,2,3,4,5,4,3,2,1],
                [5,4,3,2,1,2,3,4,5]
            ]
    

    Basically this is the same as me doing this:

        from PyQt5.QtCore    import QTimer, pyqtSlot
        from PyQt5.QtGui     import QColor
        from PyQt5.QtWidgets import QApplication, QMainWindow
        from PyQt5.QtChart   import QChartView, QBarSet, QBarSeries, QChart
    

    Frankly I find some of the stuff your source posts as guidelines are purely style issues and nothing more -- when coding you leave room for pure style up to the individual programmer and frankly there is no such thing when it comes down to it as extraneous whitespace -- since non-indentation whitespace is completely ignored by the program and is only for readability purposes -- so they should have just stated -- Use whitespace and (in your case) multiple lines to improve readability -- if your use of either of these causes the code to be more difficult to read then yes you are defeating the whole purpose of using it.

    Another example of this is Results = Value1 + Value2 is absolutely no different to the program than Results=Value1+Value2 but the former is easier for most humans to read and while A=B+C is also no different than the previous 2, it is just not as easy for humans because A, B, and C are fairly meaningless variables -- this is something that is (as it should be) address by good coding practices.

    Indentation should be 4 spaces not 2
    I am not even sure why you reference this as all my code -- due purely to preference btw -- is 4 spaces and not 2 but to be technically correct I believe the indentation can be whatever the programmer wants it to be since as long as it is consistent with what it is supposed to be consistent with the program does not care -- we thus go back to readability and overall consistency -- yes it is common practice to use 4 spaces for indentation (but its purely a preference) which is why I set Notepad++ set up to automatically put in 4 spaces when I press Tab (aka Tab is replaced with 4 blanks) so all my code uses 4 spaces of indentation

    Instance variable names should start with lowercase
    This is absolutely coding style and has nothing absolutely nothing to do with how the program works -- nor does it have anything to do with good coding practices. What it does have to do with is a bunch of folks trying to strong arm other programmers into following their preferences (coding styles) because they cannot handle diversity. This _barSet vs this bstBarGrph vs this BarGrph is purely style and as long as its clear and concise what the variable is there is nothing wrong with any of them -- however good coding practices do state that doing this for i,n in is bad since it is not clear what these 2 variables represent and one has to make an assumption about them that may be wrong.

    Further, I pass argv to QApplication because there are somethings that can me modified from the command line
    Yes I know but in this case that is not the case because you did absolutely nothing with those Command Line arguments if someone had added command lines arguments such as (-style=plastique) your code captured the Arg but then drop the ball as you did absolutely nothing with it -- thus making it absolutely pointless to have included. As such my statement was basically why include extraneous nonsensical code that does nothing -- as this is a much bigger offense to good programming than your extraneous whitespace issue or variable capitalization issue neither of which is is actually a programming issue at all

        a=QApplication(argv)
        m=MainWindow()
        m.show()
        m.resize(640,480)
        exit(a.exec_())
    

    Further as I always do I pointed out that if you are going to support Command Line arguments that you should use the argparser library -- which you do not use here -- further I would venture a guess since you use argv unnecessarily here that you most likely do not use the argparser library elsewhere -- but do correct me if I am wrong on that guess

    To sum your issues up all 3 of them are purely style issues and nothing more -- they do not effect readability, clarity, or execution at least not in a good way.

    I really don't know why you felt it necessary to comment so heavily on someone elses post
    I did not comment on your post I commented on your code but let us look at those comments compared to your purely style issues that you have outline as being problematic in the code I provided.

    1. Always declare all your Imports at the top so other programmers can easily see what this code is dependent upon
      --- Is this purely style perhaps but it is denoted as a good coding practice and I even stated why

    2. Not sure why you do this considering unless you plan to make this a stand alone class to be imported into something else parent will always be None and there are no kwargs -- always K.I.S.S. your code (Keep It Simple and Smart) do not add more complexity than is needed as this only introduces more potential issues
      def __init__(self, parent=None, **kwargs):
      vs
      def __init__(self):
      Again is this purely style ?? I think not as I denoted K.I.S.S. and this breaks the rules of K.I.S.S. by adding extraneous code that does nothing which can confuse programmers at some point in that they might believe it have some significance when it does not have any significance at all and is not needed because it serves no purpose in this example -- I also stated if you planned to import this into another program maybe it makes sense but that is not the case in this case -- this is a MUC as such it should be bare bones without extraneous garbage tossed in regardless of reason one has for it

    3. Next do not use super( ) unless you are fully aware of what 4 major issues
      Again is this style -- definitely not -- there is even a post now on here outlining these 4 issues and such of why using super( ) in python code is a very bad thing to do

    4. aka keep like things grouped
      This is basic good coding practice because it reduces confusion by grouping all the things together that you can so they are in once place for easy view ability. For instance I have seen folks declare a QHBoxLayout at the top put more code in then assign something to then more code and assign something to it etc.... where all of those could be collected at the bottom after grouping each of the objects you planned to add to that Layout --- this makes the code more easily readability -- and goes back to the concept of structured code vs spaghetti code and why good coding practices stress structured coding

    5. Okay not sure if you are aware but "_variable" is
      This is it style -- yes but I denoted it as a question were you aware and explained the fallacy of using it if that was why you were using it -- personally I do not care whether you choose to use it or not I was just outlining the general meaning associated with it in case you were unaware -- again I thought you were the OP

    6. In anything that might not be 100% straight forward
      In this I put a comment about another Good Coding Practice and while I changed it -- to show another perhaps less verbose way of doing it I did not state yours was wrong it just needed a comment aka
      This
      self._currentDataIdx=1 if not self._currentDataIdx else 0
      vs

    # This alternates the Index between 0 and 1
      self.CurDataIdx = abs((self.CurDataIdx - 1))
    
    1. It is considered bad coding practice to use non-descriptive variables
      This has been around as a good coding practice for a long time and yet you put this in place:
    for i, n in enumerate(self.Data[self.CurDataIdx])
        self._barSet.replace(i,n)
    

    further the above is a whole lot more complex than it needs to be -- K.I.S.S.

    idx = 0
    for num in self.Data[self.CurDataIdx]:
        self.bstBarGrph.replace(idx, num)
        idx += 1
    

    Maybe it is just me but I believe a newbie programmer would have more trouble understanding what yours was doing then the version I presented -- and frankly these are aimed at Newbies why code over their heads??

    Now these are my 7 Comments (and the 3 style issues you bring up are not my comments) and they explain exactly why I would make them but to perhaps help you out on this -- because they are designed to help a newbie programmer not propagate bad coding practices. Which is who these bits of example code are aimed at. And even if not aimed at a newbie -- K.I.S.S. is always the better way to go in any program (Keep It Simple and Smart) do not Make It Confusing and Complex (MICC pronounced Miss) aka If you KISS it you do not MICC it

    As a final note -- yes if whatever you (this is a general you -- not a you you) are coding must adhere to coding standards set by someone else (your employer, the community you are submitting the code to) then by all means adhere to those coding standards regardless if they are purely style or not --- but what we are posting here is not being submitted to any such organization nor community -- so freestyle is perfectly fine --- and learn to tell the difference between what is a real issue and a purely style issue so that you can recognize them for what they really are



  • @Denni-0
    Cool, I’m glad we’re on a square footing :o) and thanks for the clarity around the suspected error.

    PEP-8 is the gold standard for Python code, that’s why I referenced it and because you’d made comments regarding good practice etc., not because you had mentioned these things specifically, sorry if I wasn’t clear. I was trying to highlight how a lot of the things you had changed and made quite in-depth comments about were actually due to your taste/style and technically could be considered incorrect as they go against the generally accepted standard for our language of choice. And sorry about the indent one, your code looked like it was using 2 spaces on the forum, but I was obviously wrong. Also, as I don’t agree with all of your points regarding good practice or readability/ease of understanding (idx is no better than i, abs no clearer than enumerate to a newb IMO) I was trying to reference an independent 3rd party of standing, i.e. the Python Software Foundation. The bits about super(), the reasons I pass parent and **kwargs and where imports belong I will leave; we’re not going to agree, but my reasons are as informed, heartfelt and, IMO, valid as yours, I just don’t think there’s anything to be gained by going on about it here.

    I don’t think we are going to agree on all the points raised and the nice thing is we don’t have to. I guess my objection was based on my code being classed as bad or wrong based on what I saw as semantics and preference rather than technical errors.

    Anyway, I’d rather extend an olive branch, agree to disagree and move on. If the original OP was helped by one of both of us then that is why we’re here.

    See you around the forums dude, live long and prosper.


  • Banned

    Yeah I am aware of PEP-8 and I wholeheartedly disagree that PEP-8 is a generally accepted standard for our language of choice maybe an accepted standard by you but not by me nor everyone coding in python. Frankly I find some of the stuff they comment on to be far to nit-pickyish especially over stuff that just makes no sense to even dive into -- such as extraneous whitespace for instance -- further I think I read numerous other items they promote that are just purely style only issues and have nothing to do with good coding practices and as such should be removed from a general coding standard document -- Note I have also been writing coding standards for companies for many years and have had to delineate between good coding practices versus style choices so I actually do know what is pure style versus good coding practice having had to research that more than once. Still yeah if you got nothing to base your style on -- PEP-8 is better than nothing but I have been around a lot longer than PEP-8 and have learned quality coding practices by having to dissect really ugly code and researching to document good coding standards based on good coding practices not based on personal preferences such as your extraneous whitespace directives obviously are.

    Also as I stated the 3 things you brought up were not even something I made a comment on at all let alone an in-depth one -- and I even outlined my actual 7 comments that I did actually make -- so does PEP-8 address any of the 7 comments I actually did make? I would actually be curious to see if they do and what comment they made (if any) about those 7 items.

    Next something is not technically considered incorrect unless it is actually technically incorrect -- and purely style issues in a program not needing to adhere to said style cannot be incorrect (literally or theoretically) because its like an opinion -- it purely subjective -- so regardless if some community has over-stepped there bounds and seemingly tried to assert their self-proclaimed style upon all programmers this does not negate the facts -- one might try to cloud the facts using them but it by no means negates them. Further I do not consider them (PEP-8) to my gods and as such I do not worship them -- they are fallible humans just like the rest of us and are imo obviously prone to mistakes since some of their guidelines and lastly I am not a lemming I do not follow others blindly -- I research it, I analyze it, and then I make my own decision of whether I want to adopt it of not. For instance you are still using super( ) which I can only guess is because you have never fully researched its cons.

    Now I had to laugh at this -- idx is not clearer than i as this would be like saying index is not clearer than idx for both statements are woefully wrong and I will leave that at that.

    As for abs not being clearer than enumerate --- first you comparing Apples and Oranges with this statement -- the abs (aka python's function for absolute-value not my naming convention for it) had nothing to do with your enumerate function -- it was initiated along with a comment to make your convoluted if statement easier to read (at least in my expert opinion on that and keep in mind I have been tutoring newbies for quite a few years and have to explain if statements like yours in much simpler terms). So this as a packaged deal and corresponding to the comment that was made which was: In anything that might not be 100% straight forward make a comment denoting what you are doing and/or why clearly outlines the issue I was driving at with the added caveat of presenting the convoluted if statement in perhaps a clearer manner -- which by the way I actually made no comment about for that was merely my opinion that the if statement is convoluted and I acknowledge that is an opinion by not making a comment about it -- heck perhaps to some newbies my line of code is more confusing which is why it is accompanied with a comment denoting what it is doing for clarity . So in short this:

    # This alternates the Index between 0 and 1
    self.CurDataIdx = abs((self.CurDataIdx - 1))
    

    is definitely clearer than this

    self._currentDataIdx=1 if not self._currentDataIdx else 0
    

    as to what it is doing -- and only because the former has a comment denoting what it is doing

    As for the enumerate well let me see this:

    for i,n in enumerate(self._data[self._currentDataIdx]):
        self._barSet.replace(i,n)
    

    was actually replaced with this

    idx = 0
    for num in self.Data[self.CurDataIdx]:
        self.bstBarGrph.replace(idx, num)
        idx += 1
    

    Sorry you would be extremely hard pressed to convince me (and most newbies I would guess) that these 2 lines of code are easier to understand then these 4 lines of code even though they technically do the exactly same thing.

    As to super( ) and parent and **kwargs I can only conclude that you do not pursue these because you have no solid facts to back them up and you use them because of pure personal uninformed preference.

    As for where imports belong -- we can disagree but -- it does not change the fact that it has been a well known fact by quality programmers for years that when adding imports to a program it is much clearer and more concise to put all of them in one place and this place is typically at the very beginning so a programmer knows immediately what outside elements are being used internally -- and regardless of this fact it is definitely not clearer nor more concise to sprinkle them through out your program like some spice your adding to your food so they are well mixed in -- as this resembles what spaghetti code used to do

    To the 3 points you brought (and my #5 which was mainly a clarification about the _) I have no issue to agree to disagree because those are purely style issues and I could careless about them nor did I even comment on them (or in the case of #5 in that manner) -- to my other 6 points I brought up I will agree to disagree with you but with the caveat that they are about good quality coding practices and not implementing them is the opposite thereof.

    Olive branch accepted just keep in mind its the newbies that get hurt with items 1-4 and 6-7 not me I know what is good coding and what is not but I will continue to teach those willing to learn what makes good solid code and what makes bad code and I will fully explain why I feel that way and then I will let them decide what they will and will not use. I always tell my students do not be lemmings -- ask question, learn the truth, and make up your own mind -- and that goes equally for what I teach them as to what they pick up elsewhere.


Log in to reply