diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 7238623..7f4855c 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.1.10 +current_version = 0.1.11 commit = True tag = True diff --git a/.github/workflows/finalize-release.yml b/.github/workflows/finalize-release.yml index 55eaf9c..7c5bbd7 100644 --- a/.github/workflows/finalize-release.yml +++ b/.github/workflows/finalize-release.yml @@ -26,6 +26,8 @@ jobs: with: ref: release lfs: true + fetch-depth: 0 # Fetch all history for changelog generation + fetch-tags: true # Explicitly fetch all tags - name: Get version from files run: | @@ -91,57 +93,67 @@ jobs: - name: Generate comprehensive release notes run: | - # Check if we have any commits - if ! git rev-parse HEAD >/dev/null 2>&1; then - echo "No commits found" - CHANGELOG="- Initial release" - PREV_TAG="" - else - # Get previous release tag (check if any tags exist first) - if git tag -l | grep -q .; then - PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || git describe --tags --abbrev=0 2>/dev/null || echo "") - else - PREV_TAG="" + # Fetch all tags from all branches to ensure we have complete history + git fetch --all --tags + + # Get all tags sorted by version + ALL_TAGS=$(git tag -l "v*" --sort=-version:refname) + echo "All tags found: $ALL_TAGS" + + # Get the current tag (the one we're creating) + CURRENT_TAG="${{ env.APP_TAG }}" + + # Find the previous tag (excluding the current one if it exists) + PREV_TAG="" + for tag in $ALL_TAGS; do + if [ "$tag" != "$CURRENT_TAG" ]; then + PREV_TAG=$tag + break fi + done - # Generate changelog - if [ -z "$PREV_TAG" ]; then - # No previous tags, get all commits except the version bump - if git rev-parse HEAD~1 >/dev/null 2>&1; then - CHANGELOG=$(git log --oneline --pretty=format:"- %s" HEAD~1) - else - CHANGELOG="- Initial release" - fi + echo "Previous tag: ${PREV_TAG:-none}" + echo "Current tag: $CURRENT_TAG" + + # Generate changelog + if [ -z "$PREV_TAG" ]; then + echo "No previous tag found, including all commits" + # For first release, get all commits + CHANGELOG=$(git log --oneline --pretty=format:"- %s" --reverse HEAD 2>/dev/null || echo "- Initial release") + else + echo "Generating changelog from $PREV_TAG to $CURRENT_TAG" + # Since tags are on master, get commits between tags + # Use the current tag if it exists, otherwise use HEAD + if git rev-parse "$CURRENT_TAG" >/dev/null 2>&1; then + CHANGELOG=$(git log --oneline --pretty=format:"- %s" ${PREV_TAG}..${CURRENT_TAG} 2>/dev/null || echo "- Release updates") else - # Get commits since last tag - CHANGELOG=$(git log --oneline --pretty=format:"- %s" ${PREV_TAG}..HEAD~1 2>/dev/null || echo "- Release updates") + CHANGELOG=$(git log --oneline --pretty=format:"- %s" ${PREV_TAG}..HEAD 2>/dev/null || echo "- Release updates") fi fi + # Filter out version bump commits and merge commits + CHANGELOG=$(echo "$CHANGELOG" | grep -v "^- Bump version:" | grep -v "^- Merge" | grep -v "^- \[pre-commit\]" || true) + + # If changelog is empty, use a default message + if [ -z "$CHANGELOG" ]; then + CHANGELOG="- Release updates" + fi + + echo "Generated changelog:" + echo "$CHANGELOG" + cat > release_notes.md << EOF ## What's New in v${{ env.VERSION }} - ${CHANGELOG:-"- Initial release"} + $CHANGELOG ## Downloads This release includes distributables for the following platforms: ### macOS - - **Apple Silicon (M1/M2/M3)**: Download the \`aarch64-apple-darwin\` version - - **Intel Macs**: Download the \`x86_64-apple-darwin\` version - - ## Installation Instructions - - ### macOS - 1. Download the appropriate \`.dmg\` file for your Mac architecture - 2. Open the downloaded \`.dmg\` file - 3. Drag the app to your Applications folder - 4. Launch the app from Applications - - ## System Requirements - - - **macOS**: 10.15 (Catalina) or later + - **Apple Silicon (M1/M2/M3)**: Download the \`aarch64\` version + - **Intel Macs**: Download the \`x64\` version ## Support diff --git a/.github/workflows/package-and-release.yml b/.github/workflows/package-and-release.yml index e8a1b95..dda171f 100644 --- a/.github/workflows/package-and-release.yml +++ b/.github/workflows/package-and-release.yml @@ -57,8 +57,8 @@ jobs: shell: bash -l {0} - name: Package using PyInstaller run: | - chmod +x setup_tauri.sh - ./setup_tauri.sh + chmod +x scripts/setup_tauri.sh + ./scripts/setup_tauri.sh shell: bash -l {0} - name: setup node uses: actions/setup-node@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 4dd4931..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,56 +0,0 @@ -# Changelog - -All notable changes to QuickView will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to -[Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -### Added - -- Pre-commit hooks for code quality (ruff, prettier, codespell) -- CI/CD pipeline with GitHub Actions -- Visual indicators for manual color range override mode -- Override range persistence in saved states -- Pull request templates for different types of changes - -### Changed - -- Improved color range override logic to properly persist through state changes -- ViewManager methods renamed for clarity (e.g., `reset_views()` → - `render_all_views()`) -- Toolbar UI improvements with visual grouping and pipeline status indicators - -### Fixed - -- Menu expansion conflict with tooltips in toolbar -- Context manager error in ViewManager -- Color range override flag lost during view rebuilding -- Module-level import issues in ParaView plugins - -### Security - -- Added defensive security measures to prevent malicious code execution - -## [0.1.0] - 2024-01-01 - -### Added - -- Initial release of QuickView -- Support for E3SM atmospheric data visualization -- Multiple projection support (Cylindrical Equidistant, etc.) -- Variable selection for 2D and 3D data -- Time step navigation -- State save/load functionality -- Cross-platform desktop application using Tauri -- ParaView-based rendering pipeline - -### Known Issues - -- Performance optimization needed for large datasets -- Limited to specific E3SM data formats - -[Unreleased]: https://github.com/E3SM-Project/QuickView/compare/v0.1.0...HEAD -[0.1.0]: https://github.com/E3SM-Project/QuickView/releases/tag/v0.1.0 diff --git a/README.md b/README.md index 9549822..9e5fefd 100644 --- a/README.md +++ b/README.md @@ -3,141 +3,82 @@ [![Test](https://github.com/ayenpure/QuickView/actions/workflows/test.yml/badge.svg)](https://github.com/ayenpure/QuickView/actions/workflows/test.yml) [![Package and Release](https://github.com/ayenpure/QuickView/actions/workflows/package-and-release.yml/badge.svg)](https://github.com/ayenpure/QuickView/actions/workflows/package-and-release.yml) -**QuickView** is an interactive visualization tool designed specifically for -atmospheric scientists working with E3SM (Energy Exascale Earth System Model) -data. Built on ParaView and Trame, it provides an intuitive interface for -exploring atmospheric simulation outputs without the steep learning curve of -general-purpose visualization tools. +**QuickView** is an interactive visualization tool for atmospheric scientists working with E3SM (Energy Exascale Earth System Model) data. It provides an intuitive interface for exploring atmospheric simulation outputs without the steep learning curve of general-purpose visualization tools. ![quickview](docs/images/main.png) -## Why QuickView? +## Quick Start -Traditional visualization tools like ParaView and VisIt, while powerful, often -require significant time investment to master their complex interfaces and may -lack atmospheric science-specific features out of the box. QuickView addresses -these challenges by: +### Prerequisites +- Python 3.13+ +- ParaView 5.13.3+ (installed via conda) -- **Reducing the learning curve** - Atmospheric scientists can start visualizing - their data immediately -- **Eliminating "last-mile" effort** - No need to write custom scripts or - plugins for common tasks -- **Accelerating insights** - Focus on science, not software configuration -- **Building on proven technology** - Leverages ParaView's robust data - processing with a tailored interface - -## Installation - -### Using Conda (Recommended) - -1. Create and activate a conda environment: - -```bash -conda env create -f quickview-env.yml -conda activate quickview -``` - -2. Install QuickView: - -```bash -pip install . -``` - -### Requirements - -- Python 3.13 -- ParaView 5.13.3 (installed automatically with conda environment) -- Trame and other dependencies (installed automatically) - -## Getting the Code - -### Clone from GitHub +### Installation ```bash +# Clone the repository git clone https://github.com/ayenpure/QuickView.git cd QuickView -``` -### Download as Archive +# Set up conda environment +conda env create -f quickview-env.yml +conda activate quickview -```bash -wget https://github.com/ayenpure/QuickView/archive/main.tar.gz -tar -xvzf main.tar.gz -cd QuickView-main +# Install QuickView +pip install -e . ``` -## Running the Application - -To run QuickView with a data file: +### Running QuickView ```bash -python -m quickview.app --data data/aerosol_F2010.eam.h0.2014-12.nc -``` - -### Command Line Options - -- `--data`: Path to the NetCDF data file (required) -- `--conn`: Path to the connectivity file (optional) -- `--port`: Server port (default: 8080) -- `--host`: Server host (default: localhost) +# With sample data +quickview --data data/aerosol_F2010.eam.h0.2014-12.nc -### Example with Custom Files - -```bash -python -m quickview.app --data /path/to/your/data.nc --conn /path/to/your/connectivity.nc +# With your own data +quickview --data /path/to/your/data.nc --conn /path/to/connectivity.nc ``` -The application will start a Trame web server. Open your browser and navigate -to: +The application starts a web server at `http://localhost:8080` -``` -http://localhost:8080 -``` +## Documentation -## Sample Data +- **[Installation Guide](docs/setup/requirements.md)** - Detailed setup instructions +- **[User Guide](docs/userguide/launch.md)** - How to use QuickView +- **[Data Requirements](docs/data-requirements.md)** - NetCDF file format specifications +- **[Control Panel Reference](docs/userguide/control_panel.md)** - UI components and features -The repository includes sample data files in the `data/` directory for testing: +## Key Features -- `aerosol_F2010.eam.h0.2014-12.nc` - Sample atmospheric data -- Default connectivity file is automatically loaded +- Clean, minimalist interface tailored for atmospheric modeling +- Multi-variable visualization with drag-and-drop layout +- Geographic projections (Plate Carrée, Robinson, etc.) +- Persistent sessions - pick up where you left off +- Support for EAM v2, v3, and upcoming v4 data formats ## Development -For development setup and contribution guidelines, please see -[CONTRIBUTING.md](CONTRIBUTING.md). +See [CLAUDE.md](CLAUDE.md) for development setup and architecture details. -## Documentation +```bash +# Run linter +ruff check quickview/ -Comprehensive documentation is available in the [docs/](docs/) directory, -including: +# Run tests +python -m quickview.app --help -- [User Guide](docs/userguide/launch.md) - Detailed usage instructions -- [Control Panel Guide](docs/userguide/control_panel.md) - Interface overview -- [Viewport Customization](docs/userguide/viewport.md) - Working with multiple - variables -- [Data Requirements](docs/data-requirements.md) - NetCDF file format and - required variables +# Bump version +bumpversion patch +``` ## About -QuickView is developed by [Kitware, Inc.](https://www.kitware.com/) in -collaboration with -[Pacific Northwest National Laboratory](https://www.pnnl.gov/). It is supported -by the U.S. Department of Energy's -[Biological and Environmental Research (BER)](https://www.energy.gov/science/ber/biological-and-environmental-research) -and -[Advanced Scientific Computing Research (ASCR)](https://www.energy.gov/science/ascr/advanced-scientific-computing-research) -programs via the -[Scientific Discovery through Advanced Computing (SciDAC)](https://www.scidac.gov/) -program. +QuickView is developed by [Kitware, Inc.](https://www.kitware.com/) in collaboration with [Pacific Northwest National Laboratory](https://www.pnnl.gov/), supported by the U.S. Department of Energy's [BER](https://www.energy.gov/science/ber/biological-and-environmental-research) and [ASCR](https://www.energy.gov/science/ascr/advanced-scientific-computing-research) programs via [SciDAC](https://www.scidac.gov/). ### Contributors - **Lead Developer**: Abhishek Yenpure (Kitware, Inc.) -- **Key Contributors**: Berk Geveci, Sebastien Jourdain (Kitware, Inc.); Hui - Wan, Kai Zhang (PNNL) +- **Key Contributors**: Berk Geveci, Sebastien Jourdain (Kitware, Inc.); Hui Wan, Kai Zhang (PNNL) ## License -This project is licensed under the Apache Software License - see the -[LICENSE](LICENSE) file for details. +Apache Software License - see [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 329bf32..8085a93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "quickview" -version = "0.1.10" +version = "0.1.11" description = "An application to explore/analyze data for atmosphere component for E3SM" authors = [ {name = "Kitware Inc."}, diff --git a/quickview/__init__.py b/quickview/__init__.py index 14d8a4f..3029b22 100644 --- a/quickview/__init__.py +++ b/quickview/__init__.py @@ -1,5 +1,5 @@ """QuickView: Visual Analysis for E3SM Atmosphere Data.""" -__version__ = "0.1.10" +__version__ = "0.1.11" __author__ = "Kitware Inc." __license__ = "Apache-2.0" diff --git a/quickview/colorbar_cache.py b/quickview/colorbar_cache.py index e2dbc41..836dee7 100644 --- a/quickview/colorbar_cache.py +++ b/quickview/colorbar_cache.py @@ -2,9 +2,25 @@ # Generated using generate_colorbar_cache.py COLORBAR_CACHE = { - "oslo": { - "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAmUlEQVQokXWRWQ7EMAxCedz/zp2PeiEZVa0QEJzEDoAwtjAYiggGAUGjASkcWVB/c4RovzkR0ByhU3Yedof201xe99Th36t/ye70DmTXaRLml/QrXWSxHNzfFNwbeaQc5B2DUUgZ1QP0+NFwTimkTapMF3k+A8EjP2exS1cVeTG6EPezmMRu09PvORwH5pR8jXt4b2Z75AYKf0CgA/rlIrMBAAAAAElFTkSuQmCC", - "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAmElEQVQokW2RUQ7EQAhC6f3vzNuPjoqdTRMDQo2DD2ADviperLU0UB8lYTid7qeEqq9S1RXrAGQVQIxHIKTB7xwFDbyc0kw7nmf5/xjkwWzazlnMszBB93sjlk84GeeOeYJfWWKuYR+qoNrNltRNLamrxoYuZ/YPXmoYRP6l925JQe89w38mNFaP7TWoUb32ucH1FlcCxv4BzjllJjnD7IwAAAAASUVORK5CYII=", + "Inferno (matplotlib)": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAtElEQVQokY2SQW7EMAzEyLH6/x+velC8TorFooAhkKNJLrZQIgqRYAYccA1f8+jSZBcyCcnoMJGVO3QmHw5KgpsNXuAwm/E24+QIe8tW/qVX2M+wp3kBaIdTG32G/Ul7/7xzoM/np7bZ9l4b/Qqm48uHtpPkhPr6qNxXafL6DuTB5GWakzfBNELm+H5KRAzn8p+vIOumb17trNZ0+uI/s8jqmRYpUp1isxb50cIypaUVS5fWL+AwbZqLAs4pAAAAAElFTkSuQmCC", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAwUlEQVQokY2SUWpDMRDEZnP/Y/SWXUv9WPvlhYS2YIxGjI0xW+0XLG1d2M6iY2uHb+3QoWMXm8sOq+iwQhcrrE87GXCAQB0InM61fIITDUqCISExUiGhpELFgUcorfAYf/HvIKX77PD2n2PpgyeXFrcO/gFY5jVa3E1y1bAwA5pnLeGleYtb5k2GFObck/nUqU18lf+M7hjZl3jtqJGEeFhyoCAaDp8JqIF1zDqTsQy4HOkMxyIoZnnMgR1zeD9kgz+NE+IXkDSoZwAAAABJRU5ErkJggg==", + }, + "Viridis (matplotlib)": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAsklEQVQokXWQ2w0DMQgEZ5fWUkL6L8XkA/xI4pNOaBgWn4ReeiPLWhULSTYSXaXpt2wuOKZTpoRZ8mwXp4RAym4rQAWyeY3ADaf8Yl+nP3U9ew/slkvmaXcDT4H8f6ElSybH6JQ6p5Q5Kyj7otP3GereDZvrwM2zmgnr49qOk6N5WBkLlKZMtcNkaFijMrN2ZgcY0VsjqMdHVJKMWmyTvdtQfydIQ4hAhpCMAhmFZGwU8gd7+IgHAybGAwAAAABJRU5ErkJggg==", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAsklEQVQokXWQ0W3FMAzEKO/S/cfqFDr2I3acF78CgXDiUQjg6t+fkDbBkNZgY7A10NgSaCrSVFOxmmrGDI4wVqhmTOLljGa0lcmrHev2amvPJaz2uqp4O5XpVLyEBXde3+fqIvqchJ31nQUt5nrlUnBzBApB7harVljVA0I9qmVuWCfnNN/rF/7/1QH9KswnuHIO8srxgPOJ2dAKzN/JFo78XPOEYg6Yu9XMKkHNLcc1/wAGJ3utf9Ck5gAAAABJRU5ErkJggg==", + }, + "grayC": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAASUlEQVQokbWSOw4AMAhCgfsfukOTxrRWTT8MBh6MEoAkSSRlRLITngrAq2U82LUuX2FK6rFY3fg0BjDgn+T+zwonYqPr68aN4zZHpwL88xPUcgAAAABJRU5ErkJggg==", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAR0lEQVQokbWSSQoAIAwD6///nHgQROxiEM2hZKY9tpEkCSCcGYql6B5Dk8l/MTPdb7LAV11fHVE0mSy8slUOLi591recGdgB5Ri1JqWVr6UAAAAASUVORK5CYII=", + }, + "roma": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAxUlEQVQokW2PQQ7DIAwEd80j+tv+nJ0eDCRpK1nWMF6I4/dLHl5V9pCrWS67XBtcl9T96C+W7tKd1za2T+Bn6n/J/ZqOP+b6UFftTO2+QNU/c+RYcrNr6MHjGNWwjxnyv+5iM67uaNBehSsuVDSrUHefHjkNOPK9T/QANGnWXEclmg1o5jIJE82058hEExIlZJtcZgEhiJAISOAJ3AGRBQoAEUGsjHamzckICOrRuX5iPY0I65Etl1+B5w7Zu4UAWTsndH0AoR4v4nBAd8IAAAAASUVORK5CYII=", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAA0ElEQVQokWWPQY4gIRDD4vCi+e18lmQPTQM9K6GScQUoGD+/Nnth2WAMGCzMWQijxejtCrBkALz8kssA0gqfLjy3rdjKXAdPBt0zPJkN/oItjBHrXzI3yMboMeM1A9kaxmhYg0uiYRkNtI3RoK+skelAVm/41li1aoVPjRUaHm5opNBJgyaNuqoy6dTL/9dmKrOHs0xmF2dzEyU9Jk3bLdsPVO27bdO2emFL9Rilra6w2otXTOueP8ndPQ+9x093sfZI0Z4kh9XZpp1q2tnO/gOZg0urikp4YQAAAABJRU5ErkJggg==", + }, + "navia": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAr0lEQVQokXWS0Q3EIAxD/ZwRbojbf0LuwyGlrQ6h6OE4CVWhPl9sYYGwMOS4t+/HePzXw6PE05BhsMzotA62yIqh18mA2tVRzQLUoCcosEBS9LVFoRWQxrCECOhIjfmdOmqvJjr67ynTIXd4zVpM9qqK8yqBu/+hv5Qz+r/ijjrZ+XuzHSCxHKbApsBgXK24sKGwCb9ANuWt3I5qEdWGI+IM31dgsvvd5Emdyv4++AEbhyvIyFxhOAAAAABJRU5ErkJggg==", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAr0lEQVQokXWSQY7EIBADzf9fuP/Y41I1h24IzMxGqFU2dkgkxt/vj0E1LtgTorIdNgsdQNvfEzGzgOXgPLjlXPINpqBTgKlTaUcoKTrreNck2MslNTj0Yh0YF//n9Ex05MMpTi4/xbuSoUlXjnySs1KywzFHN7v1QHrrCew3xHzfeutex/VnP6f0L1TxE1xc0DMU99M35WE6V9dKCiJKBRafPnEt0EvmkN7ye+ZhIy9nOgFitgzqrgAAAABJRU5ErkJggg==", }, "batlow": { "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAArklEQVQokW2RwZEEMQjEWk0UG9rmHwj3AGzmZj+ULBqbKsPniwVggTAgvVjFCEswICFASC4uyeKVYWeuBEntf9TV4so8x8VZYTckyN3NBqWvT1ThnKrFPVLJU1deXn515ecl77DZmWZ3prbVGF3uIyNlYckwsoACBgyW3V/qYxDGFpZ5gOmAza3TMgooMMQ/EEHvFf2UYnaJ2Tdqdy0/fPxPWRxH5ls+Z/PymYrEfz0jPL9tQdmmAAAAAElFTkSuQmCC", @@ -14,13 +30,9 @@ "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAuUlEQVQokXWOUXIGIQyCAfcEvWHvf4ZAH4xbbf1nMuwHQVfi65siSCz9Y1uv4U35qfxut7/MMklKFKWFIiWJWnZMu2CcsOlmx2X73O3H5Nlv5r9EHNIjDi77CxjkEAZ7BIgZgBDCSggzPbARw9Xqig1XXLCTysue7FTFhWzJ0blaJ0cCO7nbrsXrJb2CnX6Su7a4m/Gy5ZWnmr3Ytue3smzK201OGX4nJwTJYW0kcNjbGb4wt2YfDH4AjnNMdUGwXfEAAAAASUVORK5CYII=", "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAwUlEQVQokXWOQZbDMAxCAW3minP/a1TQha20btM8P/xBODb/8SdCBAkRUkhIEEFhjxYI4mt66RwcfQehBInayhJV1PoW1HasksRhXqzNpHCxRBbeeO4oct1X6wh11Yqczp3F/OdIVL8sVaComtfW0dnPq/USqKACNapwFmQykMEGHBrozDI66aCddjq54OG0va3T9mOP/JlM7fHq3ydfBbfTfdpz6hN8ghM7GZtt1xY4cZDEwQUJxn5o7sKf+hXmDJ8lOkiIWk7JIwAAAABJRU5ErkJggg==", }, - "roma": { - "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAxUlEQVQokW2PQQ7DIAwEd80j+tv+nJ0eDCRpK1nWMF6I4/dLHl5V9pCrWS67XBtcl9T96C+W7tKd1za2T+Bn6n/J/ZqOP+b6UFftTO2+QNU/c+RYcrNr6MHjGNWwjxnyv+5iM67uaNBehSsuVDSrUHefHjkNOPK9T/QANGnWXEclmg1o5jIJE82058hEExIlZJtcZgEhiJAISOAJ3AGRBQoAEUGsjHamzckICOrRuX5iPY0I65Etl1+B5w7Zu4UAWTsndH0AoR4v4nBAd8IAAAAASUVORK5CYII=", - "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAA0ElEQVQokWWPQY4gIRDD4vCi+e18lmQPTQM9K6GScQUoGD+/Nnth2WAMGCzMWQijxejtCrBkALz8kssA0gqfLjy3rdjKXAdPBt0zPJkN/oItjBHrXzI3yMboMeM1A9kaxmhYg0uiYRkNtI3RoK+skelAVm/41li1aoVPjRUaHm5opNBJgyaNuqoy6dTL/9dmKrOHs0xmF2dzEyU9Jk3bLdsPVO27bdO2emFL9Rilra6w2otXTOueP8ndPQ+9x093sfZI0Z4kh9XZpp1q2tnO/gOZg0urikp4YQAAAABJRU5ErkJggg==", - }, - "tokyo": { - "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAoUlEQVQokW2Syw3DMAxD+eh7J+gY3X+2HiRZih0EEEjq+R++nx/IwsgCyWDxCDlD2C2MzJPhWZ08IwfhEGVDxBSZSNXVsGqbcCd6dCXuVjNHIilm0+jedVheAN6BS/Tq99JcQ/pERU5s3M/J+4DBewgg+RbQ5K4onyyf8NQpnLU+XMZhQrnUGnZFXdtie5kKqXAKhTVqi8hEgC2QHdvtX89/EjgCyIkUtH0AAAAASUVORK5CYII=", - "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAq0lEQVQokXWSQQ6DMAwEp/9/Y9/QD5SdHuIEJ6gCWbvLYISd1+f7FiVRsekENakkYkxKJ2bZmHh1ca0kV4WZYVaNmcBto9M5WtZloqtqVIllm0aMqOGuQlRQwikEGSSOEITs1tmq3c0KnDw7xkbWIzayC5c9XuQfwAE8+nvw/vtu6X0CbH/nPi7bfGx2JpqRr9Om4jx8qby2Z2iLnZV723PJU4x9doZHyB3+APLS0HEVvfePAAAAAElFTkSuQmCC", + "lajolla": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAArElEQVQokXWRUY5EIQgEq5pTzP0vuh+Co+/tJMY01YgKfj6ogrQAFVmw9QW9LJ/WkaNC8N8wAxfJT60SjIrxEFfIDjOud3i4bFgaePGLVPO9MznrnWxLiUbcbvcIQ6ZB04juhYEDdtE9g6zxLCEPuIb3zV93D7+TOcZwHX+m+So7K8ctd+X+dn/EGzqPl57o6k6mRyHRkGD87kVKQwrLFMYUFpYWv3SvjM6b/AE3AwLH88Pa5AAAAABJRU5ErkJggg==", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAqklEQVQokW2RWw7DMAzDuPsfbWeKuI84TrMGKAqZVl7yx3xhYHBoCbwQiw9y12ZgTPOQyYOZfxINRURNUKJKwAmnwIggRKd4QjEsrcIuKX9a+1pC70kOz8WWxynHtq9r5IBuXTdsMt/acH7R1aIScgawQpJgKq0S0fBsOR56df0jo8jJD6hn2WZPc5cusxJq+RrpRe/Z1rtXxq+yRrEFlZk94d3ir7XhnuEPk2frRoSfIrIAAAAASUVORK5CYII=", }, "davos": { "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAApklEQVQokYWSUa7DIAwEd0Z6l+v975N+2CbQNnqRsGbXGKMY8veKRqJABAxQEpEADRbWqhIAzQCQL6iqrfxMdV9WdjZwf9MhG5dqcMkVG3I4HxySQ36bCVynf0Gy+Amyqi5IPv1/5Hn+c5e6WwKXDxeWzWmZ+eu3Y4+ix95ynoAiOIA3qz8jKi6nti9gM7eDnSey2Jl6X2rAlN9RUilSZixIVWWZzW/flBj7cleqDQAAAABJRU5ErkJggg==", @@ -30,36 +42,40 @@ "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAi0lEQVQokYWRyREDIQwEu+fvNByH84/KD/CuhKGWD6O5isP36+NYmTtqfsPCFwldPJWhBDfSKfKM2fJnI+FiUMOQEISAOvAcoai3tKj55y+/lWkgLW56bZrTxoyTi5h5OzIvvX8t2oeq8yWIFEMhU8kbGOMhm41/re2gNTuaWf3sVFhTXD2r4RkDfgEEQgLT9KY7/QAAAABJRU5ErkJggg==", "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAjUlEQVQokZWSOxJDMQgDlfvfNFXqFNpXYByDPZ5JtyAJf1+f9xeQEBKIqPiHRxZzNrg2HZFdRZ4DF1tCMRQwR78R3v2AcBu7rWUyMg2zKhzLDxAC5LgPCQXLYnB2SqlhHtmUOowUTfoxvb/6D2puMlVi5/MvWHlebQe/3Mi5f2XfPOtbtEg327Vch7j1H1G+JZaGOgELAAAAAElFTkSuQmCC", }, - "grayC": { - "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAASUlEQVQokbWSOw4AMAhCgfsfukOTxrRWTT8MBh6MEoAkSSRlRLITngrAq2U82LUuX2FK6rFY3fg0BjDgn+T+zwonYqPr68aN4zZHpwL88xPUcgAAAABJRU5ErkJggg==", - "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAR0lEQVQokbWSSQoAIAwD6///nHgQROxiEM2hZKY9tpEkCSCcGYql6B5Dk8l/MTPdb7LAV11fHVE0mSy8slUOLi591recGdgB5Ri1JqWVr6UAAAAASUVORK5CYII=", + "oslo": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAmUlEQVQokXWRWQ7EMAxCedz/zp2PeiEZVa0QEJzEDoAwtjAYiggGAUGjASkcWVB/c4RovzkR0ByhU3Yedof201xe99Th36t/ye70DmTXaRLml/QrXWSxHNzfFNwbeaQc5B2DUUgZ1QP0+NFwTimkTapMF3k+A8EjP2exS1cVeTG6EPezmMRu09PvORwH5pR8jXt4b2Z75AYKf0CgA/rlIrMBAAAAAElFTkSuQmCC", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAmElEQVQokW2RUQ7EQAhC6f3vzNuPjoqdTRMDQo2DD2ADviperLU0UB8lYTid7qeEqq9S1RXrAGQVQIxHIKTB7xwFDbyc0kw7nmf5/xjkwWzazlnMszBB93sjlk84GeeOeYJfWWKuYR+qoNrNltRNLamrxoYuZ/YPXmoYRP6l925JQe89w38mNFaP7TWoUb32ucH1FlcCxv4BzjllJjnD7IwAAAAASUVORK5CYII=", }, - "navia": { - "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAr0lEQVQokXWS0Q3EIAxD/ZwRbojbf0LuwyGlrQ6h6OE4CVWhPl9sYYGwMOS4t+/HePzXw6PE05BhsMzotA62yIqh18mA2tVRzQLUoCcosEBS9LVFoRWQxrCECOhIjfmdOmqvJjr67ynTIXd4zVpM9qqK8yqBu/+hv5Qz+r/ijjrZ+XuzHSCxHKbApsBgXK24sKGwCb9ANuWt3I5qEdWGI+IM31dgsvvd5Emdyv4++AEbhyvIyFxhOAAAAABJRU5ErkJggg==", - "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAr0lEQVQokXWSQY7EIBADzf9fuP/Y41I1h24IzMxGqFU2dkgkxt/vj0E1LtgTorIdNgsdQNvfEzGzgOXgPLjlXPINpqBTgKlTaUcoKTrreNck2MslNTj0Yh0YF//n9Ex05MMpTi4/xbuSoUlXjnySs1KywzFHN7v1QHrrCew3xHzfeutex/VnP6f0L1TxE1xc0DMU99M35WE6V9dKCiJKBRafPnEt0EvmkN7ye+ZhIy9nOgFitgzqrgAAAABJRU5ErkJggg==", + "tokyo": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAoUlEQVQokW2Syw3DMAxD+eh7J+gY3X+2HiRZih0EEEjq+R++nx/IwsgCyWDxCDlD2C2MzJPhWZ08IwfhEGVDxBSZSNXVsGqbcCd6dCXuVjNHIilm0+jedVheAN6BS/Tq99JcQ/pERU5s3M/J+4DBewgg+RbQ5K4onyyf8NQpnLU+XMZhQrnUGnZFXdtie5kKqXAKhTVqi8hEgC2QHdvtX89/EjgCyIkUtH0AAAAASUVORK5CYII=", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAq0lEQVQokXWSQQ6DMAwEp/9/Y9/QD5SdHuIEJ6gCWbvLYISd1+f7FiVRsekENakkYkxKJ2bZmHh1ca0kV4WZYVaNmcBto9M5WtZloqtqVIllm0aMqOGuQlRQwikEGSSOEITs1tmq3c0KnDw7xkbWIzayC5c9XuQfwAE8+nvw/vtu6X0CbH/nPi7bfGx2JpqRr9Om4jx8qby2Z2iLnZV723PJU4x9doZHyB3+APLS0HEVvfePAAAAAElFTkSuQmCC", }, "bam": { "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAvUlEQVQokW2Q0W3FMAwDSXm8ztH9F6jIfkhWlNcmgnFHEXAQfsdXnHMi4tQ0xon1vAPuVZBrwbUnm/kIWzjtYU4tyEoW7/Clp8LRP7AYh0/5kEGsQnOQh8MfgCBZAAZxuYEVAiQCLCD+GQwYhDFgwKWXawTYtiFDBXKxml1JyrJTlpwqUF7O4VRr+kdqTVWSnXywJGVaD0uS5AtSSvIVe4WexC91e2084vt207fZ3bXSbffdfa/v4fVh8zv0CzRYXG5OJkEEAAAAAElFTkSuQmCC", "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAvUlEQVQokW2QQY7DMAwDSarX/dn+/zcme7DsCG2DQJ6RaMcI//4hsqQSJUkUVdLlBkl8Apwdsol8pmd0suQM8x4+k5pnnjvc72pcTCWJ1aDqysEqqYr1g3k7L11lqX/DZB0Vd0X1lSlCpIjLJBqAzSQ274rmoDXA1gBbf7xJAAMJgvjWwA1xcxJ4a/INaza9tQMrsXvaMd/84AG9cYPt2X/Un03bSRynyV+8/YHed3hgr+c5uj5W2+vIWl6tb9Q4Uct7Ls3FAAAAAElFTkSuQmCC", }, - "lajolla": { - "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAArElEQVQokXWRUY5EIQgEq5pTzP0vuh+Co+/tJMY01YgKfj6ogrQAFVmw9QW9LJ/WkaNC8N8wAxfJT60SjIrxEFfIDjOud3i4bFgaePGLVPO9MznrnWxLiUbcbvcIQ6ZB04juhYEDdtE9g6zxLCEPuIb3zV93D7+TOcZwHX+m+So7K8ctd+X+dn/EGzqPl57o6k6mRyHRkGD87kVKQwrLFMYUFpYWv3SvjM6b/AE3AwLH88Pa5AAAAABJRU5ErkJggg==", - "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAqklEQVQokW2RWw7DMAzDuPsfbWeKuI84TrMGKAqZVl7yx3xhYHBoCbwQiw9y12ZgTPOQyYOZfxINRURNUKJKwAmnwIggRKd4QjEsrcIuKX9a+1pC70kOz8WWxynHtq9r5IBuXTdsMt/acH7R1aIScgawQpJgKq0S0fBsOR56df0jo8jJD6hn2WZPc5cusxJq+RrpRe/Z1rtXxq+yRrEFlZk94d3ir7XhnuEPk2frRoSfIrIAAAAASUVORK5CYII=", - }, "Rainbow Desaturated": { "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAf0lEQVQokb2MSwrDMAxExxkV52a5/7oncSxZXfSD6rgkIVAQjydpmLQs99asNR3SfXzfpbuNCwnkG7Kc43wy/6QkaIEVWHnJT67HYl3bGl+SLAsy8eEc/Aq3PQJAAQXqP0Qb1KC2I/VAppO6uTiSTBPfIyTjGpzk1xq/ZBcevh6R9SSE4xjKlAAAAABJRU5ErkJggg==", "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAgUlEQVQokb2MwRLCIAxENyHI1/X/r35GM02CB2WYYq3Ug5c3L7sLdF8Wj/AIi/AId9+d36rX2aqDdl8RqiRIgjCekpvItOTpMTIggPxDDFCDeufqY/Ib3/+xmiAFqTTeuvfwlMOrs1mBVegGtWtcL+7VoBs5mBOzDCQ6CGdI9LF9AEoJAHMyopBpAAAAAElFTkSuQmCC", }, - "Cool to Warm": { - "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAj0lEQVQokY2PwRHEIAwDJdq6Fq7oq0y6B2BsQib57Qhhr/n5/kg0giQbFjMYbFxMzrAXRnNxHXKckPI08GZC1otm1WDK0V4fMvjhkJy/PWTw/SHxEQAkyLY7wLK8hbYgQ7I9QIYF2RIcyexfwtKX4YC5zo69h3Dvh8xZ7+y8622e/Wms28MiPx2K58XhyfkPxwMk8uPUcnsAAAAASUVORK5CYII=", - "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAkElEQVQokY2PQRLDIBRCgelZev9FzydZfE3QmLY75onM+/y83hBJQYREEhJEimAF4YTXa4dRi74IimKE6M9w9EdIhyv0py384kxx8dzC0V/kS2/23MKz/6h3cxgQgI1m2HCD7Z4duVXBxXtu8dGOkVxAq18t8sy3C7G8aOTCohF6z4ekxs9Dkm8Xbgf+e0jlA67XGVo/7bonAAAAAElFTkSuQmCC", - }, - "Jet": { - "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAPElEQVQokb2MwQ0AIAjEamB/Fz7EFbwHJn22XbAhHeJJi2Xp7v7DPFFQid6Z9q0kuhAUyMHyR+eiz+ieC/Oio4VU6TUjAAAAAElFTkSuQmCC", - "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAPElEQVQokbXNwQ0AIAwCQGo7uIOX6AqUaMLzgNhAAjXJ1Mf6fDDy1jgjG6WEUKVd8TwaaihLw9vjPM8PLpPXnpUG7pGjAAAAAElFTkSuQmCC", - }, "Yellow - Gray - Blue": { "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAABAklEQVQokW2NTVJAMQiDSQKMju49lfc/iW5eCy76fqojw6RfSUrx+f6RVtGVVtmV6MTSTnZ4pzq9wy3ULgs/NdTh5mq5yZeaByKXQgE6FGCADnNgtQinOSGYC05I5oTL3OFu7g/r1oAHFOZhSihtNQNKYxgTDGMYAwyD26MBhCGBMEuzbEuz/P56m/MY4xjjmPMYY4xxzDHGGHOMueqG31WzrsDGt7llatacVbOqLl51Q3VVdfd1WbDu/SfwT6yfJdukz0z3pc/WqZerX40OkiRBnOfOeoaPJWq9OV1Sp6vTuIdXcJtfrJu18C9fg32HpP0RpV9hEttXD0vUGUaIIYTzB37sE9oBp0aLAAAAAElFTkSuQmCC", "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAABCElEQVQokW2OQW7FIAxEbUM27f1P2Cu0amXPeLqA0OirFhoe9iPEPz6rqEIXVWxSZLOb7FVkd+uF15TkDTvJ1T53+ZSP+nLt1h+vHvM+PPt6NHWmbDVb+19P6mjPkTZYY/B78GetiAj3iPCIcPfwnbHPsfkoN9z9LbkfZ1v/aX9fG/c+Fo8Ym8dYvOrA2P354H9rzgNzzjHnnNecc4xrzmvOa4zr7f3LLN3SLM1SKtPKsi4TVqrLuqxLXdZpXWJalzGNKaYxDSWWUEIZIWAnINDw5BYptIGiDC202IIEGdRQl1hqiKVKoVTrBRhhhBMGesGKXnDQdtILlvCkFzzbU2tFytMjLcrjF8c3wYUVNTbdAAAAAElFTkSuQmCC", }, + "Blue Orange (divergent)": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAABLUlEQVQokWXQUW5bMQxE0TuknmtnAVlV97+SFmn8RE4+JNsNAhCDwxEECNK7fkuHOKRjgRfCCiI3lOWY5HROZys9glwZGskIjQUpVykylEGK0M4n9souQ47vTcopQs7lIPHzbsrJwo+BIacYIvEQKQ0p0YaUaEgh5U6CkbqF34JbshG6JbfQNXSVD/lQX/4HPqQh1ide0JW4Er/QQQw00CCSSEUSiRYuyjeNq9T1x/0X38WJT/wPPvAHnmbiEyY+3Sc+6XO7d+Oe9Ome7pMq99xT09XuclVXu5puV7vb7dda7bIfR7Rd7TZtyi4oU7hM491s7LXtwo/cp22vi23Xc/B8uddjy13uSZd7PaHczQOuotpVfqTK+paOaSYqa1oLBc884Y7v+BPf7c+HvwARUEha3E6gQgAAAABJRU5ErkJggg==", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAABMElEQVQokWWQQW5cMQxDHyU7bdCuepLe/2CZ6XxL7MKeSYoCBPFICQZk/ebXG/qGjuvwG5qQcn7xgYf8BFKdcob/8VSGnk6EIhVBBE9QpGIQuUGRUqKUUhpfOKUQO4aUIlFITydey5zphjiRlBJSxH4hCClCGYpQShnK4DRntGPsM2JfMhRHZCqmYrBdUzGJqZhoEvM0mjDQFAMN9A7v6DuaZqI3xY/In3f7w+vhKrrchZ/Qi1544Yv+g+/0nX7gy77MMpd9oYd1OS5/wt26t2/tW3FrfzS31q3YsMo0Lrt9fNmFa4NdeJmylilYVpnN5f+lV99WmULVlPXZmN6CtvoVT3MWXmvP6GqqvUy1q1n2Kq9mtVdRrdVUaXW4hmqoBpVqXHLjpg+c3/K1wb7M9RffkB57mVnKkwAAAABJRU5ErkJggg==", + }, + "Cool to Warm (Extended)": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAA7UlEQVQokW2QS25FIQxDbYdx99f9j7qFitgd8Hn3tQVknZiQKBD4pCiR5zyZIvgvi0WKWLzM0lLtWx2HlLThpP3pJYH87b8SSJV2HUkSxdVIN6y//m59/bWqpDq7JFWVRqnEKg2pSgfOKK/5thY5tOGld+LzMXtoYpBFDmKQgyhykB/fX0gjvhpPdMMb0hOe6cM9s2DOdO9wTrTjTjfsdKcNd9rHN7rTvn66M1fmgbkT4o5tL/Zid7vdbXc/dJ3Ydsdtn9fZTxPbSXaZPPxzuyBwYCCBQ2cBAjoM+M4MaMhgIJOGHg6uvgFx1WSAH/EtJrKFrcGEAAAAAElFTkSuQmCC", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAA+ElEQVQokWWQQVbEMAxDLSm8suYw3IX77zkAjCUWSdrO0PSpX2qcxMHXxycTVDFhBalTWUE9wbZGhWUmKF8JctN6YhRRRIBi1UoIEiBJgNh2AkEQ6+/OSYEENYHUZEqkdFNSWpUktFehIELEECQMQndg7QklQQRV065cRUJa+RiQSgNSjQGddpQEjeJmjqImhG/NwzzMo3m8/37/Fuf7Ey0oduCkEyd2Tm6nnc6ljw2+aSeeeedhd7vbC5xHu9t2d9u9R/t84sxvprPTufI+JzzlOUvayTx67FdIYlf+51cDM/TV87nRvU8ndq3CfU1O5Vrwzi972fkDNhKObqnUqaEAAAAASUVORK5CYII=", + }, + "Black-Body Radiation": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAAKElEQVQokWNkYGBgYmBgZmBggqFBxR5wB2BlD7wLhl6QsTIysg42EgCSowL6mmk4BgAAAABJRU5ErkJggg==", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAAALElEQVQokWP8//8/A8Pv//9/D0KS4R8Dw18Ghn8wNKjYA+4AbOyBtn+IBRgAiJwwE57a+5gAAAAASUVORK5CYII=", + }, + "Blue - Green - Orange": { + "normal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAABHElEQVQokWWSXZLcMBCCG9r25P5nyyFyhR0JyINkz26ioqgP9KKfxu8/76/p98yXPJQpT2UowxkfqA3OdIZraIGnMu0pD2fKczV63HJky7E325YsSVLk+CNnrw1WpLISVxy77MjerFhlwYaFCCVE8IRVEWJEyERmZSKqR1CgoqpHjndxGA4cZDsTppiwiilWiKLDWZyFAK4KkP84haBSCFlAEQUUWEQRaIBkA9+5Hye5I5tokOSze4D3Fps8PuoFvdX9jU/2q49ffb76ePX56uPq6zquq8/ruM4+mTDpKu57hwmS2OWsNy+v6LKzyvs7Ipc2bNmRfpaJbGVBnH8bxbK1xkOWpUX2Atm6Cz1TlJ/RnzjvMZv27b5PsvQX57DrjJTIH+EAAAAASUVORK5CYII=", + "inverted": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAABCAIAAACe8u/0AAABC0lEQVQokWWSUW7lMAwDxaHTHngv3/cSi/thp013A4IY0YJjw9IfSuYhYbA9ttu28QCwt38DYOt3aVbDghUZjHcHGFn37zaI/5L7VGVki+c5V4hMgViu4rvUWiokiNQPzaoF5zzf1/u9/f2a12uer3l9zfM1r7Pn7Dm7b22+tuYNd0N6dl9ZnNndO8xa6uTuzPJenjy5U+lKqlNJdVdFKVWU3F5K+Ierh3pUo071uuR91ZYiheWE6kPXR82j2oorLm1FLo1sOaLk4DAip5xdUli4sAA9nkNIFJbXiwrtD0nwI68Z+zUdrBkBo2GGGdZ2GOZYOQzrgIEO66AGOpasw3XDTtYmh/VpPob+Aq7u3qtK6nECAAAAAElFTkSuQmCC", + }, } diff --git a/quickview/interface.py b/quickview/interface.py index 9f5ecc7..39e6635 100644 --- a/quickview/interface.py +++ b/quickview/interface.py @@ -47,19 +47,37 @@ "value": "Rainbow Desaturated", }, { - "text": "Cool to Warm", - "value": "Cool to Warm", + "text": "Yellow-Gray-Blue", + "value": "Yellow - Gray - Blue", }, { - "text": "Jet", - "value": "Jet", + "text": "Blue Orange (div.)", + "value": "Blue Orange (divergent)", }, { - "text": "Yellow-Gray-Blue", - "value": "Yellow - Gray - Blue", + "text": "Cool to Warm (Ext.)", + "value": "Cool to Warm (Extended)", + }, + { + "text": "Black-Body Rad.", + "value": "Black-Body Radiation", + }, + { + "text": "Blue-Green-Orange", + "value": "Blue - Green - Orange", + }, +] + +cvd = [ + { + "text": "Inferno (matplotlib)", + "value": "Inferno (matplotlib)", + }, + { + "text": "Viridis (matplotlib)", + "value": "Viridis (matplotlib)", }, ] -cvd = [] save_state_keys = [ # Data files @@ -376,6 +394,28 @@ def load_data(self): state.midpoints = [] state.interfaces = [] + def get_default_colormap(self): + """ + Determine the default colormap based on availability. + Returns 'Batlow' if CVD colormaps are available, + 'Cool to Warm (Extended)' for non-CVD, or falls back to first available. + """ + if cvd: # CVD colormaps are available + # Look for Batlow in current colormaps + for cmap in self.state.colormaps: + if cmap["value"].lower() == "batlow": + return cmap["value"] + else: # Only non-CVD colormaps available + # Look for Cool to Warm (Extended) + for cmap in self.state.colormaps: + if cmap["value"] == "Cool to Warm (Extended)": + return cmap["value"] + + # Fallback to first available colormap + return ( + self.state.colormaps[0]["value"] if self.state.colormaps else "Cool to Warm" + ) + def load_variables(self, use_cached_layout=False): surf = [] mid = [] @@ -405,7 +445,7 @@ def load_variables(self, use_cached_layout=False): # Tracking variables to control camera and color properties with self.state as state: state.variables = vars - state.varcolor = [state.colormaps[0]["value"]] * len(vars) + state.varcolor = [self.get_default_colormap()] * len(vars) state.uselogscale = [False] * len(vars) state.invert = [False] * len(vars) state.varmin = [np.nan] * len(vars) @@ -733,7 +773,7 @@ def ui(self) -> SinglePageWithDrawerLayout: ) # Top-left info: time and level info with html.Div( - style="position: absolute; top: 8px; left: 8px; padding: 4px 8px; background-color: rgba(0, 0, 0, 0.7); color: white; font-size: 0.875rem; border-radius: 4px; z-index: 2;", + style="position: absolute; top: 8px; left: 8px; padding: 4px 8px; background-color: rgba(255, 255, 255, 0.1); color: white; font-size: 0.875rem; border-radius: 4px; z-index: 2;", classes="drag-ignore font-monospace", ): # Show time @@ -758,7 +798,7 @@ def ui(self) -> SinglePageWithDrawerLayout: ) # Top-right info: variable name and average with html.Div( - style="position: absolute; top: 8px; right: 8px; padding: 4px 8px; background-color: rgba(0, 0, 0, 0.7); color: white; font-size: 0.875rem; border-radius: 4px; z-index: 2; text-align: right;", + style="position: absolute; top: 8px; right: 8px; padding: 4px 8px; background-color: rgba(255, 255, 255, 0.1); color: white; font-size: 0.875rem; border-radius: 4px; z-index: 2; text-align: right;", classes="drag-ignore font-monospace", ): # Variable name @@ -799,8 +839,8 @@ def ui(self) -> SinglePageWithDrawerLayout: "{{ " "varmin[idx] !== null && !isNaN(varmin[idx]) ? (" "uselogscale[idx] && varmin[idx] > 0 ? " - "'10^(' + Math.log10(varmin[idx]).toFixed(2) + ')' : " - "varmin[idx].toExponential(3)" + "'10^(' + Math.log10(varmin[idx]).toFixed(1) + ')' : " + "varmin[idx].toExponential(1)" ") : 'Auto' " "}}" ), @@ -857,8 +897,8 @@ def ui(self) -> SinglePageWithDrawerLayout: "{{ " "varmax[idx] !== null && !isNaN(varmax[idx]) ? (" "uselogscale[idx] && varmax[idx] > 0 ? " - "'10^(' + Math.log10(varmax[idx]).toFixed(2) + ')' : " - "varmax[idx].toExponential(3)" + "'10^(' + Math.log10(varmax[idx]).toFixed(1) + ')' : " + "varmax[idx].toExponential(1)" ") : 'Auto' " "}}" ), diff --git a/quickview/ui/toolbar.py b/quickview/ui/toolbar.py index 094d49c..5236675 100644 --- a/quickview/ui/toolbar.py +++ b/quickview/ui/toolbar.py @@ -116,6 +116,7 @@ def __init__( v2.VBtn( "Load Variables", classes="ma-2", + color="primary", dense=True, # flat=True, tonal=True, @@ -213,6 +214,7 @@ def __init__( ): v2.VIcon("mdi-file-check") html.Span("Load Files") + """ with v2.VTooltip(bottom=True): with html.Template(v_slot_activator="{ on, attrs }"): with v2.VBtn( @@ -226,6 +228,7 @@ def __init__( ): v2.VIcon("mdi-swap-horizontal") html.Span("Replace Files") + """ with v2.VTooltip(bottom=True): with html.Template(v_slot_activator="{ on, attrs }"): with v2.VBtn( diff --git a/quickview/ui/variable_selection.py b/quickview/ui/variable_selection.py index 371c710..5801adc 100644 --- a/quickview/ui/variable_selection.py +++ b/quickview/ui/variable_selection.py @@ -70,7 +70,6 @@ def __init__( with html.Template(v_slot_activator="{ on, attrs }"): with v2.VBtn( click=(on_clear), - color="primary", depressed=True, small=True, v_bind="attrs", diff --git a/scripts/README.md b/scripts/README.md index ffa92c7..85b3578 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,15 +1,12 @@ # QuickView Scripts -This directory contains utility scripts for maintaining and developing -QuickView. +This directory contains utility scripts for maintaining and developing QuickView. ## Scripts ### generate_colorbar_cache.py -Generates the colorbar image cache for all supported colormaps. This -pre-generates base64-encoded PNG images for both normal and inverted versions of -each colormap, improving runtime performance. +Generates the colorbar image cache for all supported colormaps. This pre-generates base64-encoded PNG images for both normal and inverted versions of each colormap, improving runtime performance. **Usage:** @@ -19,5 +16,47 @@ export EAMPVIEW=/path/to/paraview/bin/pvpython $EAMPVIEW scripts/generate_colorbar_cache.py > quickview/colorbar_cache.py ``` -This will update the `quickview/colorbar_cache.py` file with all colorbar -images. +This will update the `quickview/colorbar_cache.py` file with all colorbar images. + +### release.sh + +Automates the release process for QuickView, including version bumping, tagging, and creating GitHub releases with auto-generated changelogs from git history. + +**Usage:** + +```bash +# Create a patch release (0.1.0 -> 0.1.1) +./scripts/release.sh patch + +# Create a minor release (0.1.0 -> 0.2.0) +./scripts/release.sh minor + +# Create a major release (0.1.0 -> 1.0.0) +./scripts/release.sh major +``` + +The script will: +- Bump version using bumpversion +- Create a git tag +- Generate changelog from commits +- Push changes to remote +- Create a GitHub release + +### setup_tauri.sh + +Prepares the Tauri desktop application for building by packaging the Python application with PyInstaller. This creates platform-specific sidecar executables for the Tauri app. + +**Usage:** + +```bash +# Run from project root (called by CI/CD workflow) +./scripts/setup_tauri.sh +``` + +This script: +- Creates a PyInstaller spec file +- Builds the Python application bundle +- Copies the bundle to the Tauri sidecar directory +- Prepares for Tauri desktop app compilation + +**Note:** This is primarily used by the GitHub Actions workflow for automated releases. \ No newline at end of file diff --git a/scripts/generate_colorbar_cache.py b/scripts/generate_colorbar_cache.py index 66c8302..e8deca0 100755 --- a/scripts/generate_colorbar_cache.py +++ b/scripts/generate_colorbar_cache.py @@ -18,33 +18,49 @@ from paraview.simple import GetColorTransferFunction, ImportPresets, GetLookupTableNames from quickview.utilities import build_colorbar_image -# Define the colormaps to cache (matching interface.py) noncvd = [ { "text": "Rainbow Desat.", "value": "Rainbow Desaturated", }, { - "text": "Cool to Warm", - "value": "Cool to Warm", + "text": "Yellow-Gray-Blue", + "value": "Yellow - Gray - Blue", }, { - "text": "Jet", - "value": "Jet", + "text": "Blue Orange (div.)", + "value": "Blue Orange (divergent)", }, { - "text": "Yellow-Gray-Blue", - "value": "Yellow - Gray - Blue", + "text": "Cool to Warm (Ext.)", + "value": "Cool to Warm (Extended)", + }, + { + "text": "Black-Body Rad.", + "value": "Black-Body Radiation", + }, + { + "text": "Blue-Green-Orange", + "value": "Blue - Green - Orange", }, ] -# CVD-friendly colormaps will be loaded from XML files -cvd = [] +cvd = [ + { + "text": "Inferno (matplotlib)", + "value": "Inferno (matplotlib)", + }, + { + "text": "Viridis (matplotlib)", + "value": "Viridis (matplotlib)", + }, +] # Load CVD presets from XML files try: existing = GetLookupTableNames() - presdir = os.path.join(os.path.dirname(__file__), "quickview", "presets") + presdir = os.path.join(os.path.dirname(__file__), "../quickview", "presets") + print(presdir) presets = os.listdir(path=presdir) for preset in presets: prespath = os.path.abspath(os.path.join(presdir, preset)) @@ -59,6 +75,8 @@ # Combine all colormaps all_colormaps = cvd + noncvd +print(cvd) + print("# Auto-generated colorbar cache") print("# Generated using generate_colorbar_cache.py") print() diff --git a/release.sh b/scripts/release.sh similarity index 100% rename from release.sh rename to scripts/release.sh diff --git a/setup_tauri.sh b/scripts/setup_tauri.sh similarity index 100% rename from setup_tauri.sh rename to scripts/setup_tauri.sh diff --git a/setupenv b/setupenv deleted file mode 100755 index f750826..0000000 --- a/setupenv +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -export PATH=/home/local/KHQ/abhi.yenpure/repositories/eam/paraview-eam/install/bin:$PATH diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 3a94b68..39af069 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "app" -version = "0.1.10" +version = "0.1.11" description = "QuickView: Visual Analyis for E3SM Atmosphere Data" authors = ["Kitware"] license = "" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 74611ac..dc2e593 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -7,7 +7,7 @@ }, "package": { "productName": "QuickView", - "version": "0.1.10" + "version": "0.1.11" }, "tauri": { "allowlist": { @@ -51,7 +51,7 @@ }, "resources": ["server"], "shortDescription": "", - "targets": ["appimage", "nsis", "msi", "app", "dmg"], + "targets": ["dmg"], "windows": { "certificateThumbprint": null, "digestAlgorithm": "sha256", diff --git a/src-tauri/www/Kitware.png b/src-tauri/www/Kitware.png new file mode 100644 index 0000000..627ee72 Binary files /dev/null and b/src-tauri/www/Kitware.png differ diff --git a/src-tauri/www/PNNL.png b/src-tauri/www/PNNL.png new file mode 100644 index 0000000..25e93c8 Binary files /dev/null and b/src-tauri/www/PNNL.png differ diff --git a/src-tauri/www/splashscreen.html b/src-tauri/www/splashscreen.html index 829aaae..d0fd6d8 100644 --- a/src-tauri/www/splashscreen.html +++ b/src-tauri/www/splashscreen.html @@ -19,32 +19,58 @@ box-sizing: border-box; } - .splashscreen-image { - background-image: url("splashscreen.png"); - background-position: center; - background-repeat: no-repeat; - background-size: contain; + .logos-container { width: 90%; - max-width: 600px; + max-width: 700px; flex: 1 1 auto; min-height: 200px; + display: flex; + justify-content: center; + align-items: center; + gap: 60px; + } + + .logo { + background-position: center; + background-repeat: no-repeat; + background-size: contain; + height: 150px; + width: 250px; + } + + .logo-kitware { + background-image: url("Kitware.png"); + } + + .logo-pnnl { + background-image: url("PNNL.png"); } .loading-container { - width: 50%; - max-width: 400px; + width: 70%; + max-width: 500px; min-width: 250px; display: flex; flex-direction: column; align-items: center; - gap: 20px; + gap: 15px; margin-top: 40px; flex-shrink: 0; } + .caution-text { + color: rgba(255, 255, 255, 0.7); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + sans-serif; + font-size: 13px; + text-align: center; + margin-top: 5px; + } + .loading-text { color: #fff; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + sans-serif; font-size: 16px; letter-spacing: 1px; animation: pulse 1.5s ease-in-out infinite; @@ -83,7 +109,8 @@ } @keyframes pulse { - 0%, 100% { + 0%, + 100% { opacity: 1; } 50% { @@ -98,15 +125,23 @@ } .loading-dots::after { - content: ''; + content: ""; animation: dots 1.5s steps(4, end) infinite; } @keyframes dots { - 0% { content: ''; } - 25% { content: '.'; } - 50% { content: '..'; } - 75% { content: '...'; } + 0% { + content: ""; + } + 25% { + content: "."; + } + 50% { + content: ".."; + } + 75% { + content: "..."; + } } /* Responsive adjustments for small windows */ @@ -114,16 +149,21 @@ .splashscreen-container { padding: 20px 10px; } - - .splashscreen-image { + + .logos-container { min-height: 100px; } - + + .logo { + height: 100px; + width: 180px; + } + .loading-container { margin-top: 20px; gap: 10px; } - + .loading-text { font-size: 14px; } @@ -133,7 +173,10 @@
-
+
+ + +
Loading QuickView @@ -141,6 +184,9 @@
+
+ Note: First time launch may take a few minutes +
diff --git a/src-tauri/www/splashscreen.png b/src-tauri/www/splashscreen.png deleted file mode 100644 index 22dd447..0000000 Binary files a/src-tauri/www/splashscreen.png and /dev/null differ