Getting to know... Qt for Python

I recently took a look at Dash which seems great for data visualization, but I have a project for which I'd love to build a user interface. I previously used PySimpleGUI and the result was to my satisfaction. However, there was something left to be desired. In any case, that brings me to Qt (pronounced "cute") for Python. Let's check out the documentation and see what we can do with it.

Headings in this post follow the headings in the documentation.

Qt for Python Quick start


`pip install PySide2`

Right off the bat. The `hello_world.py` seems more difficult to create something simple (versus PySimpleGUI). However, I imagine all this complexity is what eventually enables a more advanced user interface (I later learn about QtQuick/QML).

Remark: I encountered an error for which I tried various environment variable fixes. Eventually the solution which worked for me was this answer from stackoverflow. But I wasn't happy with just implementing the solution. What I learned was I had incorrectly set the necessary environment variable. To correctly set the environment variable, run the following in the Python terminal:
`import os`
`import PySide2`
`dirname = os.path.dirname(PySide2.__file__)`
`plugin_path = os.path.join(dirname, 'plugins', 'platforms')`
`print(plugin_path)`
Create a new environment variable named `QT_QPA_PLATFORM_PLUGIN_PATH` and point it to the above path.

Qt for Python Getting Started


This section was about "building Qt for Python from source." I was not interested in this.

Qt for Python Modules


This section serves as a table of contents to all the modules. There are five major categories: "Basic Modules," "QML (Qt Modeling Language) and Qt Quick," "Data visualization," "Multimedia," and "WebEngine."

Qt for Python Tutorials


Basic Tutorials


Your First QtWidgets Application


This is a simpler "hello world" application than the one shown previously in "Qt for Python Getting Started."

I noted that "`QLabel` [...] can present text (simple or rich, like html) and images."

Your First Application Using PySide2 and QtQuick/QML


This example shows that an application can be designed using QML, a declarative language. A basic application consists of a QML file and a python file which loads the QML file.

The page makes a note about programming for desktop.

A Simple Button Tutorial


I read through the page and then I copied the complete code at the end into a file called `clickable_button.py`. Run it using `python clickable_button.py`.

The page said not to worry about what a slot is, but I felt compelled to look into it. The high-level idea seems to be that objects can have inputs called slots and outputs called signals. In the design of an application, one can connect signals to slots.

Creating a Simple PySide2 Dialog Application


I read through the page and then I copied the complete code at the end into a file called `dialog.py`. Run it using `python dialog.py`.

Using UI Files


Interesting. Apparently one can use a program called Qt Creator to form the user interface file, the page gives an example code for a file named `mainwindow.ui`. This file can then either be imported as a class (after converting it with `pyside2-uic`) or loaded directly (with `QUiLoader` from `PySide2.QtUiTools`). The final example code uses the latter method (loading the UI file directly) and is called `main.py`. However, I named it `uifiles.py` after the documentation page.

Fix: the code uses the library QIODevice but forgot to import it. So I just added the import (e.g., `from PySide2.QtCore import QFile, QIODevice`).


Real use-cases applications


Data Visualization Tool Tutorial


Chapter 1 - Reading data from a CSV

The first example uses pandas to read a CSV. The file name is read in as an argument in the command line.

Because the documentation does not provide data, I generated my own dummy data (see `Generate Test Data.ipynb`).

Chapter 2 - Filter data

Aside from typical pandas actions like filtering data, this next example implies Qt has its own datetime object, `QDateTime`. The example reads the data, filters it, and extracts two columns from it. One of the two columns, is converted from a column of UTC (datetime) strings to one of `QDateTime` objects.

Initially the dummy data I generated was not compatible with the UTC string format in the example code. Rather than tweak the example code, I decided to tweak my dummy data.

Chapter 3 - Create an empty `QMainWindow`

Interestingly, this section provides example code which does not generate any output. Fortunately, it was simple enough to refer to the "Using UI Files" section and add the following snippet to the end of the example code:
if __name__ == "__main__":
    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

Remark: the code also refers to a module called `qApp` from `QtCore` but that throws an error. I was able to fix the error by replacing this import with`QApplication` from QtWidgets and replacing all references to `qApp` with `qApplication`.

The reader may find the full file in my Github repo as `add_main_window.py`.

Chapter 4 - Add a QTableView

This section ramps up the difficulty a little but I find it more useful to focus on the big picture. The section has the following files with the following classes and dependencies of other files.

1) `table_model.py` defines `CustomTableModel`
2) `main_widget.py` defines `Widget` and imports `CustomTableModel` from `table_model`
3) `main_window.py` defines `MainWindow`
4) `add_table_view.py` is the main app and imports `MainWindow` from `main_window` and `Widget` from `main_widget`

The file `main_window.py` is a small variation of `add_main_window.py` in the previous chapter. The difference is that `MainWindow` now gets passed a `widget` which it sets as the central widget via `setCentralWidget()`. Meanwhile, the file `add_table_view.py` is essentially `filter_data.py` from Chapter 2 but instead of printing data to the terminal, passes the data to form a `Widget`. The `widget` instance is then passed to form a `MainWindow` and this is shown to the user.

Run the app using the provided test data by typing `python add_table_view.py -f test_data.csv`.


Observe that the original code results in the left column to adjust to the contents and the remaining space to be allocated to the second column. Rather than focus on fixing this sight for sore eyes, I decided to leave it be and simply acknowledge that there are various settings for adjusting the column width. In particular, while the example used `setSectionResizeMode()` and `setStretchLastSection()`, one can explicitly set a column width with `setColumnWidth()`

Chapter 5 -

Similar to the previous except with `main_widget.py` defining a `Widget` class which contains a `QChartView`. In the Github repo, I placed the example code in a file called `main_widget_chart.py`. I then copied `add_table_view.py` from the previous chapter to `add_chart_view.py` and changed the import.

Run the app using the provided test data by typing `python add_chart_view.py -f test_data.csv`.

Chapter 6 -

Finally, this final step adds a method to the `main_widget_chart.py` file of the previous chapter which plots the series. I named this new file `main_widget_chart_plot.py` and made a copy of the file `add_chart_view.py` as `plot_datapoints.py` to import from it.*

Run the app using the provided test data by typing `python plot_datapoints.py -f test_data.csv`.


*After doing a test run, it occurred to me that the program assumes the data is sorted so I added a line in the `read_data` method which sorts the incoming data by the "time" column.

Other Examples


There are other examples but I decided to end here for now.

C++ and Python


I skip this section.

Other sections


There are some more sections but I decided to end here for now.

Relevant Links:
Getting to Know Qt for Python (Github Repo)

Comments

Popular posts from this blog

PySpark + Anaconda + Jupyter (Windows)

Using tensorflowjs_converter

pyspark: the number of entries in a column which are null or not