diff --git a/.github/workflows/dist-build.yaml b/.github/workflows/dist-build.yaml index 83a7c8e..2a746f6 100644 --- a/.github/workflows/dist-build.yaml +++ b/.github/workflows/dist-build.yaml @@ -1,10 +1,16 @@ name: Build Windows binary +permissions: + contents: read on: push: branches: - release +env: + APP_RELEASE_VERSION: '0.1' + PYTHON_VERSION: '3.13.7' + jobs: build-windows: runs-on: windows-2022 @@ -15,15 +21,15 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: '3.13.7' + python-version: $PYTHON_VERSION - name: Cache pip dependencies uses: actions/cache@v4 with: path: ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-pip-3.13.7-${{ hashFiles('requirements.txt') }} + key: ${{ runner.os }}-pip-$PYTHON_VERSION-${{ hashFiles('requirements.txt') }} restore-keys: | - ${{ runner.os }}-pip-3.13.7- + ${{ runner.os }}-pip-$PYTHON_VERSION- - name: Install dependencies run: pip install -r requirements.txt @@ -41,14 +47,14 @@ jobs: include-package: netCDF4,cftime include-module: netCDF4.utils include-data-dir: "C:\\hostedtoolcache\\windows\\Python\\3.13.7\\x64\\Lib\\site-packages\\offline_folium=offline_folium" - include-data-files: "qwebchannel.js=qwebchannel.js" + include-data-files: "qwebchannel.js=qwebchannel.js,offline_folium=offline_folium" nofollow-import-to: scipy.integrate copyright: 'GNU General Public License v3.0' #windows-console-mode: disable windows-icon-from-ico: 'icon.png' company-name: 'Rok Kuk' product-name: 'NetSeeDF' - file-version: '0.1' + file-version: $APP_RELEASE_VERSION - name: Upload artifact id: artifact_upload @@ -58,12 +64,6 @@ jobs: name: dist-build-windows path: build - - name: If executable upload success - if: steps.artifact_upload.conclusion == 'success' - run: | - echo "Executable uploaded successfully" >> $GITHUB_STEP_SUMMARY - echo "uploaded='true'" >> $GITHUB_OUTPUT - - name: If executable upload fails if: failure() && steps.artifact_upload.conclusion == 'failure' run: | @@ -80,15 +80,15 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: '3.13.7' + python-version: $PYTHON_VERSION - name: Cache pip dependencies uses: actions/cache@v4 with: path: ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-pip-3.13.7-${{ hashFiles('requirements.txt') }} + key: ${{ runner.os }}-pip-$PYTHON_VERSION-${{ hashFiles('requirements.txt') }} restore-keys: | - ${{ runner.os }}-pip-3.13.7- + ${{ runner.os }}-pip-$PYTHON_VERSION- - name: Install dependencies run: pip install -r requirements.txt @@ -113,7 +113,7 @@ jobs: macos-app-icon: 'icon.png' company-name: 'Rok Kuk' macos-app-name: 'NetSeeDF' - macos-app-version: '0.1' + macos-app-version: $APP_RELEASE_VERSION - name: Upload artifact id: artifact_upload @@ -123,12 +123,6 @@ jobs: name: dist-build-macos path: build - - name: If executable upload success - if: steps.artifact_upload.conclusion == 'success' - run: | - echo "Executable uploaded successfully" >> $GITHUB_STEP_SUMMARY - echo "uploaded='true'" >> $GITHUB_OUTPUT - - name: If executable upload fails if: failure() && steps.artifact_upload.conclusion == 'failure' run: | @@ -145,15 +139,15 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: '3.13.7' + python-version: $PYTHON_VERSION - name: Cache pip dependencies uses: actions/cache@v4 with: path: ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-pip-3.13.7-${{ hashFiles('requirements.txt') }} + key: ${{ runner.os }}-pip-$PYTHON_VERSION-${{ hashFiles('requirements.txt') }} restore-keys: | - ${{ runner.os }}-pip-3.13.7- + ${{ runner.os }}-pip-$PYTHON_VERSION- - name: Install dependencies run: pip install -r requirements.txt @@ -161,7 +155,6 @@ jobs: - name: Install offline_folium map files run: python -m offline_folium - # Remove problematic brew libs if Intel Mac - name: Remove problematic brew libs run: | brew remove --force --ignore-dependencies openssl@3 @@ -184,7 +177,7 @@ jobs: macos-app-icon: 'icon.png' company-name: 'Rok Kuk' macos-app-name: 'NetSeeDF' - macos-app-version: '0.1' + macos-app-version: $APP_RELEASE_VERSION - name: Upload artifact id: artifact_upload @@ -194,12 +187,6 @@ jobs: name: dist-build-macos-intel path: build - - name: If executable upload success - if: steps.artifact_upload.conclusion == 'success' - run: | - echo "Executable uploaded successfully" >> $GITHUB_STEP_SUMMARY - echo "uploaded='true'" >> $GITHUB_OUTPUT - - name: If executable upload fails if: failure() && steps.artifact_upload.conclusion == 'failure' run: | diff --git a/.gitignore b/.gitignore index 76f3668..f9a2479 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,7 @@ dist .venv profile_stats.prof netseedf.dist +netseedf.build +netseedf.onefile-build netseedf.cmd netseedf.exe diff --git a/datawindow_1d.py b/datawindow_1d.py index d8c6b8c..193e0dc 100644 --- a/datawindow_1d.py +++ b/datawindow_1d.py @@ -52,6 +52,13 @@ def __init__(self, file_name, variable_name, file_path): except Exception: pass + # display description of the variable if given in the NetCDF file + try: + desc_label = QLabel("Description: \t" + variable_data.description, wordWrap=True) + layout.addWidget(desc_label) + except Exception: + pass + # display the data in a table data_table = QTableWidget(self) data_table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers) diff --git a/datawindow_2d.py b/datawindow_2d.py index 4de7595..c33f75d 100644 --- a/datawindow_2d.py +++ b/datawindow_2d.py @@ -44,8 +44,6 @@ def __init__(self, file_name, variable_name, file_path): except Exception: pass - print(ncfile.variables) - # display calendar type if given the NetCDF file try: if variable_data.calendar is not None: @@ -54,6 +52,13 @@ def __init__(self, file_name, variable_name, file_path): except Exception: pass + # display description of the variable if given in the NetCDF file + try: + desc_label = QLabel("Description: \t" + variable_data.description, wordWrap=True) + layout.addWidget(desc_label) + except Exception: + pass + # display the data in a table data_table = QTableView(self) data_table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers) diff --git a/datawindow_3d.py b/datawindow_3d.py index e5af420..e35eb01 100644 --- a/datawindow_3d.py +++ b/datawindow_3d.py @@ -54,6 +54,13 @@ def __init__(self, file_name, variable_name, file_path): except Exception: pass + # display description of the variable if given in the NetCDF file + try: + desc_label = QLabel("Description: \t" + variable_data.description, wordWrap=True) + layout.addWidget(desc_label) + except Exception: + pass + # display the data in a table data_table = QTableView(self) data_table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers) diff --git a/netseedf.py b/netseedf.py index 1324746..b60cb40 100644 --- a/netseedf.py +++ b/netseedf.py @@ -232,12 +232,12 @@ def on_selection_change(self, current, previous): if __name__ == "__main__": - import argparse - import cProfile + #import argparse + #import cProfile - parser = argparse.ArgumentParser(description="NetSeeDF Application") - parser.add_argument('--profile', action='store_true', help='Enable profiling') - args = parser.parse_args() + #parser = argparse.ArgumentParser(description="NetSeeDF Application") + #parser.add_argument('--profile', action='store_true', help='Enable profiling') + #args = parser.parse_args() try: # Set taskbar icon on Windows from ctypes import windll # Only exists on Windows. @@ -251,13 +251,13 @@ def on_selection_change(self, current, previous): window = MainWindow() window.show() - if args.profile: - profile_filename = 'profile_stats.prof' - print(f"Profiling enabled. Results will be saved to {profile_filename}") - with cProfile.Profile() as pr: - exit_code = app.exec() - pr.dump_stats(profile_filename) - print(f"Profile data saved to {profile_filename}. You can analyze it with 'python -m pstats {profile_filename}' or a visualization tool like SnakeViz.") - sys.exit(exit_code) - else: - sys.exit(app.exec()) + # if args.profile: + # profile_filename = 'profile_stats.prof' + # print(f"Profiling enabled. Results will be saved to {profile_filename}") + # with cProfile.Profile() as pr: + # exit_code = app.exec() + # pr.dump_stats(profile_filename) + # print(f"Profile data saved to {profile_filename}. You can analyze it with 'python -m pstats {profile_filename}' or a visualization tool like SnakeViz.") + # sys.exit(exit_code) + # else: + sys.exit(app.exec()) diff --git a/plotwindow_2d.py b/plotwindow_2d.py index abb20ae..12c8630 100644 --- a/plotwindow_2d.py +++ b/plotwindow_2d.py @@ -88,7 +88,12 @@ def __init__(self, file_name, variable_name, file_path): except Exception: pass - ncfile.close() + # display description of the variable if given in the NetCDF file + try: + desc_label = QLabel("Description: \t" + variable_data.description, wordWrap=True) + layout.addWidget(desc_label) + except Exception: + pass scheme = QWebEngineUrlScheme(b'qrc') scheme.setFlags(QWebEngineUrlScheme.Flag.LocalScheme | QWebEngineUrlScheme.Flag.LocalAccessAllowed) @@ -107,10 +112,10 @@ def __init__(self, file_name, variable_name, file_path): maplayout.addWidget(self.view) # intial data load - ncfile = Dataset(self.file_path, "r") - variable_data = ncfile.variables[self.variable_name] masked_data = ma.masked_equal(variable_data, self.fill_value) + ncfile.close() + image, colorbar = self.getb64image(masked_data) # map raster layer diff --git a/plotwindow_3d.py b/plotwindow_3d.py index bb8ce48..1686345 100644 --- a/plotwindow_3d.py +++ b/plotwindow_3d.py @@ -110,6 +110,13 @@ def __init__(self, file_name, variable_name, file_path): except Exception: pass + # display description of the variable if given in the NetCDF file + try: + desc_label = QLabel("Description: \t" + variable_data.description, wordWrap=True) + layout.addWidget(desc_label) + except Exception: + pass + slice_selector_widget = QWidget() slice_selector_layout = QHBoxLayout() slice_selector_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) @@ -156,8 +163,6 @@ def __init__(self, file_name, variable_name, file_path): self.units_are_kelvin = True layout.addWidget(temp_convert_widget) - ncfile.close() - scheme = QWebEngineUrlScheme(b'qrc') scheme.setFlags(QWebEngineUrlScheme.Flag.LocalScheme | QWebEngineUrlScheme.Flag.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(scheme) @@ -175,15 +180,15 @@ def __init__(self, file_name, variable_name, file_path): maplayout.addWidget(self.view) # intial data load - ncfile = Dataset(self.file_path, "r") - variable_data = ncfile.variables[self.variable_name] if self.slice_dim_index == 0: # select the slice and read it into memory from disk sliced_data = variable_data[0, :, :] elif self.slice_dim_index == 1: sliced_data = variable_data[:, 0, :] else: sliced_data = variable_data[:, :, 0] + ncfile.close() + sliced_data = ma.masked_equal(sliced_data, self.fill_value) image, colorbar = self.getb64image(sliced_data)