diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index dc060b6..b5a944a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -37,6 +37,8 @@ jobs: - name: Render Quarto Project uses: quarto-dev/quarto-actions/render@v2 + env: + QUARTO_PROFILE: production - name: Upload static files as artifact uses: actions/upload-pages-artifact@v3 diff --git a/.gitignore b/.gitignore index f09646d..2f3464d 100644 --- a/.gitignore +++ b/.gitignore @@ -120,6 +120,7 @@ index.ipynb index.md index_files/ index.tex +/_*.local # Prevents committing locally rendered site docs diff --git a/README.md b/README.md index 8bc9169..95755e8 100644 --- a/README.md +++ b/README.md @@ -16,21 +16,20 @@ explained in the [GitHub guide](https://github.com/OSGeo/grass/blob/main/doc/development/github_guide.md) written for OSGeo/grass repository, so just adjust it for this repository. - ## License -The content in this repository is dual-licensed under the -[GNU Free Documentation License v1.2 or later](https://www.gnu.org/licenses/fdl-1.2.html) -(GFDL-1.2-or-later) and the -[Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/) +The content in this repository is dual-licensed under the +[GNU Free Documentation License v1.2 or later](https://www.gnu.org/licenses/fdl-1.2.html) +(GFDL-1.2-or-later) and the +[Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/) (CC-BY-SA-4.0). ## Acknowledgments -The initial content of this website was supported by funding from the +The initial content of this website was supported by funding from the U.S. National Science Foundation [award 2303651](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2303651). ## Contact -For questions or suggestions, feel free to open an issue or reach out to the +For questions or suggestions, feel free to open an issue or reach out to the maintainers through the [GRASS community channels](https://grass.osgeo.org/community/). diff --git a/_brand.yml b/_brand.yml new file mode 100644 index 0000000..420a079 --- /dev/null +++ b/_brand.yml @@ -0,0 +1,42 @@ +meta: + name: + full: GRASS + short: GRASS + link: + home: https://grass.osgeo.org + docs: https://grass.osgeo.org/grass-stable/manuals/ + description: | + Bringing advanced geospatial technologies to the world + founded: 1984 + +# https://posit-dev.github.io/brand-yml/brand/logo.html +# https://sc.edu/about/offices_and_divisions/digital-accessibility/toolbox/best_practices/alternative_text/logo-alt-text/index.php +logo: + images: + logo-small-no-text-light: + path: ../../images/logos/small/grass-logo-white-simple@05x.png + alt: "Small sized GRASS icon colored white with GRASS shape" + logo-small-no-text-dark: + path: ../../images/logos/small/grass-logo-green-simple@05x.png + alt: "Small sized GRASS icon colored GRASS green with GRASS shape" + logo-medium-no-text-light: + path: ../../images/logos/medium/grass-logo-white-simple@1x.png + alt: "Medium sized GRASS icon colored white with GRASS shape" + logo-medium-no-text-dark: + path: ../../images/logos/medium/grass-logo-green-simple@1x.png + alt: "Medium sized GRASS icon colored GRASS green with GRASS shape" + logo-large-no-text-light: + path: ../../images/logos/large/grass-white-no-text.svg + alt: "Large vector (svg) GRASS icon colored white with GRASS shape" + logo-large-no-text-dark: + path: ../../images/logos/large/grass-green-no-text.svg + alt: "Large vector (svg) GRASS icon colored GRASS green with GRASS shape" + small: + light: logo-small-no-text-light + dark: logo-small-no-text-dark + medium: + light: logo-medium-no-text-light + dark: logo-medium-no-text-dark + large: + light: logo-large-no-text-light + dark: logo-large-no-text-dark diff --git a/_freeze/content/tests/styling/execute-results/html.json b/_freeze/content/tests/styling/execute-results/html.json new file mode 100644 index 0000000..4cd2ee8 --- /dev/null +++ b/_freeze/content/tests/styling/execute-results/html.json @@ -0,0 +1,12 @@ +{ + "hash": "924be59cc65ec1d83de0079693abb610", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: GRASS Quarto Design Guide\ndescription: Adopted from Quarto Documentatoin\nauthor:\n - name: Corey White\n - name: Sarah White\ndate: May 5, 2025\ndate-modified: today\nformat: \n html:\n other-links:\n - text: GRASS Website\n href: \"{{< var grass.website >}}\"\n code-links:\n - text: Data Import Code\n icon: file-code\n href: data-import.py\n notebook-links: inline\n code-tools: true\n code-copy: true\n code-fold: true\n code-summary: \"Show the code\"\nprofile: local\ntoc: true\ntoc-depth: 3\nlisting: \n - id: lab-reports\n contents: \"*.qmd\"\n type: table\n - id: meeting-notes\n contents: \"*.qmd\"\n type: grid\n - id: default-notes\n contents: \"*.qmd\"\n type: default\ncitation:\n type: article-journal\n container-title: ACM Transactions on Embedded Computing Systems\n volume: 21\n issue: 2\n issued: 2022-03\n issn: 1539-9087\n doi: 10.1145/3514174\nexecute:\n eval: false\n echo: true\n output: false\n\n\n---\n\n# Components Showcase\n\nThis document demonstrates various components available in Quarto.\n\n## Headings\n\n# Heading 1\n## Heading 2\n### Heading 3\n#### Heading 4\n##### Heading 5\n###### Heading 6\n\n## Text Formatting\n\n**Bold Text** \n*Italic Text* \n~~Strikethrough~~ \n`Inline Code`\n\nsuperscript^2^ / subscript~2~\n\n## Lists\n\n### Ordered List\n1. First item\n2. Second item\n3. Third item\n\n### Unordered List\n- Item 1\n- Item 2\n- Item 3\n\n* unordered list\n + sub-item 1\n + sub-item 2\n - sub-sub-item 1\n\n* item 2\n\n Continued (indent 4 spaces)\n\n(@) A list whose numbering\n\ncontinues after\n\n(@) an interruption\n\n### Tasks\n\n- [ ] Task 1\n- [x] Task 2\n\n## Blockquotes\n\n### `>` Blockquote\n\n> This is a blockquote. \n> It can span multiple lines.\n\n### Line Block\n\n| Line Block\n| Spaces and newlines\n| are preserved\n\n## Footnotes\n\nHere is a footnote reference,[^1] and another.[^longnote]\n\n[^1]: Here is the footnote.\n\n[^longnote]: Here's one with multiple blocks.\n\n Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.\n\n { some.code }\n\n The whole paragraph can be indented, or just the first\n line. In this way, multi-paragraph footnotes work like\n multi-paragraph list items.\n\nThis paragraph won't be part of the note, because it\nisn't indented.\n\nHere is an inline note.^[Inlines notes are easier to write,\nsince you don't have to pick an identifier and move down to\ntype the note.]\n\n## Tables\n\n### Default\n\n| Header 1 | Header 2 | Header 3 |\n|----------|----------|----------|\n| Row 1 | Data 1 | Data 2 |\n| Row 2 | Data 3 | Data 4 |\n\n```md\n| Header 1 | Header 2 | Header 3 |\n|----------|----------|----------|\n| Row 1 | Data 1 | Data 2 |\n| Row 2 | Data 3 | Data 4 |\n```\n\n### Column Aligned\n\n| Default | Left | Right | Center |\n|---------|:-----|------:|:------:|\n| 12 | 12 | 12 | 12 |\n| 123 | 123 | 123 | 123 |\n| 1 | 1 | 1 | 1 |\n\n```{md}\n| Default | Left | Right | Center |\n|---------|:-----|------:|:------:|\n| 12 | 12 | 12 | 12 |\n| 123 | 123 | 123 | 123 |\n| 1 | 1 | 1 | 1 |\n```\n\n### Pipe Format\n\nfruit| price\n-----|-----:\napple|2.05\npear|1.37\norange|3.09\n\n: Demonstration of pipe table syntax\n\n### Pipe Format Striped\n\n| fruit | price |\n|--------|--------|\n| apple | 2.05 |\n| pear | 1.37 |\n| orange | 3.09 |\n\n: Fruit prices {.striped .hover}\n\n### Pipe Format Custom Col widths\n\n| fruit | price |\n|--------|--------|\n| apple | 2.05 |\n| pear | 1.37 |\n| orange | 3.09 |\n\n: Fruit prices {tbl-colwidths=\"[75,25]\"}\n\n### Grid Table\n\n+-----------+-----------+--------------------+\n| Fruit | Price | Advantages |\n+===========+===========+====================+\n| Bananas | $1.34 | - built-in wrapper |\n| | | - bright color |\n+-----------+-----------+--------------------+\n| Oranges | $2.10 | - cures scurvy |\n| | | - tasty |\n+-----------+-----------+--------------------+\n\n: Sample grid table.\n\n## Cross Reference\n\n| Col1 | Col2 | Col3 |\n|------|------|------|\n| A | B | C |\n| E | F | G |\n| A | G | G |\n\n: My Caption {#tbl-letters}\n\nSee @tbl-letters.\n\n### Subtables\n\n::: {#tbl-panel layout-ncol=2}\n| Col1 | Col2 | Col3 |\n|------|------|------|\n| A | B | C |\n| E | F | G |\n| A | G | G |\n\n: First Table {#tbl-first}\n\n| Col1 | Col2 | Col3 |\n|------|------|------|\n| A | B | C |\n| E | F | G |\n| A | G | G |\n\n: Second Table {#tbl-second}\n\nMain Caption\n:::\n\nSee @tbl-panel for details, especially @tbl-second.\n\n## Links & Images\n\n[GRASS Website]({{< var grass.website >}})\n\n{{< var grass.website >}}\n\n## Images\n\n![Width 25%]({{< var grass.logos.horizontal.gradient >}}){width=25%}\n\n![Width 50%]({{< var grass.logos.horizontal.gradient >}}){width=50%}\n\n![Width 75%]({{< var grass.logos.horizontal.gradient >}}){width=75%}\n\n![Width 100%]({{< var grass.logos.horizontal.gradient >}}){width=100%}\n\n### Image Link\n\n[![Caption]({{< var grass.logos.gradient >}}){width=20%}]({{< var grass.website >}})\n\n[![Caption]({{< var grass.logos.gradient >}} \"Alt text\"){width=20%}]({{< var grass.website >}})\n\n### Aligned Images\n\n![Aligned Left]({{< var grass.logos.gradient >}} \"Alt text\"){width=20% fig-align=\"left\"}\n![Aligned Right]({{< var grass.logos.gradient >}} \"Alt text\"){width=20% fig-align=\"right\"}\n\n### Lightbox\n![Lightbox]({{< var grass.logos.gradient >}} \"Alt text\"){width=20% fig-align=\"center\" .lightbox}\n\n### Placeholders\n\n{{< placeholder 400 200 format=svg >}}\n\n## Brand\n\nUsing `{{< brand logo small light >}}` from the `_brand.yml` file.\n\n### Logo small light\n{{< brand logo small light >}}\n\n\n\n## Callouts\n\nNote that there are five types of callouts, including: \n`note`, `tip`, `warning`, `caution`, and `important`.\n\n\n### Note\n\n::: {.callout-note}\nThis is a note callout.\n:::\n\n### Warning\n\n::: {.callout-warning}\nThis is a warning callout.\n:::\n\n### Tip\n\n::: {.callout-tip}\nThis is a warning callout.\n:::\n\n### Important\n\n::: {.callout-important}\nThis is a warning callout.\n:::\n\n### Caution\n\n::: {.callout-caution collapse=\"true\"}\n## Expand To Learn About Collapse\nThis is a caution callout.\n:::\n\n## Math\n\n### Inline\nInline math: $E = mc^2$\n\n### Block\n\nBlock math: \n$$\n\\int_a^b f(x) dx = F(b) - F(a)\n$$\n\n### TeX Macro\n::: {.hidden}\n$$\n \\def\\RR{{\\bf R}}\n \\def\\bold#1{{\\bf #1}}\n$$\n:::\n\n## Buttons\n\n[Primary](#){.btn .btn-primary .btn role=\"button\"}\n[Secondary](#){.btn .btn-secondary .btn role=\"button\"}\n[Donate](#){.btn .btn-primary .gs-support-button .btn role=\"button\"}\n\n[Primary Outline](#){.btn .btn-outline-primary .btn role=\"button\"}\n[Secondary Outline](#){.btn .btn-outline-primary .btn role=\"button\"}\n\n## Alerts\n\n::: {.alert .alert-success}\nThis is a success alert.\n:::\n\n::: {.alert .alert-danger}\nThis is a danger alert.\n:::\n\n## Code Blocks with Syntax Highlighting\n\n### Default\n\n```default\ncode\n```\n\n### Python\n```python\n# Comment\nimport sys\nimport subprocess\n\nsys.path.append(\n subprocess.check_output([\"grass\", \"--config\", \"python_path\"], text=True).strip()\n)\n\nimport grass.script as gs\nimport grass.jupyter as gj\n```\n\n### Terminal\n```bash\ngrass \"~/grassdata/\" --exec script.py \n```\n\n### R\n```r\nlibrary(rgrass)\n\nsession <- initGRASS(gisBase = \"/usr/lib/grass84\", # where grass binaries live, `grass --config path`\n gisDbase = \"/home/user/grassdata\", # path to grass database or folder where your project lives\n location = \"nc_basic_spm_grass7\", # existing project name\n mapset = \"PERMANENT\" # mapset name\n )\n\n```\n\n### Raw Content\n\n```{=html}\n\n```\n\n## Diagrams\n\n### Flowchart\n```{mermaid}\nflowchart LR\n A[Hard edge] --> B(Round edge)\n B --> C{Decision}\n C --> D[Result one]\n C --> E[Result two]\n```\n\n### Sequence Diagram\n```{mermaid}\nsequenceDiagram\n participant Alice\n participant Bob\n Alice->>John: Hello John, how are you?\n loop Healthcheck\n John->>John: Fight against hypochondria\n end\n Note right of John: Rational thoughts
prevail!\n John-->>Alice: Great!\n John->>Bob: How about you?\n Bob-->>John: Jolly good!\n```\n\n### Dot\n\n```{dot}\ngraph G {\n layout=neato\n run -- intr;\n intr -- runbl;\n runbl -- run;\n run -- kernel;\n kernel -- zombie;\n kernel -- sleep;\n kernel -- runmem;\n sleep -- swap;\n swap -- runswap;\n runswap -- new;\n runswap -- runmem;\n new -- runmem;\n sleep -- runmem;\n}\n```\n\n## Videos\n\n{{< video https://www.youtube.com/embed/zboP3Z7VBuU >}}\n\n## Page Break\n\npage 1\n\n{{< pagebreak >}}\n\npage 2\n\n## Divs & Spans\n\n### Boarder\n\n::: {.border}\nThis content can be styled with a border\n:::\n\n### Sidebar\n\n::::: {#special .sidebar}\n\n::: {.warning}\nHere is a warning.\n:::\n\nMore content.\n:::::\n\n### Spans\n\n[This is *some text*]{.class key=\"val\"}\n\n\nThis is a custom span.\n\n## Listing\n\n### Table\n\n:::{#lab-reports}\n:::\n\n### Grid\n\n:::{#meeting-notes}\n:::\n\n### Default\n:::{#default-notes}\n:::\n\n## Layout\n\n### Column Full screen inset\n::: {.column-screen-inset}\n![A full screen image](images/LinkedIn-Post-Image.png)\n:::\n\n### Column Full screen shaded inset\n::: {.column-shaded-screen-inset}\n![A full screen image](images/LinkedIn-Post-Image.png)\n:::\n\n### Column Margin\n::: {.column-margin}\n![A image in the margin](images/LinkedIn-Post-Image.png)\n:::\n\n## Lipsum\n\n### Single Paragraph\n{{< lipsum 1 >}}\n\n### Multi Paragraph\n{{< lipsum 2 random=true >}}\n\n", + "supporting": [ + "styling_files" + ], + "filters": [], + "includes": {} + } +} \ No newline at end of file diff --git a/_freeze/content/tutorials/get_started/JupyterOnWindows_OSGeo4W_Tutorial/execute-results/html.json b/_freeze/content/tutorials/get_started/JupyterOnWindows_OSGeo4W_Tutorial/execute-results/html.json new file mode 100644 index 0000000..6f14618 --- /dev/null +++ b/_freeze/content/tutorials/get_started/JupyterOnWindows_OSGeo4W_Tutorial/execute-results/html.json @@ -0,0 +1,12 @@ +{ + "hash": "7c6836e62a1583bd1a107417cd6a1726", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: \"Get started with GRASS in Jupyter Notebooks on Windows\"\nauthor: \"Caitlin Haedrich\"\ndate: 2024-06-15\nimage: images/getting_started_grass_jupyternotebook.png\ndate-modified: today\nformat:\n html:\n toc: true\n code-tools: true\n code-copy: true\n code-fold: false\ncategories: [Python, Windows, beginner]\ndescription: Learn how to run GRASS in Jupyter Notebooks on Windows.\nengine: jupyter\nexecute:\n eval: false\njupyter: python3\n---\n\n\nThe development of the Python package `grass.jupyter`, has streamlined the use \nof GRASS is Jupyter notebooks. In this tutorial we will demonstrate the \nrecommended way of running GRASS in Jupyter Notebooks for Windows users.\n\n## Set Up\n\nOn Windows, we'll use the OSGeo4W package manager to setup and update GRASS,\nJupyterlab and other dependencies. Follow the directions below to setup Jupyter \nand GRASS in Windows.\n\n#### 1. Download the OSGeo4W Network Installer\n\nDownload the OSGeo4W network install from [here](https://trac.osgeo.org/osgeo4w/). \nOpen it and select _\"Advanced Install\"_.\n\n#### 2. Install GRASS, Jupyterlab and `grass.jupyter` dependencies\n\nFollow the prompts until you get to the _\"Select Packages\"_ window (the defaults\nare fine for most situations). Use the Search bar to find and select the \nfollowing packages for install (switching from \"Skip\" to the version number):\n\n* `grass`\n* `python3-jupyterlab`\n* `python3-ipywidgets`\n\n![Install GRASS with OSGeo4W installer](images/osgeo4w_install_grass.png){width=60%}\n\n#### 3. Go make a cup of tea\n\nIt may take a minute to install... Click \"Finish\" and exit when it finishes.\n\n#### 4. Open the OSGeo4W Shell and install folium\n\nLaunch the OSGeo4W Shell and install folium with:\n\n`pip install folium`\n\n#### 5. Launch Jupyter Lab\n\nWe're ready to launch jupyterlab now: \n\n`jupyter lab`\n\n\nThis should launch Jupyter lab in your default web browser. Use the left side\npanel to navigate to the notebook you wish to run and you're ready to go!\n\n#### 6. Launching Jupyter Lab in the Future\n\nTo launch Jupyter Lab in the future:\n\n1. Open the OSGeo4W Shell\n2. Launch jupyter lab with `jupyter lab`\n\n\n## Start GRASS within Jupyter\n\nNow, we're ready to code! Let's import the GRASS Python packages and launch\nGRASS. If you want to run this tutorial, please download and unzip the \nNorth Carolina [sample dataset](https://grass.osgeo.org/sampledata/north_carolina/nc_spm_08_grass7.zip).\n\n::: {#b243f45c .cell execution_count=1}\n``` {.python .cell-code}\n# Import standard python packages\nimport sys\nimport subprocess\n\n# Ask GRASS where its Python packages are and add them to the path\ngrass_call = \"grass83\"\nsys.path.append(\n subprocess.check_output([grass_call, \"--config\", \"python_path\"], text=True, shell=True).strip()\n)\n\n# Import the GRASS python packages we need\nimport grass.script as gs\nimport grass.jupyter as gj\n\n# Launch a GRASS session.\ngj.init(\"path/to/nc_spm_08_grass/user1\");\n```\n:::\n\n\n## Using GRASS\n\nNow that we have GRASS running in our notebook, let's try some basic \ncommands. \n\nIn this section, we will set the color table to the `elevation` raster map from\nthe GRASS sample project we downloaded and then display it. \n\n::: {#b23efd61 .cell execution_count=2}\n``` {.python .cell-code}\n# Set the computational region to the study area\ngs.parse_command(\"g.region\", \n raster=\"elevation\", \n flags='pg')\n\n# Set colors for elevation raster\ngs.run_command(\"r.colors\", \n map=\"elevation\", \n color=\"elevation\")\n```\n:::\n\n\n::: {#0d9685ac .cell execution_count=3}\n``` {.python .cell-code}\n# Create Map instance\nimg = gj.Map()\n# Add a raster\nimg.d_rast(map=\"elevation\")\n# Add legend\nimg.d_legend(raster=\"elevation\", at=(55, 95, 80, 84), flags=\"b\")\n# Display map\nimg.show()\n```\n:::\n\n\nNow, we're up and running! Have a look at other tutorials for inspiration on \nthe avenues you can follow with GRASS tools combined with other Python packages. \n\n## Troubleshooting\n\nSomething not working? Here are some common stumbling blocks...\n\n* `FileNotFoundError`\n\n::: {#57d8a58f .cell execution_count=4}\n``` {.python .cell-code}\nFileNotFoundError: [WinError 2] The system cannot find the file specified\n```\n:::\n\n\nCheck the `shell` parameter in the `subprocess.check_output()`. On Windows, \nthis should be `shell=True`. On Mac and Linux operating systems, this should \nbe `shell=False`.\n\n* `CalledProcessError`\n\n::: {#812330be .cell execution_count=5}\n``` {.python .cell-code}\nCalledProcessError: Command '['grass83', '--config', 'python_path']' returned non-zero exit status 1.\n```\n:::\n\n\nCheck which version of GRASS you have installed. On Windows, the `grass_call`\nshould be `grass` followed by the first two digits of the version you have \ninstalled (for example, GRASS 8.4 would be called with `grass84`). On Mac and \nLinux, it should be just `grass`.\n\n* Errors from `gj.init()`\n\nThis command takes several different configurations of the GRASS project \nand mapset location on your system. All the following are examples that work:\n\n```\ngj.init(\"path/to/grassdata\", \"project_name\", \"mapset_name\")\ngj.init(\"path/to/project_name/mapset_name\")\ngj.init(\"../project_name/mapset_name\")\n```\n\nAlso pay attention to the slash direction. Windows uses `\\` in it's file \npaths but the `\\` character in strings is also for escaping characters (for\nexample, putting `\\n` in a string will print a new line). Therefore, you'll \nneed to either switch to forward slashes (`/`) or put double back-slashes \n(`\\\\`).\n\n", + "supporting": [ + "JupyterOnWindows_OSGeo4W_Tutorial_files" + ], + "filters": [], + "includes": {} + } +} \ No newline at end of file diff --git a/_freeze/content/tutorials/get_started/fast_track_grass_and_R/execute-results/html.json b/_freeze/content/tutorials/get_started/fast_track_grass_and_R/execute-results/html.json new file mode 100644 index 0000000..06c474e --- /dev/null +++ b/_freeze/content/tutorials/get_started/fast_track_grass_and_R/execute-results/html.json @@ -0,0 +1,17 @@ +{ + "hash": "78c634237345a8560278e569f3db8595", + "result": { + "engine": "knitr", + "markdown": "---\ntitle: \"Get started with GRASS & R: the rgrass package\"\nauthor: \"Veronica Andreo\"\ndate: 2024-03-29\ndate-modified: today\nformat:\n ipynb: default\n html:\n toc: true\n code-tools: true\n code-copy: true\n code-fold: false\ncategories: [R, rgrass, intermediate]\ndescription: Learn how to use GRASS and R to analyze geospatial data.\nengine: knitr\nexecute: \n eval: false\n---\n\nThe [**rgrass**](https://cran.r-project.org/web/packages/rgrass/index.html) \npackage allows us to interact with GRASS tools (and data) serving as an\ninterface between GRASS and R.\nThe *rgrass* package source code can be\nfound at: . In this fast track tutorial,\nwe will learn how to use GRASS from R.\n\n::: {.callout-note title=\"Setup\"}\nTo run this tutorial locally you should have GRASS 8.4+, \n[R](https://www.r-project.org/) and, optionally, \n[RStudio](https://posit.co/download/rstudio-desktop/) installed. \nYou will also need to install *rgrass*, *terra* and *mapview*\nR packages and download the \n[North Carolina sample dataset](https://grass.osgeo.org/sampledata/north_carolina/nc_basic_spm_grass7.zip).\n:::\n\n## *rgrass* main functions\n\nThe main functions within **rgrass** are the following:\n\n- `initGRASS()`: starts a GRASS session from R.\n- `execGRASS()`: executes GRASS commands from R.\n- `gmeta()`: prints GRASS session metadata like database, project, mapset, computational region settings and CRS.\n- `read_VECT()` and `read_RAST()`: read vector and raster maps from a GRASS project into R.\n- `write_VECT()` and `write_RAST()`: write vector and raster objects from R into a GRASS project.\n\n:::{.callout-note}\nFor further details on *rgrass* functionality, usage examples and data format \ncoercion, see: .\n:::\n\n## Basic usage: Choose your own adventure\n\nIf you are a regular R user that needs to use GRASS functionality \n**because, well, you know it rocks**, rgrass has your back. For example,\nmaybe you struggle with large raster datasets in R or you need some specific \ntool, like watershed delineation for a large high resolution DEM. We will show \nhere the way to use GRASS tools within your R workflows. \n\nOn the other hand, if you already use GRASS as your geospatial data processing \nengine, you most likely have your spatial data within GRASS projects. \nYou might need however to do some statistical analysis, some modelling and \nprediction or create publication ready visualizations in R. In such cases, \nyou can start a GRASS session in your project from R or RStudio.\n\nLet's see the general **basic steps** and then dive into the details:\n\n1. Make sure GRASS is installed.\n2. Open R (or RStudio)\n3. Load `rgrass` library with `library(rgrass)`\n4. Start a GRASS session with `initGRASS()`\n5. Use GRASS tools through `execGRASS()`\n6. Use `read_VECT()`, `read_RAST()`, `write_VECT()` and `write_RAST()` to read data from and write data into GRASS database.\n\n:::{.callout-note}\nGRASS raster and vector maps are translated into *terra*'s package SpatRaster \nand SpatVector objects, respectively. These objects can then, within R, be \neasily coerced to other types of spatial objects such as simple features (sf), \nstars, etc.\n\nSee *terra* vignettes with further explanations and examples: \n.\n:::\n\n### A. Use GRASS tools within your R spatial workflows\n\nWe start R or Rstudio and load the `rgrass` library. It will tell us that GRASS \nis not running, but we know that already... and that's about to change in a \nmoment.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(rgrass)\n```\n:::\n\n\nIn case you need to include some of the cool GRASS tools within your\nR workflow, the `initGRASS()` function allows you to create temporary GRASS \nprojects to use GRASS tools on R objects. \nThis is equivalent to what QGIS does when you use GRASS tools via the \nQGIS Processing Toolbox.\n\nFirst, we will use `initGRASS()` to create a temporary \nGRASS project based on the extent, resolution and CRS of a raster or vector R object, \nlikely the one we want to process or one that has the extent of our study area. \nHence, we need to pass a reference spatial grid via the *SG* parameter. \nThen, we will write our R objects into the temporary GRASS project, run the desired \nprocesses, and export the outputs back to the R environment.\n\nLet's start with getting some spatial data, e.g., a raster file, into R.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(terra)\nf <- system.file(\"ex/elev.tif\", package=\"terra\")\nr <- rast(f)\nplot(r)\n```\n:::\n\n\nNow, we will start GRASS in a temporary folder. By specifying `SG = r`,\nthe GRASS project is internally created with raster `r`'s object CRS (BTW,\nyou can check that with `crs(r)`), extent and resolution.\nThese latter define the GRASS computational region that will affect all raster\nprocessing, i.e., all new raster maps generated within GRASS will have the\nsame extent and resolution of the map provided. \nIf you wish to change the computational region later on, you can use the \n`g.region` GRASS tool with `execGRASS(\"g.region --h\")`.\n\nOptionally, we can specify which GRASS binary to use with `gisBase`. This might\nbe useful in case we have several GRASS versions on our system. If not provided,\n`initGRASS()` will attempt to find it in default locations depending on your\noperating system.\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Start GRASS from R\ninitGRASS(home = tempdir(),\n SG = r, \n override = TRUE)\n```\n:::\n\n\nNow, we can write our SpatRaster into the GRASS temporary project.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nwrite_RAST(r, \"terra_elev\")\n```\n:::\n\n\nAlternatively, we can use GRASS importing tools to import common raster and\nvector formats. Data will be reprojected if needed.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"r.import\", input=f, output=\"test\")\n```\n:::\n\n\nLet's check both raster maps (`test` and `terra_elev`) are indeed within\nthe project and run the GRASS tool \n[`r.slope.aspect`](https://grass.osgeo.org/grass-stable/manuals/r.slope.aspect.html)\non one of them.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"g.list\", type = \"raster\")\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"r.slope.aspect\", \n elevation = \"terra_elev\", \n slope = \"slope\",\n aspect = \"aspect\")\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"g.list\", type = \"raster\")\n```\n:::\n\n\nLet's get slope and aspect maps into R\n\n\n::: {.cell}\n\n```{.r .cell-code}\ngrass_maps <- read_RAST(c(\"aspect\", \"slope\"))\ngrass_maps\n```\n:::\n\n\nNow that the output maps are back into our R environment, we can plot them, do\nfurther analysis or write them into other raster formats, in which case we use\n`terra::writeRaster()` function.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nplot(grass_maps)\n```\n:::\n\n\n![](images/R_aspect_slope.png){.preview-image width=60%}\n\n\n::: {.cell}\n\n```{.r .cell-code}\nwriteRaster(grass_maps, \"grass_maps.tif\", overwrite=TRUE)\n```\n:::\n\n\nAlternatively, we can use GRASS exporting tools like \n[r.out.gdal](https://grass.osgeo.org/grass-stable/manuals/r.out.gdal.html) \nand [v.out.ogr](https://grass.osgeo.org/grass-stable/manuals/v.out.ogr.html), \nto directly save our outputs into common raster or vector formats, respectively.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"r.out.gdal\", input=\"slope\", output=\"slope.tif\", format=\"GTiff\", flags=\"overwrite\")\n```\n:::\n\n\n\n### B. Use R tools within GRASS workflows\n\nLet's see an example for the case when we do our geospatial data processing \nwithin GRASS and hence have all the spatial data organized within GRASS projects\nbut we need to run some statistical analysis, modelling, prediction \nor visualization in R.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(rgrass)\n```\n:::\n\n\nWe start GRASS from within R or RStudio using the `initGRASS()` function. \nSince we want to start GRASS in a specific project and mapset, we need to\nspecify them.\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Start GRASS from R\ninitGRASS(gisDbase = path.expand(\"~/grassdata/\"),\n location = \"nc_basic_spm_grass7\",\n mapset = \"PERMANENT\",\n override = TRUE,\n remove_GISRC = TRUE)\n```\n:::\n\n\nWe can now list and read our GRASS raster and vector maps into R and do our \nstatistical analysis, modelling and/or visualizations using other R packages. \nHere, we will demonstrate the use of all the main *rgrass* functions \nmentioned above.\n\nLet's then list our GRASS raster and vector maps:\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# List GRASS raster maps\nexecGRASS(\"g.list\", type=\"raster\")\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# List GRASS vector maps\nexecGRASS(\"g.list\", type=\"vector\")\n```\n:::\n\n\nThe resulting map lists could be saved in an R object that we can subset later \nin case we want to import several but not all raster maps, for example. Let's \nsee how to do that.\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Save map list in an object\nrast_list <- execGRASS(\"g.list\", type=\"raster\")\n\n# Retrieve only the map list from standard output\nrast_list <- attributes(rast_list)$resOut\n\n# Import elevation and landuse\nto_import <- c(\"elevation\", \"landuse\") # optionally, by position: rast_list[c(3,7)]\n\nmaplist <- list()\nfor (i in to_import) {\n maplist[[i]] <- read_RAST(i)\n}\n\nmaplist\n```\n:::\n\n\nRemember that raster objects will always be exported from GRASS following the \n*computational region settings*. So, bear that in mind when reading into R which \nwill hold them in memory. Vectors however will be exported in their full extent.\n\nLet's load the *terra* library to quickly display our recently imported raster \nmaps:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(terra)\nplot(maplist$elevation)\n```\n:::\n\n\nOptionally, we could stack our two `SpatRaster` objects together and plot them \ntogether:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nrstack <- rast(maplist)\nplot(rstack)\n```\n:::\n\n\nLet's create a boxplot of elevation per land class.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nboxplot(rstack$elevation, rstack$landuse, maxcell=50000)\n```\n:::\n\n\nLet's import a vector map, too, and explore its attributes.\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncensus <- read_VECT(\"census\")\nhead(census)\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nsummary(census$TOTAL_POP)\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nplot(census, \"P25_TO_34\", type=\"interval\", breaks=5, plg=list(x=\"topright\"))\n```\n:::\n\n\nLet's do some interactive visualization with `mapview`.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(mapview)\nmapview(rstack$elevation) + census\n```\n:::\n\n\nWe highly recommend you to check the [tmap](https://r-tmap.github.io/tmap/) \npackage to make really appealing and publication ready maps.\n\nTo exemplify the use of `write_*` functions, let's do a simple operation with \nthe *landuse* raster map. We will apply a custom function that makes NULL all \nvalues less than 4.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nresult <- app(rstack$landuse, fun=function(x){ x[x < 4] <- NA; return(x)} )\nplot(result)\n```\n:::\n\n\nTo use this new raster in GRASS, for example as an input to a GRASS tool, we need to call `write_RAST` function:\n\n::: {.cell}\n\n```{.r .cell-code}\nwrite_RAST(result, \"result_from_R\", overwrite = TRUE)\n```\n:::\n\n\nThe new raster is now written as a GRASS raster and can be listed:\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"g.list\", parameters = list(type=\"raster\", pattern=\"result*\"))\n```\n:::\n\n\n\nFinally, there is yet another way in which you can use GRASS and R together, and it \ninvolves calling R from the GRASS terminal. In this way, *rgrass* will read all \nGRASS session environmental variables, and you won't need to use \n`initGRASS()`. It goes more or less like this:\n\n1. Open GRASS\n2. Type `R` or `rstudio &` in the GRASS terminal\n3. Load `rgrass` library with `library(rgrass)`\n4. Use `read_VECT()`, `read_RAST()` to read data from GRASS into R\n5. Do your analysis or plotting in R\n6. Write data (back) to GRASS database with `write_VECT()` and `write_RAST()`\n7. Quit R `quit()` and get back to GRASS terminal.\n\n``` \nStarting GRASS GIS...\n\n __________ ___ __________ _______________\n / ____/ __ \\/ | / ___/ ___/ / ____/ _/ ___/\n / / __/ /_/ / /| | \\__ \\\\_ \\ / / __ / / \\__ \\\n / /_/ / _, _/ ___ |___/ /__/ / / /_/ // / ___/ /\n \\____/_/ |_/_/ |_/____/____/ \\____/___//____/\n\nWelcome to GRASS GIS 8.4.0\nGRASS GIS homepage: https://grass.osgeo.org\nThis version running through: Bash Shell (/bin/bash)\nHelp is available with the command: g.manual -i\nSee the licence terms with: g.version -c\nSee citation options with: g.version -x\nIf required, restart the GUI with: g.gui wxpython\nWhen ready to quit enter: exit\n\nLaunching GUI in the background, please wait...\n[Raster MASK present]\nGRASS nc_basic_spm_grass7/PERMANENT:~ > R\n\nR version 4.3.1 (2023-06-16) -- \"Beagle Scouts\"\nCopyright (C) 2023 The R Foundation for Statistical Computing\nPlatform: x86_64-pc-linux-gnu (64-bit)\n\nR is free software and comes with ABSOLUTELY NO WARRANTY.\nYou are welcome to redistribute it under certain conditions.\nType 'license()' or 'licence()' for distribution details.\n\n Natural language support but running in an English locale\n\nR is a collaborative project with many contributors.\nType 'contributors()' for more information and\n'citation()' on how to cite R or R packages in publications.\n\nType 'demo()' for some demos, 'help()' for on-line help, or\n'help.start()' for an HTML browser interface to help.\nType 'q()' to quit R.\n\n> library(rgrass)\nGRASS GIS interface loaded with GRASS version: GRASS 8.4.0 (2024)\nand location: nc_basic_spm_grass7\n> \n```\n\n**Enjoy!** {{< fa rocket >}}\n\n\n## References\n\n- Bivand R (2024).\n_rgrass: Interface Between 'GRASS' Geographical Information System and 'R'_. \nR package version 0.4-1, .\n\n\n***\n\n:::{.smaller}\nThe development of this tutorial was funded by the US \n[National Science Foundation (NSF)](https://www.nsf.gov/), \naward [2303651](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2303651).\n:::\n", + "supporting": [ + "fast_track_grass_and_R_files" + ], + "filters": [ + "rmarkdown/pagebreak.lua" + ], + "includes": {}, + "engineDependencies": {}, + "preserve": {}, + "postProcess": true + } +} \ No newline at end of file diff --git a/_freeze/content/tutorials/get_started/fast_track_grass_and_R/execute-results/ipynb.json b/_freeze/content/tutorials/get_started/fast_track_grass_and_R/execute-results/ipynb.json new file mode 100644 index 0000000..e1b369b --- /dev/null +++ b/_freeze/content/tutorials/get_started/fast_track_grass_and_R/execute-results/ipynb.json @@ -0,0 +1,15 @@ +{ + "hash": "78c634237345a8560278e569f3db8595", + "result": { + "engine": "knitr", + "markdown": "---\ntitle: \"Get started with GRASS & R: the rgrass package\"\nauthor: \"Veronica Andreo\"\ndate: 2024-03-29\ndate-modified: today\nformat:\n ipynb: default\n html:\n toc: true\n code-tools: true\n code-copy: true\n code-fold: false\ncategories: [R, rgrass, intermediate]\ndescription: Learn how to use GRASS and R to analyze geospatial data.\nengine: knitr\nexecute: \n eval: false\n---\n\nThe [**rgrass**](https://cran.r-project.org/web/packages/rgrass/index.html) \npackage allows us to interact with GRASS tools (and data) serving as an\ninterface between GRASS and R.\nThe *rgrass* package source code can be\nfound at: . In this fast track tutorial,\nwe will learn how to use GRASS from R.\n\n::: {.callout-note title=\"Setup\"}\nTo run this tutorial locally you should have GRASS 8.4+, \n[R](https://www.r-project.org/) and, optionally, \n[RStudio](https://posit.co/download/rstudio-desktop/) installed. \nYou will also need to install *rgrass*, *terra* and *mapview*\nR packages and download the \n[North Carolina sample dataset](https://grass.osgeo.org/sampledata/north_carolina/nc_basic_spm_grass7.zip).\n:::\n\n## *rgrass* main functions\n\nThe main functions within **rgrass** are the following:\n\n- `initGRASS()`: starts a GRASS session from R.\n- `execGRASS()`: executes GRASS commands from R.\n- `gmeta()`: prints GRASS session metadata like database, project, mapset, computational region settings and CRS.\n- `read_VECT()` and `read_RAST()`: read vector and raster maps from a GRASS project into R.\n- `write_VECT()` and `write_RAST()`: write vector and raster objects from R into a GRASS project.\n\n:::{.callout-note}\nFor further details on *rgrass* functionality, usage examples and data format \ncoercion, see: .\n:::\n\n## Basic usage: Choose your own adventure\n\nIf you are a regular R user that needs to use GRASS functionality \n**because, well, you know it rocks**, rgrass has your back. For example,\nmaybe you struggle with large raster datasets in R or you need some specific \ntool, like watershed delineation for a large high resolution DEM. We will show \nhere the way to use GRASS tools within your R workflows. \n\nOn the other hand, if you already use GRASS as your geospatial data processing \nengine, you most likely have your spatial data within GRASS projects. \nYou might need however to do some statistical analysis, some modelling and \nprediction or create publication ready visualizations in R. In such cases, \nyou can start a GRASS session in your project from R or RStudio.\n\nLet's see the general **basic steps** and then dive into the details:\n\n1. Make sure GRASS is installed.\n2. Open R (or RStudio)\n3. Load `rgrass` library with `library(rgrass)`\n4. Start a GRASS session with `initGRASS()`\n5. Use GRASS tools through `execGRASS()`\n6. Use `read_VECT()`, `read_RAST()`, `write_VECT()` and `write_RAST()` to read data from and write data into GRASS database.\n\n:::{.callout-note}\nGRASS raster and vector maps are translated into *terra*'s package SpatRaster \nand SpatVector objects, respectively. These objects can then, within R, be \neasily coerced to other types of spatial objects such as simple features (sf), \nstars, etc.\n\nSee *terra* vignettes with further explanations and examples: \n.\n:::\n\n### A. Use GRASS tools within your R spatial workflows\n\nWe start R or Rstudio and load the `rgrass` library. It will tell us that GRASS \nis not running, but we know that already... and that's about to change in a \nmoment.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(rgrass)\n```\n:::\n\n\nIn case you need to include some of the cool GRASS tools within your\nR workflow, the `initGRASS()` function allows you to create temporary GRASS \nprojects to use GRASS tools on R objects. \nThis is equivalent to what QGIS does when you use GRASS tools via the \nQGIS Processing Toolbox.\n\nFirst, we will use `initGRASS()` to create a temporary \nGRASS project based on the extent, resolution and CRS of a raster or vector R object, \nlikely the one we want to process or one that has the extent of our study area. \nHence, we need to pass a reference spatial grid via the *SG* parameter. \nThen, we will write our R objects into the temporary GRASS project, run the desired \nprocesses, and export the outputs back to the R environment.\n\nLet's start with getting some spatial data, e.g., a raster file, into R.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(terra)\nf <- system.file(\"ex/elev.tif\", package=\"terra\")\nr <- rast(f)\nplot(r)\n```\n:::\n\n\nNow, we will start GRASS in a temporary folder. By specifying `SG = r`,\nthe GRASS project is internally created with raster `r`'s object CRS (BTW,\nyou can check that with `crs(r)`), extent and resolution.\nThese latter define the GRASS computational region that will affect all raster\nprocessing, i.e., all new raster maps generated within GRASS will have the\nsame extent and resolution of the map provided. \nIf you wish to change the computational region later on, you can use the \n`g.region` GRASS tool with `execGRASS(\"g.region --h\")`.\n\nOptionally, we can specify which GRASS binary to use with `gisBase`. This might\nbe useful in case we have several GRASS versions on our system. If not provided,\n`initGRASS()` will attempt to find it in default locations depending on your\noperating system.\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Start GRASS from R\ninitGRASS(home = tempdir(),\n SG = r, \n override = TRUE)\n```\n:::\n\n\nNow, we can write our SpatRaster into the GRASS temporary project.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nwrite_RAST(r, \"terra_elev\")\n```\n:::\n\n\nAlternatively, we can use GRASS importing tools to import common raster and\nvector formats. Data will be reprojected if needed.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"r.import\", input=f, output=\"test\")\n```\n:::\n\n\nLet's check both raster maps (`test` and `terra_elev`) are indeed within\nthe project and run the GRASS tool \n[`r.slope.aspect`](https://grass.osgeo.org/grass-stable/manuals/r.slope.aspect.html)\non one of them.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"g.list\", type = \"raster\")\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"r.slope.aspect\", \n elevation = \"terra_elev\", \n slope = \"slope\",\n aspect = \"aspect\")\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"g.list\", type = \"raster\")\n```\n:::\n\n\nLet's get slope and aspect maps into R\n\n\n::: {.cell}\n\n```{.r .cell-code}\ngrass_maps <- read_RAST(c(\"aspect\", \"slope\"))\ngrass_maps\n```\n:::\n\n\nNow that the output maps are back into our R environment, we can plot them, do\nfurther analysis or write them into other raster formats, in which case we use\n`terra::writeRaster()` function.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nplot(grass_maps)\n```\n:::\n\n\n![](images/R_aspect_slope.png){.preview-image width=60%}\n\n\n::: {.cell}\n\n```{.r .cell-code}\nwriteRaster(grass_maps, \"grass_maps.tif\", overwrite=TRUE)\n```\n:::\n\n\nAlternatively, we can use GRASS exporting tools like \n[r.out.gdal](https://grass.osgeo.org/grass-stable/manuals/r.out.gdal.html) \nand [v.out.ogr](https://grass.osgeo.org/grass-stable/manuals/v.out.ogr.html), \nto directly save our outputs into common raster or vector formats, respectively.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"r.out.gdal\", input=\"slope\", output=\"slope.tif\", format=\"GTiff\", flags=\"overwrite\")\n```\n:::\n\n\n\n### B. Use R tools within GRASS workflows\n\nLet's see an example for the case when we do our geospatial data processing \nwithin GRASS and hence have all the spatial data organized within GRASS projects\nbut we need to run some statistical analysis, modelling, prediction \nor visualization in R.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(rgrass)\n```\n:::\n\n\nWe start GRASS from within R or RStudio using the `initGRASS()` function. \nSince we want to start GRASS in a specific project and mapset, we need to\nspecify them.\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Start GRASS from R\ninitGRASS(gisDbase = path.expand(\"~/grassdata/\"),\n location = \"nc_basic_spm_grass7\",\n mapset = \"PERMANENT\",\n override = TRUE,\n remove_GISRC = TRUE)\n```\n:::\n\n\nWe can now list and read our GRASS raster and vector maps into R and do our \nstatistical analysis, modelling and/or visualizations using other R packages. \nHere, we will demonstrate the use of all the main *rgrass* functions \nmentioned above.\n\nLet's then list our GRASS raster and vector maps:\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# List GRASS raster maps\nexecGRASS(\"g.list\", type=\"raster\")\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# List GRASS vector maps\nexecGRASS(\"g.list\", type=\"vector\")\n```\n:::\n\n\nThe resulting map lists could be saved in an R object that we can subset later \nin case we want to import several but not all raster maps, for example. Let's \nsee how to do that.\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Save map list in an object\nrast_list <- execGRASS(\"g.list\", type=\"raster\")\n\n# Retrieve only the map list from standard output\nrast_list <- attributes(rast_list)$resOut\n\n# Import elevation and landuse\nto_import <- c(\"elevation\", \"landuse\") # optionally, by position: rast_list[c(3,7)]\n\nmaplist <- list()\nfor (i in to_import) {\n maplist[[i]] <- read_RAST(i)\n}\n\nmaplist\n```\n:::\n\n\nRemember that raster objects will always be exported from GRASS following the \n*computational region settings*. So, bear that in mind when reading into R which \nwill hold them in memory. Vectors however will be exported in their full extent.\n\nLet's load the *terra* library to quickly display our recently imported raster \nmaps:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(terra)\nplot(maplist$elevation)\n```\n:::\n\n\nOptionally, we could stack our two `SpatRaster` objects together and plot them \ntogether:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nrstack <- rast(maplist)\nplot(rstack)\n```\n:::\n\n\nLet's create a boxplot of elevation per land class.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nboxplot(rstack$elevation, rstack$landuse, maxcell=50000)\n```\n:::\n\n\nLet's import a vector map, too, and explore its attributes.\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncensus <- read_VECT(\"census\")\nhead(census)\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nsummary(census$TOTAL_POP)\n```\n:::\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nplot(census, \"P25_TO_34\", type=\"interval\", breaks=5, plg=list(x=\"topright\"))\n```\n:::\n\n\nLet's do some interactive visualization with `mapview`.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(mapview)\nmapview(rstack$elevation) + census\n```\n:::\n\n\nWe highly recommend you to check the [tmap](https://r-tmap.github.io/tmap/) \npackage to make really appealing and publication ready maps.\n\nTo exemplify the use of `write_*` functions, let's do a simple operation with \nthe *landuse* raster map. We will apply a custom function that makes NULL all \nvalues less than 4.\n\n\n::: {.cell}\n\n```{.r .cell-code}\nresult <- app(rstack$landuse, fun=function(x){ x[x < 4] <- NA; return(x)} )\nplot(result)\n```\n:::\n\n\nTo use this new raster in GRASS, for example as an input to a GRASS tool, we need to call `write_RAST` function:\n\n::: {.cell}\n\n```{.r .cell-code}\nwrite_RAST(result, \"result_from_R\", overwrite = TRUE)\n```\n:::\n\n\nThe new raster is now written as a GRASS raster and can be listed:\n\n::: {.cell}\n\n```{.r .cell-code}\nexecGRASS(\"g.list\", parameters = list(type=\"raster\", pattern=\"result*\"))\n```\n:::\n\n\n\nFinally, there is yet another way in which you can use GRASS and R together, and it \ninvolves calling R from the GRASS terminal. In this way, *rgrass* will read all \nGRASS session environmental variables, and you won't need to use \n`initGRASS()`. It goes more or less like this:\n\n1. Open GRASS\n2. Type `R` or `rstudio &` in the GRASS terminal\n3. Load `rgrass` library with `library(rgrass)`\n4. Use `read_VECT()`, `read_RAST()` to read data from GRASS into R\n5. Do your analysis or plotting in R\n6. Write data (back) to GRASS database with `write_VECT()` and `write_RAST()`\n7. Quit R `quit()` and get back to GRASS terminal.\n\n``` \nStarting GRASS GIS...\n\n __________ ___ __________ _______________\n / ____/ __ \\/ | / ___/ ___/ / ____/ _/ ___/\n / / __/ /_/ / /| | \\__ \\\\_ \\ / / __ / / \\__ \\\n / /_/ / _, _/ ___ |___/ /__/ / / /_/ // / ___/ /\n \\____/_/ |_/_/ |_/____/____/ \\____/___//____/\n\nWelcome to GRASS GIS 8.4.0\nGRASS GIS homepage: https://grass.osgeo.org\nThis version running through: Bash Shell (/bin/bash)\nHelp is available with the command: g.manual -i\nSee the licence terms with: g.version -c\nSee citation options with: g.version -x\nIf required, restart the GUI with: g.gui wxpython\nWhen ready to quit enter: exit\n\nLaunching GUI in the background, please wait...\n[Raster MASK present]\nGRASS nc_basic_spm_grass7/PERMANENT:~ > R\n\nR version 4.3.1 (2023-06-16) -- \"Beagle Scouts\"\nCopyright (C) 2023 The R Foundation for Statistical Computing\nPlatform: x86_64-pc-linux-gnu (64-bit)\n\nR is free software and comes with ABSOLUTELY NO WARRANTY.\nYou are welcome to redistribute it under certain conditions.\nType 'license()' or 'licence()' for distribution details.\n\n Natural language support but running in an English locale\n\nR is a collaborative project with many contributors.\nType 'contributors()' for more information and\n'citation()' on how to cite R or R packages in publications.\n\nType 'demo()' for some demos, 'help()' for on-line help, or\n'help.start()' for an HTML browser interface to help.\nType 'q()' to quit R.\n\n> library(rgrass)\nGRASS GIS interface loaded with GRASS version: GRASS 8.4.0 (2024)\nand location: nc_basic_spm_grass7\n> \n```\n\n**Enjoy!** {{< fa rocket >}}\n\n\n## References\n\n- Bivand R (2024).\n_rgrass: Interface Between 'GRASS' Geographical Information System and 'R'_. \nR package version 0.4-1, .\n\n\n***\n\n:::{.smaller}\nThe development of this tutorial was funded by the US \n[National Science Foundation (NSF)](https://www.nsf.gov/), \naward [2303651](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2303651).\n:::\n", + "supporting": [], + "filters": [ + "rmarkdown/pagebreak.lua" + ], + "includes": {}, + "engineDependencies": {}, + "preserve": null, + "postProcess": false + } +} \ No newline at end of file diff --git a/_freeze/content/tutorials/get_started/fast_track_grass_and_python/execute-results/ipynb.json b/_freeze/content/tutorials/get_started/fast_track_grass_and_python/execute-results/ipynb.json new file mode 100644 index 0000000..f0323c8 --- /dev/null +++ b/_freeze/content/tutorials/get_started/fast_track_grass_and_python/execute-results/ipynb.json @@ -0,0 +1,11 @@ +{ + "hash": "d8676bba6a0dac10a49031145cf06442", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: \"Get started with GRASS & Python in Jupyter Notebooks\"\nauthor: \"Veronica Andreo\"\ndate: 2024-03-25\ndate-modified: today\nformat:\n ipynb: default\n html:\n toc: true\n code-tools: true\n code-copy: true\n code-fold: false\ncategories: [Python, beginner]\ndescription: Learn how to analyze geospatial data with Python in Jupyter Notebooks.\nengine: jupyter\nexecute:\n eval: false\njupyter: python3\n---\n\nPython, a widely used general-purpose, high-level programming language provides\na powerful scripting interface for geospatial data processing. Being easy-to-use\nyet powerful, it enables users to efficiently exploit the capabilities of the\nGRASS software. Python scripts for GRASS can be written at high level\n(GRASS tools) as well as at low level (GRASS libraries) through dedicated\ninterfaces. Indeed, GRASS is distributed with a set of\n[python packages](https://grass.osgeo.org/grass-stable/manuals/libpython/index.html)\nto provide functionalities at different levels.\n\nIn this tutorial, we will focus on two packages:\n[`grass.script`](https://grass.osgeo.org/grass-stable/manuals/libpython/script_intro.html)\nand [`grass.jupyter`](https://grass.osgeo.org/grass-stable/manuals/libpython/grass.jupyter.html),\nwhich provide Python interface to launch GRASS tools in scripts and offer\nclasses and setup functions for running GRASS in Jupyter Notebooks,\nrespectively.\nWe will show two different use cases:\n\n- A. You are mostly a Python user and only need to run a certain GRASS tool on your spatial data to get a specific output\n- B. You are mostly a GRASS user that wants to use GRASS from a Python environment or combine GRASS with other Python packages.\n\nLet's first go through the main functions of GRASS Python packages.\n\n### Python package `grass.script`\n\nThe **grass.script** package or GRASS Python Scripting Library provides\nfunctions for calling GRASS tools within Python scripts. The most\ncommonly used functions include:\n\n- `run_command`: used when there is no text output or the text output does not need to be further processed\n- `read_command`: used when the output of the tools is of text type\n- `parse_command`: used with tools that output machine readable text output\n- `write_command`: used with tools that expect text input, either in the form of a file or from stdin\n\nThere are several wrapper functions for frequently used tools, too.\nFor example:\n\n- To get info from a raster, script.raster.raster_info() is used: `gs.raster_info('dsm')`\n- To get info of a vector, script.vector.vector_info() is used: `gs.vector_info('roads')`\n- To list the raster in a project, script.core.list_grouped() is used: `gs.list_grouped(type=['raster'])`\n- To obtain the computational region, script.core.region() is used: `gs.region()`\n- To run raster algebra with r.mapcalc, script.raster.mapcalc() is used: `gs.mapcalc()`\n\nThe grass.script package also comes with different functions that are useful\nwhen you are writing your own GRASS tools or converting your scripts or\nworkflows into GRASS tools. Some examples of these functions are:\n`append_uuid`, `use_temp_region`, `del_temp_region`, `parse_key_val`, etc.\n\n:::{.callout-note}\nVisit the grass.script documentation for more details and examples:\n\n:::\n\n### Python package `grass.jupyter`\n\nThe **grass.jupyter** library improves the integration of GRASS and Jupyter, and\nprovides different classes to facilitate GRASS maps visualization:\n\n- `Map`: 2D rendering\n- `Map3D`: 3D rendering\n- `InteractiveMap`: interactive map visualization with folium or ipyleaflet\n- `SeriesMap`: visualizations of a series of raster or vector maps\n- `TimeSeriesMap`: visualization of space-time datasets\n\n:::{.callout-note}\nVisit the grass.jupyter documentation for more details and examples:\n\n:::\n\n## Let's get started!\n\n### Setup\nThis tutorial can be run locally. You need to have **GRASS 8.4+** and\n**Jupyter** installed. For part A, please download these\n[Sentinel 2](https://grass.osgeo.org/sampledata/north_carolina/nc_sentinel_utm17n.zip)\nscenes and move the unzipped download into the directory where you are running\nthis tutorial.\nFor part B, we asume that you have downloaded the North Carolina\n[sample dataset](https://grass.osgeo.org/sampledata/north_carolina/nc_basic_spm_grass7.zip),\ni.e., there's an existing GRASS project.\nBe sure you also have the following Python libraries installed in your\nenvironment: `folium` or `ipyleaflet`, `numpy`, `seaborn`, `matplotlib`, `pandas`.\n\nThe first thing we need to do is to\n*import GRASS python packages*. In order to do so, we need to\n*add GRASS python package to PATH*. Let's see how we do that.\n\n::: {#6ed5ab24 .cell execution_count=1}\n``` {.python .cell-code}\n# import standard Python packages\nimport os\nimport sys\nimport subprocess\nfrom pathlib import Path\n```\n:::\n\n\n::: {#2a0d21cb .cell execution_count=2}\n``` {.python .cell-code}\n# check where GRASS python packages are and add them to PATH\nsys.path.append(\n subprocess.check_output([\"grass\", \"--config\", \"python_path\"], text=True).strip()\n)\n```\n:::\n\n\n::: {#f2f0099a .cell execution_count=3}\n``` {.python .cell-code}\n# import GRASS python packages\nimport grass.script as gs\nimport grass.jupyter as gj\n```\n:::\n\n\n:::{.callout-note}\nWe recommend Windows users to review how to run [GRASS in Jupyter Notebooks on Windows](JupyterOnWindows_OSGeo4W_Tutorial.qmd).\n:::\n\n\n### A. Use GRASS tools within your Python spatial workflows\n\nNow, let's assume you have some raster data you want to process with GRASS\ntools, eg. Sentinel 2 satellite data, to obtain texture indices. The first thing\nyou'll need to do is to **create a GRASS project** to import your data. As\nwe saw already in a previous [fast track](fast_track.qmd) tutorial, GRASS\nprojects are folders where we store spatial data with the same spatial\nreference. These projects can be placed wherever you want, including a temporary\ndirectory if you are mostly interested in the outputs only.\n\nSo, let's *create a project in a temporary directory* to import, i.e. read, our\ndata with GRASS. The `gs.create_project()` function allows us to create a\nGRASS project passing different information. For example, we can use the EPSG\ncode of the data CRS or directly pass a georeferenced file.\n\n::: {#da0766b0 .cell execution_count=4}\n``` {.python .cell-code}\n# Create a temporary folder where to place our GRASS project\nimport tempfile\ntempdir = tempfile.TemporaryDirectory()\n```\n:::\n\n\n::: {#bc1f20c5 .cell execution_count=5}\n``` {.python .cell-code}\n# Create a project in the temporary directory\ngs.create_project(path=tempdir.name,\n name=\"nc_sentinel\",\n epsg=\"32617\")\n```\n:::\n\n\nAlternatively, use a georeferenced file to read the spatial reference\ninformation from:\n\n::: {#cdab95c1 .cell execution_count=6}\n``` {.python .cell-code}\n# gs.create_project(path=tempdir.name, name=\"nc_sentinel\", filename=\"path/to/georef/file\", overwrite=True)\n```\n:::\n\n\nNow that we created a project, let's **start a GRASS** session there.\n\n::: {#37b75a70 .cell execution_count=7}\n``` {.python .cell-code}\n# Start GRASS in the recently created project\nsession = gj.init(Path(tempdir.name, \"nc_sentinel\"))\n```\n:::\n\n\nWe are now ready to **import data** into the recently created project. Let's use\na for loop to import all 10 m resolution bands. These are level 2A surface\nreflectance data for blue, green, red and near infrared Sentinel 2 bands.\n\n::: {#fcf7936b .cell execution_count=8}\n``` {.python .cell-code}\nimport shutil\n\nshutil.unpack_archive(\"./nc_sentinel_utm17n/S2A_MSIL2A_20220304T160151_N0400_R097_T17SQV_20220304T215812.zip\", \"./nc_sentinel_utm17n\")\nfiles = sorted(Path('./nc_sentinel_utm17n/S2A_MSIL2A_20220304T160151_N0400_R097_T17SQV_20220304T215812.SAFE/GRANULE/L2A_T17SQV_A034986_20220304T160221/IMG_DATA/R10m').glob('*B*.jp2'))\nfiles\n```\n:::\n\n\n::: {#19c5a6a4 .cell execution_count=9}\n``` {.python .cell-code}\nfor file in files:\n name = str(file)[-11:-4]\n print(\"importing \" + name)\n gs.run_command(\"r.import\", input=file, output=name)\n```\n:::\n\n\nLet's check the files we just imported are there:\n\n::: {#e37a9bd2 .cell execution_count=10}\n``` {.python .cell-code}\ngs.list_grouped(type=\"raster\")[\"PERMANENT\"]\n```\n:::\n\n\nLet's have a quick look at one of the imported bands. We can use the `InteractiveMap`\nclass from the grass.jupyter package to **visualize** it.\n\n::: {#9084bde4 .cell execution_count=11}\n``` {.python .cell-code}\nm = gj.InteractiveMap()\nm.add_raster(\"B08_10m\")\nm.show()\n```\n:::\n\n\nNext step is to do some **processing or analysis** with the imported data.\nSince we'll be creating new raster maps, we first\nneed to set our *computational region* to the extent and resolution of one of our\nimported bands.\n\n::: {#2c7268fd .cell execution_count=12}\n``` {.python .cell-code}\n# Set computational region\ngs.run_command(\"g.region\", raster=\"B08_10m\", flags=\"p\")\n```\n:::\n\n\n::: {#6dcd9740 .cell execution_count=13}\n``` {.python .cell-code}\nm = gj.InteractiveMap(tiles=\"OpenStreetMap\")\nm.add_raster(\"B08_10m\")\nm.show()\n```\n:::\n\n\nIt is common to estimate texture measures over panchromatic bands. Since\nwe do not have one in Sentinel 2 data, we'll create a synthetic one by averaging\nblue, green and red bands.\n\n::: {#da14a88b .cell execution_count=14}\n``` {.python .cell-code}\n# Create synthetic pan band\ngs.mapcalc(\"pan = (B02_10m + B03_10m + B04_10m) / 3\")\n```\n:::\n\n\nNow that we have the synthetic pan band, let's estimate some texture measures\nwith the [r.texture](https://grass.osgeo.org/grass-stable/manuals/r.texture.html)\ntool.\n\n::: {#08fcd519 .cell execution_count=15}\n``` {.python .cell-code}\ngs.run_command(\"r.texture\",\n input=\"pan\",\n output=\"pan\",\n size=5,\n method=\"contrast,corr\")\n```\n:::\n\n\n::: {#dce941ad .cell execution_count=16}\n``` {.python .cell-code}\ngs.list_grouped(type=\"raster\", pattern=\"pan*\")[\"PERMANENT\"]\n```\n:::\n\n\n::: {#1217a25e .cell execution_count=17}\n``` {.python .cell-code}\nt = gj.InteractiveMap(tiles=\"OpenStreetMap\")\nt.add_raster(\"pan_Contr\")\nt.add_raster(\"pan_Corr\")\nt.show()\n```\n:::\n\n\nFinally, we can **export** our texture maps out of GRASS and use them\nsomewhere else or load them into a webGIS.\n\n::: {#e6b051e0 .cell execution_count=18}\n``` {.python .cell-code}\ntexture_maps = gs.list_grouped(type=\"raster\", pattern=\"pan_*\")[\"PERMANENT\"]\ntexture_maps\n```\n:::\n\n\n::: {#081823c8 .cell execution_count=19}\n``` {.python .cell-code}\nfor texture in texture_maps:\n gs.run_command(\"r.out.gdal\", input=texture, output=f\"{texture}.tif\", format=\"GTiff\")\n```\n:::\n\n\nThis use case follows the\nExtract-Transform-Load (ETL) process common in production systems. Indeed, this\napproach allows to include GRASS tools into such workflows. These type of\ntasks could be automatized in scripts to be run without even starting GRASS\nusing the `--exec` tool... but that's material for a different tutorial :)\n\n### B. Use Python tools within GRASS workflows\n\nThis case is more relevant for GRASS users who want to combine GRASS\nwith other Python tools for their data processing and analysis workflows.\n\nSeveral GRASS users store most or all of their projects in a single folder,\nwhich has traditionally been called `grassdata`. When this is the case, to\n**start GRASS in an existing project**, we also need to provide the path\nto such a folder.\n\n::: {#e1b1bdb7 .cell execution_count=20}\n``` {.python .cell-code}\n# Start GRASS\nsession = gj.init(\"~/grassdata/nc_basic_spm_grass7/PERMANENT\")\n# alternatively\n# session = gj.init(\"~/grassdata/nc_basic_spm_grass7\")\n# session = gj.init(\"~/grassdata\", \"nc_basic_spm_grass7\", \"PERMANENT\")\n```\n:::\n\n\nWe are now within a GRASS project, let's **obtain information** about it, like\nCRS details, region settings, list of raster and vector maps, etc.\n\n::: {#2694990a .cell execution_count=21}\n``` {.python .cell-code}\n# Print project's CRS\ngs.parse_command(\"g.proj\", flags=\"g\")[\"srid\"]\n```\n:::\n\n\n::: {#7dcd2ab6 .cell execution_count=22}\n``` {.python .cell-code}\n# Print computational region\ngs.region()\n```\n:::\n\n\n::: {#9f7a7ff5 .cell execution_count=23}\n``` {.python .cell-code}\n# List raster maps\ngs.list_grouped([\"raster\"])\n```\n:::\n\n\nLet's obtain metadata about the *elevation* raster map.\n\n::: {#5ce4f3d6 .cell execution_count=24}\n``` {.python .cell-code}\n# Raster info\ngs.raster_info(\"elevation\")\n```\n:::\n\n\nIf we would only need to know or use the minimum value of the *elevation* raster,\nwe can get it as follows:\n\n::: {#454008bf .cell execution_count=25}\n``` {.python .cell-code}\ngs.raster_info(\"elevation\")[\"min\"]\n```\n:::\n\n\nLet's now **visualize** raster and vector maps with a different `grass.jupyter`\nclass, the non-interactive `Map` class. This class creates and displays GRASS\nmaps as PNG files. We basically instantiate the class first, add maps and maps'\nelements and finally show the result. There are 2 ways of calling display\n(`d.*`) modules:\n\n- replace `.` by `_` as in `m.d_rast()`\n- use `run()` as in `m.run(\"d.rast\")`\n\n::: {#1e17718b .cell execution_count=26}\n``` {.python .cell-code}\n# Instantiate the Map class\nm = gj.Map(width=400)\n```\n:::\n\n\nThe *Map* class will by default use the first raster or vector extent to set the\ndisplay extent. You could however also use the current computational region with\n`use_region=True` or call a previously saved computational region (different\nthan the current) with the argument `saved_region`.\n\n::: {#ebe373c3 .cell execution_count=27}\n``` {.python .cell-code}\n# Add maps and map elements\nm.d_rast(map=\"elevation\")\nm.d_vect(map=\"streams\")\nm.d_legend(raster=\"elevation\", at=(50, 95, 85, 90), flags=\"b\")\n```\n:::\n\n\n::: {#0cb1e8a2 .cell execution_count=28}\n``` {.python .cell-code}\n# Display the result\nm.show()\n```\n:::\n\n\nWe can save our displayed maps by calling the `save()` method, i.e., `m.save()`.\nFor the Map class it will output a PNG file, while for the InteractiveMap class\nan HTML.\n\n#### GRASS & NumPy\n\nLet's now see how to convert our **GRASS rasters into numpy arrays**. Having our\nraster maps as numpy arrays opens up a world of possibilities in terms of\nvisualization and data analysis and modeling. We won't go into anything complex\nhere, but we'll show how to read rasters into numpy arrays, plot them, modify\nthem and then write them back into GRASS.\n\n::: {#7c43c748 .cell execution_count=29}\n``` {.python .cell-code}\n# Import required libraries\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom grass.script import array as garray\n```\n:::\n\n\n::: {#7dcdbe19 .cell execution_count=30}\n``` {.python .cell-code}\n# Read elevation as numpy array\nelev = garray.array(mapname=\"elevation\", null=\"nan\")\nprint(elev.shape)\n```\n:::\n\n\n::: {#ed3ff6f5 .cell execution_count=31}\n``` {.python .cell-code}\n# Estimate array average\nprint(np.average(elev))\n```\n:::\n\n\n::: {#7c539d76 .cell execution_count=32}\n``` {.python .cell-code}\n# Plot elev histogram\nsns.set_style('darkgrid')\nsns.histplot(data=elev.ravel(), kde=True)\n```\n:::\n\n\nLet's modify our array and write it back into GRASS. For this, we create a\nnew copy of the GRASS elevation map first as shown below.\n\n::: {#a4a8b2a1 .cell execution_count=33}\n``` {.python .cell-code}\nelev_2 = garray.array(mapname=\"elevation\")\nelev_2 *= 2\n```\n:::\n\n\n::: {#0f23d4d3 .cell execution_count=34}\n``` {.python .cell-code}\n# Plot elev*2\nsns.histplot(data=[elev.ravel(), elev_2.ravel()], kde=True)\nplt.legend(labels=[\"elevation * 2\", \"elevation\"])\n```\n:::\n\n\n![](images/grass_python_histogram.png){.preview-image}\n\nNow we write the modified array into a GRASS raster map and check it's actually\nthere.\n\n::: {#a1bd0f56 .cell execution_count=35}\n``` {.python .cell-code}\nelev_2.write(mapname=\"elevation_2\", overwrite=True)\n```\n:::\n\n\n::: {#43ae7caa .cell execution_count=36}\n``` {.python .cell-code}\ngs.list_grouped(type=\"raster\", pattern=\"elev*\")\n```\n:::\n\n\n#### GRASS & Pandas\n\nLet's now explore how to convert text outputs into pandas data frames. We will\nget elevation univariate statistics for each land use class and parse the output\ninto a pandas data frame.\n\n::: {#0f91588f .cell execution_count=37}\n``` {.python .cell-code}\nimport pandas as pd\nfrom io import StringIO\n```\n:::\n\n\n::: {#53d8f1dd .cell execution_count=38}\n``` {.python .cell-code}\nstats = gs.read_command(\"r.univar\",\n flags=\"t\",\n map=\"elevation\",\n zones=\"landuse\",\n separator=\"comma\")\ndf = pd.read_csv(StringIO(stats))\n\ndf\n```\n:::\n\n\nNext, we plot the mean elevation per class as follows:\n\n::: {#738873bf .cell execution_count=39}\n``` {.python .cell-code}\nplt.figure(figsize=(10, 5))\nplt.bar(df['label'], df['mean'])\nplt.ylabel('Elevation')\nplt.title('Mean elevation by land cover type')\nplt.xticks(rotation=90)\nplt.show()\n```\n:::\n\n\nSimilarly, if we need to do analysis with the attributes of GRASS vector maps,\nit is also possible to read the attribute table as a pandas data frame. Let's\nsee an example with the census vector map:\n\n::: {#a6784787 .cell execution_count=40}\n``` {.python .cell-code}\ncensus = gs.parse_command(\"v.db.select\", map=\"census\", format=\"json\")[\"records\"]\ndf = pd.DataFrame(census)\ndf\n```\n:::\n\n\nOnce the attribute table is a data frame, we can, e.g., filter data by a\ncondition and plot the results.\n\n::: {#f6597fa6 .cell execution_count=41}\n``` {.python .cell-code}\nfam_size_3 = df[df[\"FAM_SIZE\"] > 3.0]\n```\n:::\n\n\n::: {#5a2a0915 .cell execution_count=42}\n``` {.python .cell-code}\nfam_size_3.plot.scatter(x=\"FAM_SIZE\", y=\"OWNER_U\")\n```\n:::\n\n\n## Final remarks\n\nIn this tutorial, we have demonstrated, with very simple examples, how to use\nGRASS tools together with Python, putting a special focus on data import\nand export as well as format conversions. Expert GRASS or Python users can then\nimplement their workflows combining tools accordingly.\n\n**Enjoy!** {{< fa rocket >}}\n\n\n***\n:::{.smaller}\nThe development of this tutorial was funded by the US\n[National Science Foundation (NSF)](https://www.nsf.gov/),\naward [2303651](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2303651).\n:::\n\n---\njupyter:\n kernelspec:\n display_name: Python 3 (ipykernel)\n language: python\n name: python3\n path: /home/coreywhite/.local/share/jupyter/kernels/python3\n language_info:\n codemirror_mode:\n name: ipython\n version: 3\n file_extension: .py\n mimetype: text/x-python\n name: python\n nbconvert_exporter: python\n pygments_lexer: ipython3\n version: 3.10.12\n---\n", + "supporting": [ + "fast_track_grass_and_python_files" + ], + "filters": [] + } +} \ No newline at end of file diff --git a/_freeze/content/tutorials/get_started/grass_gis_in_google_colab/execute-results/html.json b/_freeze/content/tutorials/get_started/grass_gis_in_google_colab/execute-results/html.json new file mode 100644 index 0000000..adb99e8 --- /dev/null +++ b/_freeze/content/tutorials/get_started/grass_gis_in_google_colab/execute-results/html.json @@ -0,0 +1,12 @@ +{ + "hash": "4818d1ab26e2738f74953b93a768e1f1", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: \"Get started with GRASS in Google Colab\"\nauthor: \"Veronica Andreo\"\ndate: 2024-04-12\ndate-modified: today\nformat:\n ipynb: default\n html:\n toc: true\n code-tools: true\n code-copy: true\n code-fold: false\ncategories: [Python, Google Colab, beginner]\ndescription: Learn how to analyze geospatial data with Python in Google Colab.\nengine: jupyter\nexecute: \n eval: false\njupyter: python3\n---\n\n# What is Colab?\n\nPerhaps you have heard of Google Colaboratory or simply Colab. This is a hosted\nJupyter Notebook service that requires no setup or configuration to use and\nprovides free access to computing resources, including GPUs and TPUs.\nColab is especially well suited to machine learning, data science, and education.\nFurthermore, it allows easy sharing of workflows which facilitates reproducibility.\n\nColab notebooks allow you to combine executable code and rich text in a single\ndocument, along with images, HTML, LaTeX and more. When you create your own\nColab notebooks, they are stored in your Google Drive account. You can easily\nshare your Colab notebooks with co-workers or friends, allowing them to comment\non your notebooks or even edit them.\n\n::: {.callout-note}\nSee Colab's FAQ for more details: \nand follow the Google Colab blog in Medium at .\n:::\n\n# Why GRASS in Colab?\n\nSince Colab offers Jupyter notebooks in a Linux environment\n**it is really easy to install or even compile GRASS there**.\nAlso, because of the integration with Google Drive, it is a great resource to\nrun our workflows in the cloud and export the results or keep our GRASS\nprojects and code there. This clearly facilitates teaching workshops or courses\nsince attendants do not need to install or download anything on their own\nmachines.\n\nThere are a couple of things to consider when working with GRASS within\nColab though. Users will need to\n*install GRASS every time they start a new working session or notebook*.\nFurthermore, whatever files users download within Colab\n*will last only during the current session*.\nIf the runtime gets disconnected because of inactivity, downloaded data and\noutputs created within Colab, will be lost too.\nIf users instead, mount their own Google drive, download data and create their\nGRASS projects there, those will be preserved even if the runtime is\ndisconnected or the session closed.\n\n# Install GRASS in Colab\n\nStart at and create a new notebook. Let's first print system description to know where are we. The exclamation mark is used for executing commands from the underlying operating system:\n\n::: {#a73945f8 .cell execution_count=1}\n``` {.python .cell-code}\n!lsb_release -a\n```\n:::\n\n\nAt the time of writing this tutorial, Colab has Linux\n[Ubuntu 22.04.4 LTS](https://medium.com/google-colab/colab-updated-to-ubuntu-22-04-lts-709a91555b3c).\nSo we add the ppa:ubuntugis repository, update and install GRASS. It might\ntake a couple of minutes according to the resources available.\n\n::: {#62c1d90f .cell execution_count=2}\n``` {.python .cell-code}\n!add-apt-repository -y ppa:ubuntugis/ubuntugis-unstable\n!apt update\n!apt-get install -y grass-core grass-dev\n```\n:::\n\n\nCheck that GRASS is installed by asking which version is there.\n\n::: {#e581f768 .cell execution_count=3}\n``` {.python .cell-code}\n!grass --version\n```\n:::\n\n\nTo import the `grass.script` and `grass.jupyter` modules, you need to tell\nPython where the GRASS Python package is:\n\n::: {#636a26d2 .cell execution_count=4}\n``` {.python .cell-code}\n# Import standard Python packages we need\nimport sys\nimport subprocess\n\n# Ask GRASS where its Python packages are to be able to run it from the notebook\nsys.path.append(\n subprocess.check_output([\"grass\", \"--config\", \"python_path\"], text=True).strip()\n)\n```\n:::\n\n\n::: {#66fa3de7 .cell execution_count=5}\n``` {.python .cell-code}\n# Import the GRASS packages\nimport grass.script as gs\nimport grass.jupyter as gj\n```\n:::\n\n\n:::{.callout-note}\nBy default we have access to the `/content` folder within Colab, and any data we\ncreate and download will be placed there. We can change that of course, it is just a Linux\nfile system. In any case, we should bare in mind that whatever data we download\nwithin Colab, will disappear if the runtime gets disconected because of inactivity\nor once we close the Colab session.\n:::\n\n# Create a new GRASS project\n\nTo create a new project we can use the `create_project` function from the\ngrass.script library.\nLet's, for example, create a project with the EPSG code\n 32617 (UTM zone 17N):\n\n::: {#5cbff021 .cell execution_count=6}\n``` {.python .cell-code}\ngs.create_project(\"nc_sentinel\", epsg=\"32617\")\n```\n:::\n\n\nNow we can start GRASS in the created project:\n\n::: {#65512f1f .cell execution_count=7}\n``` {.python .cell-code}\n# Start GRASS in default project mapset\nsession = gj.init(\"nc_sentinel\")\n```\n:::\n\n\nNow you can import data and start your analysis, following the\n[GRASS and Python tutorial, part A](fast_track_grass_and_python.qmd#a.-use-grass-tools-within-your-python-spatial-workflows).\n\n# Start GRASS with a sample dataset\n\nIf you want to learn data analysis with GRASS, instead of creating a new project from scratch,\nyou can downlaod a ready-to-use sample dataset to play with.\n\n## Download sample data\n\nLet's get the North Carolina sample dataset into Colab to show a data\ndownload workflow.\n\n::: {#b6148238 .cell execution_count=8}\n``` {.python .cell-code}\n!wget -c https://grass.osgeo.org/sampledata/north_carolina/nc_basic_spm_grass7.zip -O nc.zip\n```\n:::\n\n\nWe unzip the downloaded file in /content\n\n::: {#39a68b00 .cell execution_count=9}\n``` {.python .cell-code}\n!unzip nc.zip\n```\n:::\n\n\nand finally check it is indeed there:\n\n::: {#e85cf8a8 .cell execution_count=10}\n``` {.python .cell-code}\nimport os\n\n# List files and directories\nos.listdir()\n```\n:::\n\n\nYou should see *nc_basic_spm_grass7* sample dataset, which is a GRASS project.\n\n## Start GRASS\n\nWe have GRASS installed and a sample project to play around, so we are ready\nto start GRASS within the North Carolina project.\n\n::: {#321c5bd5 .cell execution_count=11}\n``` {.python .cell-code}\n# Start GRASS in default project mapset\nsession = gj.init(\"nc_basic_spm_grass7\")\n```\n:::\n\n\nJust as an example, we will list the raster maps and display one of them using\nthe InteractiveMap class.\n\n::: {#2db06293 .cell execution_count=12}\n``` {.python .cell-code}\ngs.list_grouped(type=\"raster\")\n```\n:::\n\n\n::: {#cc1ed9c1 .cell execution_count=13}\n``` {.python .cell-code}\nm = gj.InteractiveMap()\nm.add_raster(\"elevation\")\nm.show()\n```\n:::\n\n\nYou can continue exploring the dataset in [GRASS and Python tutorial, part B](fast_track_grass_and_python.qmd#b.-use-python-tools-within-grass-workflows).\n\n# Connect Colab with Google Drive\n\nIf we do not want to loose our GRASS projects when closing the Colab notebook,\nwe can connect Colab with our Google Drive and upload, download or create our\nprojects there. To be able to do any of that, we need to mount our drive first\n(i.e., similar to what we do with external drives).\nWe first import the `drive` library.\n\n::: {#692a4c9a .cell execution_count=14}\n``` {.python .cell-code}\nfrom google.colab import drive \n```\n:::\n\n\nThen, we define the mounting point. Running the cell below triggers a dialog to\ngrant Colab access to our drive. It is possible to change accounts, too. Once\nthat is complete, we will have access to everything we have in our GDrive folders\nand we can browse the content either with commands or from the left panel in\nthe Colab notebook.\n\n::: {#c67a232b .cell execution_count=15}\n``` {.python .cell-code}\ndrive.mount(\"/content/drive\")\n```\n:::\n\n\nWe can also mount our drive directly from the Colab interface as shown below:\n\n![](images/colab_mount_gdrive.png){.preview-image}\n\nOnce the GDrive is mounted, we can create a new project and start GRASS there.\nTo stay organized, GRASS projects are often saved under `grassdata` folder.\n\n::: {#cf7ec5ec .cell execution_count=16}\n``` {.python .cell-code}\ngs.create_project(\"/content/drive/MyDrive/grassdata/nc_sentinel\", epsg=\"32617\")\ngs.init(\"/content/drive/MyDrive/grassdata/nc_sentinel\")\n```\n:::\n\n\nImportantly, we can then process and analyse our data so that our data\nwill remain in GDrive for the next time.\n\n**Cool, ah?! Enjoy!** {{< fa rocket >}}\n\n***\n\n:::{.smaller}\nThe development of this tutorial was funded by the US\n[National Science Foundation (NSF)](https://www.nsf.gov/),\naward [2303651](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2303651).\n:::\n\n", + "supporting": [ + "grass_gis_in_google_colab_files/figure-html" + ], + "filters": [], + "includes": {} + } +} \ No newline at end of file diff --git a/_freeze/content/tutorials/get_started/grass_gis_in_google_colab/execute-results/ipynb.json b/_freeze/content/tutorials/get_started/grass_gis_in_google_colab/execute-results/ipynb.json new file mode 100644 index 0000000..408dff0 --- /dev/null +++ b/_freeze/content/tutorials/get_started/grass_gis_in_google_colab/execute-results/ipynb.json @@ -0,0 +1,11 @@ +{ + "hash": "4818d1ab26e2738f74953b93a768e1f1", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: \"Get started with GRASS in Google Colab\"\nauthor: \"Veronica Andreo\"\ndate: 2024-04-12\ndate-modified: today\nformat:\n ipynb: default\n html:\n toc: true\n code-tools: true\n code-copy: true\n code-fold: false\ncategories: [Python, Google Colab, beginner]\ndescription: Learn how to analyze geospatial data with Python in Google Colab.\nengine: jupyter\nexecute: \n eval: false\njupyter: python3\n---\n\n# What is Colab?\n\nPerhaps you have heard of Google Colaboratory or simply Colab. This is a hosted\nJupyter Notebook service that requires no setup or configuration to use and\nprovides free access to computing resources, including GPUs and TPUs.\nColab is especially well suited to machine learning, data science, and education.\nFurthermore, it allows easy sharing of workflows which facilitates reproducibility.\n\nColab notebooks allow you to combine executable code and rich text in a single\ndocument, along with images, HTML, LaTeX and more. When you create your own\nColab notebooks, they are stored in your Google Drive account. You can easily\nshare your Colab notebooks with co-workers or friends, allowing them to comment\non your notebooks or even edit them.\n\n::: {.callout-note}\nSee Colab's FAQ for more details: \nand follow the Google Colab blog in Medium at .\n:::\n\n# Why GRASS in Colab?\n\nSince Colab offers Jupyter notebooks in a Linux environment\n**it is really easy to install or even compile GRASS there**.\nAlso, because of the integration with Google Drive, it is a great resource to\nrun our workflows in the cloud and export the results or keep our GRASS\nprojects and code there. This clearly facilitates teaching workshops or courses\nsince attendants do not need to install or download anything on their own\nmachines.\n\nThere are a couple of things to consider when working with GRASS within\nColab though. Users will need to\n*install GRASS every time they start a new working session or notebook*.\nFurthermore, whatever files users download within Colab\n*will last only during the current session*.\nIf the runtime gets disconnected because of inactivity, downloaded data and\noutputs created within Colab, will be lost too.\nIf users instead, mount their own Google drive, download data and create their\nGRASS projects there, those will be preserved even if the runtime is\ndisconnected or the session closed.\n\n# Install GRASS in Colab\n\nStart at and create a new notebook. Let's first print system description to know where are we. The exclamation mark is used for executing commands from the underlying operating system:\n\n::: {#839e1f8b .cell execution_count=1}\n``` {.python .cell-code}\n!lsb_release -a\n```\n:::\n\n\nAt the time of writing this tutorial, Colab has Linux\n[Ubuntu 22.04.4 LTS](https://medium.com/google-colab/colab-updated-to-ubuntu-22-04-lts-709a91555b3c).\nSo we add the ppa:ubuntugis repository, update and install GRASS. It might\ntake a couple of minutes according to the resources available.\n\n::: {#88214644 .cell execution_count=2}\n``` {.python .cell-code}\n!add-apt-repository -y ppa:ubuntugis/ubuntugis-unstable\n!apt update\n!apt-get install -y grass-core grass-dev\n```\n:::\n\n\nCheck that GRASS is installed by asking which version is there.\n\n::: {#e3695550 .cell execution_count=3}\n``` {.python .cell-code}\n!grass --version\n```\n:::\n\n\nTo import the `grass.script` and `grass.jupyter` modules, you need to tell\nPython where the GRASS Python package is:\n\n::: {#7c41e4b0 .cell execution_count=4}\n``` {.python .cell-code}\n# Import standard Python packages we need\nimport sys\nimport subprocess\n\n# Ask GRASS where its Python packages are to be able to run it from the notebook\nsys.path.append(\n subprocess.check_output([\"grass\", \"--config\", \"python_path\"], text=True).strip()\n)\n```\n:::\n\n\n::: {#6945bca4 .cell execution_count=5}\n``` {.python .cell-code}\n# Import the GRASS packages\nimport grass.script as gs\nimport grass.jupyter as gj\n```\n:::\n\n\n:::{.callout-note}\nBy default we have access to the `/content` folder within Colab, and any data we\ncreate and download will be placed there. We can change that of course, it is just a Linux\nfile system. In any case, we should bare in mind that whatever data we download\nwithin Colab, will disappear if the runtime gets disconected because of inactivity\nor once we close the Colab session.\n:::\n\n# Create a new GRASS project\n\nTo create a new project we can use the `create_project` function from the\ngrass.script library.\nLet's, for example, create a project with the EPSG code\n 32617 (UTM zone 17N):\n\n::: {#a5931266 .cell execution_count=6}\n``` {.python .cell-code}\ngs.create_project(\"nc_sentinel\", epsg=\"32617\")\n```\n:::\n\n\nNow we can start GRASS in the created project:\n\n::: {#02129b8e .cell execution_count=7}\n``` {.python .cell-code}\n# Start GRASS in default project mapset\nsession = gj.init(\"nc_sentinel\")\n```\n:::\n\n\nNow you can import data and start your analysis, following the\n[GRASS and Python tutorial, part A](fast_track_grass_and_python.qmd#a.-use-grass-tools-within-your-python-spatial-workflows).\n\n# Start GRASS with a sample dataset\n\nIf you want to learn data analysis with GRASS, instead of creating a new project from scratch,\nyou can downlaod a ready-to-use sample dataset to play with.\n\n## Download sample data\n\nLet's get the North Carolina sample dataset into Colab to show a data\ndownload workflow.\n\n::: {#4e2a2fda .cell execution_count=8}\n``` {.python .cell-code}\n!wget -c https://grass.osgeo.org/sampledata/north_carolina/nc_basic_spm_grass7.zip -O nc.zip\n```\n:::\n\n\nWe unzip the downloaded file in /content\n\n::: {#f4e43273 .cell execution_count=9}\n``` {.python .cell-code}\n!unzip nc.zip\n```\n:::\n\n\nand finally check it is indeed there:\n\n::: {#2ce171dc .cell execution_count=10}\n``` {.python .cell-code}\nimport os\n\n# List files and directories\nos.listdir()\n```\n:::\n\n\nYou should see *nc_basic_spm_grass7* sample dataset, which is a GRASS project.\n\n## Start GRASS\n\nWe have GRASS installed and a sample project to play around, so we are ready\nto start GRASS within the North Carolina project.\n\n::: {#35a6c833 .cell execution_count=11}\n``` {.python .cell-code}\n# Start GRASS in default project mapset\nsession = gj.init(\"nc_basic_spm_grass7\")\n```\n:::\n\n\nJust as an example, we will list the raster maps and display one of them using\nthe InteractiveMap class.\n\n::: {#3762c9e9 .cell execution_count=12}\n``` {.python .cell-code}\ngs.list_grouped(type=\"raster\")\n```\n:::\n\n\n::: {#00f1c50d .cell execution_count=13}\n``` {.python .cell-code}\nm = gj.InteractiveMap()\nm.add_raster(\"elevation\")\nm.show()\n```\n:::\n\n\nYou can continue exploring the dataset in [GRASS and Python tutorial, part B](fast_track_grass_and_python.qmd#b.-use-python-tools-within-grass-workflows).\n\n# Connect Colab with Google Drive\n\nIf we do not want to loose our GRASS projects when closing the Colab notebook,\nwe can connect Colab with our Google Drive and upload, download or create our\nprojects there. To be able to do any of that, we need to mount our drive first\n(i.e., similar to what we do with external drives).\nWe first import the `drive` library.\n\n::: {#5867b832 .cell execution_count=14}\n``` {.python .cell-code}\nfrom google.colab import drive \n```\n:::\n\n\nThen, we define the mounting point. Running the cell below triggers a dialog to\ngrant Colab access to our drive. It is possible to change accounts, too. Once\nthat is complete, we will have access to everything we have in our GDrive folders\nand we can browse the content either with commands or from the left panel in\nthe Colab notebook.\n\n::: {#66f066ae .cell execution_count=15}\n``` {.python .cell-code}\ndrive.mount(\"/content/drive\")\n```\n:::\n\n\nWe can also mount our drive directly from the Colab interface as shown below:\n\n![](images/colab_mount_gdrive.png){.preview-image}\n\nOnce the GDrive is mounted, we can create a new project and start GRASS there.\nTo stay organized, GRASS projects are often saved under `grassdata` folder.\n\n::: {#a6d05496 .cell execution_count=16}\n``` {.python .cell-code}\ngs.create_project(\"/content/drive/MyDrive/grassdata/nc_sentinel\", epsg=\"32617\")\ngs.init(\"/content/drive/MyDrive/grassdata/nc_sentinel\")\n```\n:::\n\n\nImportantly, we can then process and analyse our data so that our data\nwill remain in GDrive for the next time.\n\n**Cool, ah?! Enjoy!** {{< fa rocket >}}\n\n***\n\n:::{.smaller}\nThe development of this tutorial was funded by the US\n[National Science Foundation (NSF)](https://www.nsf.gov/),\naward [2303651](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2303651).\n:::\n\n---\njupyter:\n kernelspec:\n display_name: Python 3 (ipykernel)\n language: python\n name: python3\n path: /home/coreywhite/.local/share/jupyter/kernels/python3\n language_info:\n codemirror_mode:\n name: ipython\n version: 3\n file_extension: .py\n mimetype: text/x-python\n name: python\n nbconvert_exporter: python\n pygments_lexer: ipython3\n version: 3.10.12\n---\n", + "supporting": [ + "grass_gis_in_google_colab_files" + ], + "filters": [] + } +} \ No newline at end of file diff --git a/_freeze/content/tutorials/good_looking_plots/good_looking_plots_in_grass/execute-results/ipynb.json b/_freeze/content/tutorials/good_looking_plots/good_looking_plots_in_grass/execute-results/ipynb.json new file mode 100644 index 0000000..fab68d9 --- /dev/null +++ b/_freeze/content/tutorials/good_looking_plots/good_looking_plots_in_grass/execute-results/ipynb.json @@ -0,0 +1,11 @@ +{ + "hash": "9eb303253278716d8c235f4273083661", + "result": { + "engine": "jupyter", + "markdown": "---\ntitle: \"Making plots with GRASS\"\nauthor: \"Veronica Andreo\"\ndate: 2024-04-25\ndate-modified: today\nimage: images/making_plots.png\nformat:\n ipynb: default\n html:\n toc: true\n code-tools: true\n code-copy: true\n code-fold: false\ncategories: [statistics, matplotlib, beginner]\nengine: jupyter\nexecute: \n eval: false\n---\n\nIn previous tutorials we saw examples of how to convert GRASS\nraster and vector maps into Python and R objects to perform data \nanalysis and visualizations. \nThere are some GRASS tools, mostly based in the well known \n[matplotlib](https://matplotlib.org/) Python library,\nthat allow us to create plots for data visualization without the\nneed to explicitly convert GRASS data. \nHere are these plotting tools for raster, vector and time series\ndata within GRASS:\n\n| Raster | Vector | Time series |\n|-----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------|\n| [r.boxplot](https://grass.osgeo.org/grass-stable/manuals/addons/r.boxplot.html) | [v.scatterplot](https://grass.osgeo.org/grass-stable/manuals/addons/v.scatterplot.html) | [g.gui.tplot](https://grass.osgeo.org/grass-stable/manuals/g.gui.tplot.html) |\n| [r.series.boxplot](https://grass.osgeo.org/grass-stable/manuals/addons/r.series.boxplot.html) | [v.boxplot](https://grass.osgeo.org/grass-stable/manuals/addons/v.boxplot.html) | [t.rast.boxplot](https://grass.osgeo.org/grass-stable/manuals/addons/t.rast.boxplot.html) |\n| | [v.histogram](https://grass.osgeo.org/grass-stable/manuals/addons/v.histogram.html) | [t.rast.line](https://grass.osgeo.org/grass-stable/manuals/addons/t.rast.line.html) |\n\n\nIn this tutorial, we'll demonstrate their use with maps from the North Carolina\n[full dataset](https://grass.osgeo.org/sampledata/north_carolina/nc_spm_08_grass7.zip). \nWe'll also use a special \n[mapset containing MODIS LST data products](https://grass.osgeo.org/sampledata/north_carolina/nc_spm_mapset_modis2015_2016_lst_grass8.zip)\nto exemplify tools' usage with time series data. While these tools can be invoked \nfrom the GUI menu or Tools tab, we will show how the GRASS commands look like \nso you can run them from the terminal or the Console tab of the GUI. \nWe also show the command wrapping for Python scripts using the grass.script package. \nYou can test them in the Python tab. The use of commands facilitates reproducibility \nand quick testing of small changes and tweaks.\n\n\n## Raster plotting tools\n\n### [r.boxplot](https://grass.osgeo.org/grass-stable/manuals/addons/r.boxplot.html)\n\n`r.boxplot` is a GRASS addon that allows us to make boxplots with our GRASS\nraster maps. It also allows to use a zonal map like a land cover classification \nto draw boxplots of a certain variable per classes, i.e., land cover classes. \nThe tool then contemplates some nice features like the possibility to plot per \nclass boxplots of the same color that the class is assigned in the zonal map or \ncreate a point vector map with the locations of the outliers, among other tweaks. \nLet's see an example using a zonal map, plotting outliers and coloring boxes\nwith the colors of the zonal map classes:\n\n::: {.panel-tabset}\n# Bash\n```{bash}\ng.extension extension=r.boxplot\nr.boxplot -oc map=elevation zones=landclass96 output=r.boxplot.png\n```\n\n# Python\n\n::: {#66df15df .cell execution_count=1}\n``` {.python .cell-code}\ngs.run_command(\"g.extension\", extension=\"r.boxplot\")\ngs.run_command(\"r.boxplot\", \n map=\"elevation\", \n zones=\"landclass96\", \n raster_statistics=\"median,IQR\", \n output=\"r.boxplot.png\",\n flags=\"oc\")\n```\n:::\n\n\n:::\n\n![](images/r.boxplot.png)\n\nFor more examples of the different options available in this addon, see [this tutorial](https://ecodiv.earth/post/drawing-boxplots-of-raster-values/#r.boxplot).\n\n### [r.series.boxplot](https://grass.osgeo.org/grass-stable/manuals/addons/r.series.boxplot.html)\n\n`r.series.boxplot` draws boxplots of a series of input raster maps that might \nrepresent different times, spectral bands in satellite imagery or other kind\nof variation. If users are interested in e.g., ploting the spectral signature\nof different land cover classes, they can alternatively set masks and recreate\nthe boxplot series. Let's see an example for developed and forested classes.\n\n::: {.panel-tabset}\n# Bash\n\n```{bash}\n# install the extension\ng.extension extension=r.series.boxplot\n# add landsat mapset to the list of accessible mapsets\ng.mapsets mapset=landsat operation=add\n# list of maps and labels\nbands=`g.list type=raster pattern=\"lsat7_2000*\" exclude=\"*6*,*8*\" sep=comma`\nlabels=\"band1,band2,band3,band4,band5,band7\"\n\nr.mask raster=landclass96 maskcats=1\nr.series.boxplot map=$bands bxcolor=grey text_labels=$labels output=r.series.boxplot_developed.png\n\nr.mask -r \n\nr.mask raster=landclass96 maskcats=5\nr.series.boxplot map=$bands bxcolor=grey \\\n text_labels=$labels output=r.series.boxplot_forest.png\n```\n\n# Python\n\n::: {#1e6bca01 .cell execution_count=2}\n``` {.python .cell-code}\ngs.run_command(\"g.extension\", extension=\"r.series.boxplot\")\n\ngs.run_command(\"g.mapsets\", mapset=\"landsat\", operation=\"add\")\n\nbands = gs.list_grouped(type=\"raster\", pattern=\"lsat7_2000*\", exclude=\"*6*,*8*\")[\"landsat\"]\nlabels = [\"band1\", \"band2\", \"band3\", \"band4\", \"band5\", \"band7\"]\n\ngs.run_command(\"r.mask\", raster=\"landclass96\", maskcats=\"1\")\ngs.run_command(\"r.series.boxplot\", \n map=bands, \n bxcolor=\"grey\", \n text_labels=labels, \n output=\"r.series.boxplot_developed.png\")\n\ngs.run_command(\"r.mask\", flags=\"r\")\n\ngs.run_command(\"r.mask\", raster=\"landclass96\", maskcats=\"5\")\n\ngs.run_command(\"r.series.boxplot\", \n map=bands, \n bxcolor=\"grey\", \n text_labels=labels, \n output=\"r.series.boxplot_forested.png\")\n```\n:::\n\n\n:::\n\n::: {layout-ncol=2}\n![Class developed](images/r.series.boxplot_developed.png)\n\n![Class forest](images/r.series.boxplot_forested.png)\n:::\n\n\n## Vector plotting tools\n\n### [v.boxplot](https://grass.osgeo.org/grass-stable/manuals/addons/v.boxplot.html)\n\n`v.boxplot` draws the boxplot of values in a vector map attribute column. It \nalso provides an option to group by categories in a second attribute column.\n\n::: {.panel-tabset}\n# Bash\n\n```{bash}\ng.extension extension=v.boxplot\n\nv.boxplot -r map=bridges column=WIDTH group_by=YEAR_BUILT where=\"YEAR_BUILT < '1920'\" order=ascending output=boxplot_bridges_width_per_year.png\n```\n\n# Python\n\n::: {#0496f7e1 .cell execution_count=3}\n``` {.python .cell-code}\ngs.run_command(\"g.extension\", extension=\"v.boxplot\")\n\ngs.run_command(\"v.boxplot\",\n map=\"bridges\", \n column=\"WIDTH\", \n group_by=\"YEAR_BUILT\", \n where=\"YEAR_BUILT < '1920'\", \n order=\"ascending\", \n output=\"boxplot_bridges_width_per_year.png\", \n flags=\"r\")\n```\n:::\n\n\n:::\n\n![](images/boxplot_bridges_width_per_year.png)\n\n\n### [v.scatterplot](https://grass.osgeo.org/grass-stable/manuals/addons/v.scatterplot.html)\n\n`v.scatterplot` creates a scatterplot with the values of two attribute columns \nfrom a vector map. It provides many arguments to control different plot features\nand it exposes some nice matplotlib functionality to do bining, add trend lines\nand confidence ellipses. While there's\n[r.scatterplot](https://grass.osgeo.org/grass-stable/manuals/addons/r.scatterplot.html) \nfor raster data, it does not create a plot but a vector map. \nUsers can, however, sample raster maps with a vector and then create scatterplots \nfrom the sampled data. \n\n::: {.panel-tabset}\n# Bash\n\n```{bash}\ng.extension extension=v.scatterplot\n\nv.scatterplot map=bridges x=YEAR_BUILT y=WIDTH trendline=polynomial degree=1 line_color=red type=density bins=10,10 file_name=scatterplot_bridges_width_vs_year.png\n```\n\n# Python\n\n::: {#7c2d34cb .cell execution_count=4}\n``` {.python .cell-code}\ngs.run_command(\"g.extension\", extension=\"v.scatterplot\")\n\ngs.run_command(\"v.scatterplot\", \n map=\"bridges\", \n x=\"YEAR_BUILT\", \n y=\"WIDTH\", \n trendline=\"polynomial\", \n degree=1, \n line_color=\"red\", \n type=\"density\", \n bins=\"10,10\", \n file_name=\"scatterplot_bridges_width_vs_year.png\")\n```\n:::\n\n\n:::\n\n![](images/scatterplot_bridges_width_vs_year.png)\n\n### [v.histogram](https://grass.osgeo.org/grass-stable/manuals/addons/v.histogram.html)\n\n`v.histogram` draws a histogram of the values in a vector map attribute column.\nThe tool provides basic options to select values according to a condition and \nset the number of bins. \n\n::: {.panel-tabset}\n# Bash\n\n```{bash}\ng.extension extension=v.histogram\n\nv.histogram map=bridges column=WIDTH where=\"YEAR_BUILT < '1940'\" plot_output=histogram_bridges_width.png\n```\n\n# Python\n\n::: {#cd491a32 .cell execution_count=5}\n``` {.python .cell-code}\ngs.run_command(\"g.extension\", extension=\"v.histogram\")\n\ngs.run_command(\"v.histogram\", \n map=\"bridges\", \n column=\"WIDTH\", \n where=\"YEAR_BUILT < '1940'\", \n plot_output=\"histogram_bridges_width.png\")\n```\n:::\n\n\n:::\n\n![](images/histogram_bridges_width.png)\n\n## Time series plotting tools\n\n### [g.gui.tplot](https://grass.osgeo.org/grass-stable/manuals/g.gui.tplot.html)\n\n`g.gui.tplot` is part of GRASS core distribution and it allows to plot the \nvalues of raster and vector time series. Users can pass coordinate pairs for the\ncase of raster time series and ids plus attribute column in the case of vector\ntime series. The module also supports to display the trend line based on a linear\nregression and the R-squared value, visualize pop-up annotations, export the time\nseries values to a text file, among other. Let's see an example for the MODIS\nLSD DAY monthly raster time series.\n\n::: {.panel-tabset}\n# Bash\n\n```{bash}\ng.region -p raster=MOD11B3.A2015001.h11v05.single_LST_Day_6km\ng.gui.tplot -l strds=LST_Day_monthly coordinates=413831,196000 xlabel=\"Time\" ylabel=\"LST (K*50)\" output=LST_plot.png size=1000,800\n```\n\n# Python\n\n::: {#1d5dafce .cell execution_count=6}\n``` {.python .cell-code}\ngs.read_command(\"g.region\", \n raster=\"MOD11B3.A2015001.h11v05.single_LST_Day_6km\")\n \ngs.run_command(\"g.gui.tplot\", \n strds=\"LST_Day_monthly\", \n coordinates=\"413831,196000\", \n xlabel=\"Time\", \n ylabel=\"LST (K*50)\", \n output=\"LST_plot.png\", \n size=\"1000,800\", \n flags=\"l\")\n```\n:::\n\n\n:::\n\n![](images/LST_plot.png)\n\n\n### [t.rast.boxplot](https://grass.osgeo.org/grass-stable/manuals/addons/t.rast.boxplot.html)\n\n`t.rast.boxplot` draws boxplots from raster maps in a space-time raster dataset,\nhence the x axis is determined by the STRDS temporal granularity, i.e., day, week,\nmonth, etc. Let's see an example for plotting monthly LST within the state of North\nCarolina.\n\n::: {.panel-tabset}\n# Bash\n\n```{bash}\ng.extension extension=t.rast.boxplot\ng.region -p vector=boundary_county align=MOD11B3.A2015001.h11v05.single_LST_Day_6km\nr.mask vector=boundary_county\nt.rast.boxplot -o input=LST_Day_monthly dpi=300 rotate_labels=90 font_size=11 date_format=\"%Y-%m\" bx_width=0.7 bx_color=195:194:194:255 flier_color=77:77:77:255\n```\n\n# Python\n\n::: {#25d1db2f .cell execution_count=7}\n``` {.python .cell-code}\ngs.run_command(\"g.extension\", extension=\"t.rast.boxplot\")\n\ngs.read_command(\"g.region\", vector=\"boundary_county\", align=\"MOD11B3.A2015001.h11v05.single_LST_Day_6km\")\n\ngs.run_command(\"r.mask\", vector=\"boundary_county\")\n\ngs.run_command(\"t.rast.boxplot\", \n input=\"LST_Day_monthly\", \n dpi=\"300\", \n rotate_labels=90, \n font_size=11, \n date_format=\"%Y-%m\", \n bx_width=0.7, \n bx_color=\"195:194:194:255\", \n flier_color=\"77:77:77:255\", \n flags=\"o\")\n```\n:::\n\n\n:::\n\n![](images/t.rast.boxplot_LST_NC.png)\n\nIf users would like to compare boxplot time series representing different areas, \nthey could alternatively set masks for their areas of interest and then create \nthe respective boxplot time series.\n\n::: {.panel-tabset}\n# Bash\n\n```{bash}\nr.mask vector=geology where=\"GEO_NAME LIKE '%Zat%'\"\nt.rast.boxplot -o input=LST_Day_monthly dpi=300 rotate_labels=90 font_size=11 date_format=\"%Y-%m\" bx_width=0.7 bx_color=195:194:194:255 flier_color=77:77:77:255\n\nr.mask -r\n\nr.mask vector=geology where=\"GEO_NAME LIKE '%Qp%'\"\nt.rast.boxplot -o input=LST_Day_monthly dpi=300 rotate_labels=90 font_size=11 date_format=\"%Y-%m\" bx_width=0.7 bx_color=195:194:194:255 flier_color=77:77:77:255\n```\n\n# Python\n\n::: {#2c01a755 .cell execution_count=8}\n``` {.python .cell-code}\ngs.run_command(\"r.mask\", vector=\"geology\", where=\"GEO_NAME LIKE '%Zat%'\")\n\ngs.run_command(\"t.rast.boxplot\", \n input=\"LST_Day_monthly\", \n dpi=300, \n rotate_labels=90, \n font_size=11, \n date_format=\"%Y-%m\", \n bx_width=0.7, \n bx_color=\"195:194:194:255\", \n flier_color=\"77:77:77:255\", \n flags=\"o\")\n\ngs.run_command(\"r.mask\", flags=\"r\")\n\ngs.run_command(\"r.mask\", vector=\"geology\", where=\"GEO_NAME LIKE '%Qp%'\")\n\ngs.run_command(\"t.rast.boxplot\", \n input=\"LST_Day_monthly\", \n dpi=300, \n rotate_labels=90, \n font_size=11, \n date_format=\"%Y-%m\", \n bx_width=0.7, \n bx_color=\"195:194:194:255\", \n flier_color=\"77:77:77:255\", \n flags=\"o\")\n```\n:::\n\n\n:::\n\n### [t.rast.line](https://grass.osgeo.org/grass-stable/manuals/addons/t.rast.line.html)\n\n`t.rast.line` draws line plots from raster maps in a space-time raster dataset and \nalso allows to pass a zonal map to compare average temporal changes of different \nareas of interest in the same plot.\n\n::: {.panel-tabset}\n# Bash\n\n```{bash}\ng.extension extension=t.rast.line\nt.rast.line input=LST_Day_monthly zones=boundary_county_500m y_label=\"LST (K*50)\" date_format=%Y-%m\n```\n\n# Python\n\n::: {#a51ab24a .cell execution_count=9}\n``` {.python .cell-code}\ngs.run_command(\"g.extension\", extension=\"t.rast.line\")\n\ngs.run_command(\"t.rast.line\", \n input=\"LST_Day_monthly\", \n zones=\"boundary_county_500m\", \n y_label=\"LST (K*50)\", \n date_format=\"%Y-%m\")\n```\n:::\n\n\n:::\n\n![](images/t.rast.line_LST_NC_counties.png)\n\n---\njupyter:\n kernelspec:\n display_name: Python 3 (ipykernel)\n language: python\n name: python3\n path: /home/coreywhite/.local/share/jupyter/kernels/python3\n language_info:\n codemirror_mode:\n name: ipython\n version: 3\n file_extension: .py\n mimetype: text/x-python\n name: python\n nbconvert_exporter: python\n pygments_lexer: ipython3\n version: 3.10.12\n---\n", + "supporting": [ + "good_looking_plots_in_grass_files" + ], + "filters": [] + } +} \ No newline at end of file diff --git a/_freeze/content/tutorials/r_python_interfaces_comparison/quick_comparison_r_vs_python_grass_interfaces/execute-results/ipynb.json b/_freeze/content/tutorials/r_python_interfaces_comparison/quick_comparison_r_vs_python_grass_interfaces/execute-results/ipynb.json new file mode 100644 index 0000000..3f849a0 --- /dev/null +++ b/_freeze/content/tutorials/r_python_interfaces_comparison/quick_comparison_r_vs_python_grass_interfaces/execute-results/ipynb.json @@ -0,0 +1,15 @@ +{ + "hash": "0e94abd57cedf73a009f080503d52c11", + "result": { + "engine": "knitr", + "markdown": "---\ntitle: \"Quick comparison: R and Python GRASS interfaces\"\nauthor: \"Veronica Andreo\"\ndate: 2024-04-01\ndate-modified: today\nformat:\n ipynb: default\n html:\n toc: true\n code-tools: true\n code-copy: true\n code-fold: false\ncategories: [Python, R, intermediate]\nengine: knitr\nexecute:\n eval: false\n---\n\n![](images/R_Python_compare.png){.preview-image width=50%}\n\nIn this short tutorial we will highlight the similarities of R and Python GRASS interfaces\nin order to streamline the use of GRASS within R and Python communities.\nAs you may know, there's\nan R package called [rgrass](https://github.com/OSGeo/rgrass/) that provides\nbasic functionality to read and write data from and into GRASS database as well\nas to execute GRASS tools in either existing or temporary GRASS projects.\nThe [GRASS Python API](https://grass.osgeo.org/grass-stable/manuals/libpython/index.html),\non the other hand, is composed of various packages that provide classes and\nfunctions for low and high level tasks, including those that can be executed\nwith rgrass.\n\n\n\nThere are some parallelisms between the\n**rgrass** and **grass.script**/**grass.jupyter** packages, i.e.,\nR and Python interfaces to GRASS.\nLet's review them and go through some examples.\n\n\n| Task | rgrass function | GRASS Python API function |\n|------------------------------------------------------------|--------------------------------|---------------------------------------------------------|\n| Load library | library(rgrass) | import grass.script as gs
import grass.jupyter as gj |\n| Start GRASS and set all needed
environmental variables | initGRASS() | gs.setup.init() for scripts,
gj.init() for notebooks |\n| Execute GRASS commands | execGRASS() | gs.run_command(),
gs.read_command(),
gs.parse_command() |\n| Read raster and vector data
from GRASS | read_RAST(),
read_VECT() | gs.array.array(),
n/a |\n| Write raster and vector data
into GRASS | write_RAST(),
write_VECT() | gs.array.write(),
n/a |\n| Get raster and vector info | n/a,
vInfo() | gs.raster_info(),
gs.vector_info() |\n| Close GRASS session | unlink_.gislock() | gs.setup.finish(),
gj.finish() |\n\n: R and Python GRASS interfaces compared {.striped .hover}\n\n## Comparison examples\n\nLet's see how usage examples would look like.\n\n1. **Load the library**: We need to\nload the libraries that allow us to interface with GRASS\nfunctionality and (optionally) data. For the Python case, we first need to add\nthe GRASS python package path to our system's path.\n\n::: {.panel-tabset}\n\n## R\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(rgrass)\n```\n:::\n\n\n## Python\n\n\n::: {.cell python.reticulate='false'}\n\n```{.python .cell-code}\nimport sys\nimport subprocess\n\nsys.path.append(\n subprocess.check_output([\"grass\", \"--config\", \"python_path\"], text=True).strip()\n)\n\nimport grass.script as gs\nimport grass.jupyter as gj\n```\n:::\n\n\n:::\n\n2. **Start a GRASS session**: Once we loaded or imported the packages, we\nstart a GRASS session. We need to pass the path to a\ntemporary or existing GRASS project.\nIn the case of R, `initGRASS` will automatically look for GRASS binaries, alternatively we can\nspecify the path to the binaries ourselves.\nIn the case of Python, it is worth noting that while grass.script and grass.jupyter init functions\ntake the same arguments, `gj.init` also sets other environmental variables to\nstreamline work within Jupyter Notebooks, e.g., overwrite is set to true so cells\ncan be executed multiple times.\n\n::: {.panel-tabset}\n\n## R\n\n\n::: {.cell}\n\n```{.r .cell-code}\nsession <- initGRASS(gisBase = \"/usr/lib/grass84\", # where grass binaries live, `grass --config path`\n gisDbase = \"/home/user/grassdata\", # path to grass database or folder where your project lives\n location = \"nc_basic_spm_grass7\", # existing project name\n mapset = \"PERMANENT\" # mapset name\n )\n```\n:::\n\n\n## Python\n\n\n::: {.cell python.reticulate='false'}\n\n```{.python .cell-code}\n# With grass.script for scripts\nsession = gs.setup.init(path=\"/home/user/grassdata\",\n location=\"nc_basic_spm_grass7\",\n mapset=\"PERMANENT\")\n# Optionally, the path to a mapset\nsession = gs.setup.init(\"/home/user/grassdata/nc_basic_spm_grass7/PERMANENT\")\n\n# With grass.jupyter for notebooks\nsession = gj.init(path=\"/home/user/grassdata\",\n location=\"nc_basic_spm_grass7\",\n mapset=\"PERMANENT\")\n# Optionally, the path to a mapset\nsession = gj.init(\"~/grassdata/nc_basic_spm_grass7/PERMANENT\")\n```\n:::\n\n\n:::\n\n3. **Execute GRASS commands**: Both interfaces work pretty similarly, the\nfirst argument is always the GRASS tool name and then we pass the parameters\nand flags. While in R we basically use `execGRASS()` for all GRASS commands, in\nthe Python API, we have different wrappers to execute GRASS commands depending\non the nature of their output.\n\n::: {.panel-tabset}\n\n## R\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Map output\nexecGRASS(\"r.slope.aspect\",\n elevation = \"elevation\",\n slope = \"slope\",\n aspect = \"aspect\")\n\n# Text output\nexecGRASS(\"g.region\",\n raster = \"elevation\",\n flags = \"p\")\n```\n:::\n\n\n## Python\n\n\n::: {.cell python.reticulate='false'}\n\n```{.python .cell-code}\n# Map output\ngs.run_command(\"r.slope.aspect\",\n elevation=\"elevation\",\n slope=\"slope\",\n aspect=\"aspect\")\n# Text output\nprint(gs.read_command(\"g.region\",\n raster=\"elevation\",\n flags=\"p\"))\n# Text output - dictionary\nregion = gs.parse_command(\"g.region\",\n raster=\"elevation\",\n flags=\"g\")\nregion\n```\n:::\n\n\n:::\n\n4. **Read raster and vector data into other R or Python formats**:\n*rgrass* functions `read_RAST()` and `read_VECT()` convert GRASS raster and\nvector maps into terra's SpatRaster and SpatVector objects within R.\nIn the case of Python, GRASS\nraster maps that can be converted into numpy arrays through\n`gs.array.array()`. Vector attribute data can be converted into\nPandas data frames in various ways.\n\n::: {.panel-tabset}\n\n## R\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Raster\nelevr <- read_RAST(\"elevation\")\n\n# Vector\nschoolsr <- read_VECT(\"schools\")\n```\n:::\n\n\n## Python\n\n\n::: {.cell python.reticulate='false'}\n\n```{.python .cell-code}\n# Raster into numpy array\nelev = gs.array.array(\"elevation\")\n\n# Vector attributes\nimport pandas as pd\nschools = gs.parse_command(\"v.db.select\", map=\"schools\", format=\"json\")\npd.DataFrame(schools[\"records\"])\n\n# Vector geometry and attributes to GeoJSON\ngs.run_command(\"v.out.ogr\", input=\"schools\", output=\"schools.geojson\", format=\"GeoJSON\")\n```\n:::\n\n\n:::\n\n\n5. **Write R or Python objects into GRASS raster and vector maps**: R terra's\nSpatRaster and SpatVector objects can be written (back) into GRASS format with\n`write_RAST()` and `write_VECT()` functions. Within the Python environment,\nnumpy arrays can also be written (back) into GRASS raster maps with the\n`write()` method.\n\n::: {.panel-tabset}\n\n## R\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Raster\nwrite_RAST(elevr, \"elevation_r\")\n\n# Vector\nwrite_VECT(schoolsr, \"schools_r\")\n```\n:::\n\n\n## Python\n\n\n::: {.cell python.reticulate='false'}\n\n```{.python .cell-code}\n# Raster\nelev.write(mapname=\"elev_np\", overwrite=True)\n\n# GeoJSON into GRASS vector\ngs.run_command(\"v.in.ogr\", input=\"schools.geojson\", output=\"schools2\")\n```\n:::\n\n\n:::\n\n\n6. **Close GRASS session**: In general, just closing R or Rstudio, as well\nas shutting down Jupyter notebook, will clean up and close the GRASS session\nproperly. Sometimes, however, especially if the user changed mapset within the\nworkflow, it is better to clean up explicitly before closing.\n\n::: {.panel-tabset}\n\n## R\n\n\n::: {.cell}\n\n```{.r .cell-code}\nunlink_.gislock()\n```\n:::\n\n\n## Python\n\n\n::: {.cell python.reticulate='false'}\n\n```{.python .cell-code}\nsession.finish()\n```\n:::\n\n\n:::\n\n## Final remarks\n\nThe examples and comparisons presented here are intended to facilitate the\ncombination of tools and languages as well as the exchange of data and format\nconversions. We hope that's useful as a starting point for the implementation\nof different use cases and workflows that suit the needs of users.\nSee R and Python tutorials for more examples:\n\n* [GRASS and Python tutorial for beginners](../get_started/fast_track_grass_and_python.qmd)\n* [GRASS and R tutorial for beginners](../get_started/fast_track_grass_and_R.qmd)\n\n## References\n\n* [GRASS Python API docs](https://grass.osgeo.org/grass-stable/manuals/libpython/index.html)\n* [rgrass docs](https://osgeo.github.io/rgrass/)\n\n\n***\n\n:::{.smaller}\nThe development of this tutorial was funded by the US\n[National Science Foundation (NSF)](https://www.nsf.gov/),\naward [2303651](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2303651).\n:::\n", + "supporting": [], + "filters": [ + "rmarkdown/pagebreak.lua" + ], + "includes": {}, + "engineDependencies": {}, + "preserve": null, + "postProcess": false + } +} \ No newline at end of file diff --git a/_quarto-local.yml b/_quarto-local.yml new file mode 100644 index 0000000..1beacd4 --- /dev/null +++ b/_quarto-local.yml @@ -0,0 +1,5 @@ +project: + type: website + title: "(Local) Learn GRASS" + render: + - "content/tests/*.qmd" \ No newline at end of file diff --git a/_quarto-production.yml b/_quarto-production.yml new file mode 100644 index 0000000..dcf9ef8 --- /dev/null +++ b/_quarto-production.yml @@ -0,0 +1,6 @@ +project: + render: + - "*.qmd" + - "!content/tests/" +execute: + freeze: false \ No newline at end of file diff --git a/_quarto.yml b/_quarto.yml index 42dddab..ce00cbc 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -1,13 +1,16 @@ project: type: website output-dir: docs + render: + - "*.qmd" website: - favicon: images/logos/grass-favicon-16x16.png + site-url: "https://grass-tutorials.osgeo.org" + favicon: images/favicon.ico + twitter-card: true + open-graph: true navbar: - title: "Learn GRASS" - background: primary + title: Learn GRASS search: true - logo: "images/logos/grass-favicon-white-32x32.png" tools: - icon: github menu: @@ -20,30 +23,49 @@ website: Partially supported by US NSF [![](/images/logos/NSF_Official_logo_100x100.png){fig-alt="NSF" width=45px}](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2303651) center: Content is dual-licensed under [GFDL-1.2-or-later](https://www.gnu.org/licenses/fdl-1.2.html) and [CC-BY-SA-4.0](https://creativecommons.org/licenses/by-sa/4.0/) + # Quarto does not support the icon tag to use FontAwesome. + # The workaround is to use the fa icon in the text. + # We do this for consistency with the rest of the sites. + # https://github.com/quarto-ext/fontawesome/issues/6 right: - - icon: github - href: https://github.com/OSGeo/grass - aria-label: GRASS on GitHub - - icon: chat-fill - href: https://discourse.osgeo.org/c/grass/62 - aria-label: GRASS on Discourse - - icon: mastodon + - icon: opencollective + href: https://opencollective.com/grass/contribute + aria-label: GRASS on Open Collective + - text: "{{< fa brands gitter >}}" + href: https://gitter.im/grassgis/community + aria-label: GRASS on Gitter + - text: "{{< fa brands mastodon >}}" href: https://fosstodon.org/@grassgis aria-label: GRASS on Mastodon - - icon: twitter-x + - text: "{{< fa brands discourse >}}" + href: https://discourse.osgeo.org/c/grass/62 + aria-label: GRASS on Discourse + - text: "{{< fa brands linkedin >}}" + href: "https://linkedin.com/company/grass-gis" + aria-label: GRASS on LinkedIn + - text: "{{< fa brands x-twitter >}}" href: https://x.com/grassgis aria-label: GRASS on X - - icon: facebook - href: https://www.facebook.com/groups/GRASS - aria-label: GRASS on Facebook - - icon: youtube + - text: "{{< fa brands youtube >}}" href: https://www.youtube.com/@grass-gis aria-label: GRASS on YouTube + - text: "{{< fa brands github >}}" + href: https://github.com/OSGeo/grass + aria-label: GRASS on GitHub + + margin-header : | + [{{< fa heart >}} Support GRASS]({{< var grass.support >}}){.btn .btn-outline-support .btn role="button" align="center"} + execute: freeze: auto format: html: - theme: [pandoc, theme.scss] + theme: [pandoc, brand, theme.scss] toc: true toc-title: Table of Contents link-external-newwindow: true + +brand: _brand.yml +profile: + default: local + \ No newline at end of file diff --git a/_variables.yml b/_variables.yml new file mode 100644 index 0000000..4e4e691 --- /dev/null +++ b/_variables.yml @@ -0,0 +1,23 @@ +grass: + name: GRASS + version: 8.4 + website: https://grass.osgeo.org + support: https://opencollective.com/grass/contribute + description: Bringing advanced geospatial technologies to the world + founded: 1984 + docs: + website: https://grass.osgeo.org/grass-stable/manuals/ + logos: + green: images/logos/large/grass-green.svg + white: images/logos/large/grass-white.svg + gradient: images/logos/large/grass-gradient.svg + horizontal: + green: images/logos/large/grass-green-horizontal.svg + white: images/logos/large/grass-white-horizontal.svg + gradient: images/logos/large/grass-gradient-horizontal.svg + # GRASS icon only without text + icons: + green: images/logos/large/grass-green-no-text.svg + white: images/logos/large/grass-white-no-text.svg + gradient: images/logos/large/grass-gradient-no-text.svg + diff --git a/content/include/_support-button.qmd b/content/include/_support-button.qmd new file mode 100644 index 0000000..4c0b2a5 --- /dev/null +++ b/content/include/_support-button.qmd @@ -0,0 +1,2 @@ + +[{{< fa heart >}} Support]({{< var grass.support >}}){.btn .btn-support .btn role="button"} \ No newline at end of file diff --git a/content/include/_support-outline-button.qmd b/content/include/_support-outline-button.qmd new file mode 100644 index 0000000..cb3a32a --- /dev/null +++ b/content/include/_support-outline-button.qmd @@ -0,0 +1 @@ +[{{< fa heart >}} Support]({{< var grass.support >}}){.btn .btn-outline-support .btn role="button"} \ No newline at end of file diff --git a/content/tests/images/LinkedIn-Post-Image.png b/content/tests/images/LinkedIn-Post-Image.png new file mode 100644 index 0000000..b82dfaa Binary files /dev/null and b/content/tests/images/LinkedIn-Post-Image.png differ diff --git a/content/tests/listing.qmd b/content/tests/listing.qmd new file mode 100644 index 0000000..a23b5a1 --- /dev/null +++ b/content/tests/listing.qmd @@ -0,0 +1,9 @@ +--- +title: Test Listing +description: This listing is used to visualize listing styles in styling.qmd +author: GRASS Developer Team +categories: ["grass", "design", "test"] +data: today +profile: local +image: images/LinkedIn-Post-Image.png +--- \ No newline at end of file diff --git a/content/tests/styling.qmd b/content/tests/styling.qmd new file mode 100644 index 0000000..87696df --- /dev/null +++ b/content/tests/styling.qmd @@ -0,0 +1,1034 @@ +--- +title: GRASS Quarto Design Guide +description: Adopted from Quarto Documentation +image: images/LinkedIn-Post-Image.png +title-block-banner: true +author: + - name: Corey White + - name: Sarah White +date: May 5, 2025 +date-modified: today +categories: ['design', 'guide', 'styling'] +format: + html: + other-links: + - text: GRASS Website + href: https://grass.osgeo.org + - text: Quarto + href: https://quarto.org/ + code-links: + - text: Data Import Code + icon: file-code + href: data-import.py + notebook-links: inline + code-tools: true + code-copy: true + code-fold: true + code-summary: "Show the code" + code-overflow: wrap +profile: local +toc: true +toc-depth: 3 +listing: + - id: lab-reports + contents: "*.qmd" + type: table + - id: meeting-notes + contents: "*.qmd" + type: grid + - id: default-notes + contents: "*.qmd" + type: default +citation: + type: article-journal + container-title: GRASS + volume: 1 + issue: 1 + issued: 2025-05 + issn: 0000-0000 + doi: 10.0000/0000000 +execute: + eval: true + echo: true + output: true +--- + +# Components Showcase + +This document demonstrates various components available in Quarto. + +## Headings + +Heading 1 is bolded and used as the title of the page. + +# Heading 1 + +```md +# Heading 1 +``` + +Heading 2 is thined and used to introduce a new section or topic within a page. + +## Heading 2 +```md +## Heading 2 +``` + +Heading 3 is bolded and used to introduce a new subsection or subtopic within a page. + +### Heading 3 + +```md +### Heading 3 +``` + +Headings 4, 5 and 6 are inceasing smaller and can be used as need after heading 3. + +#### Heading 4 +##### Heading 5 +###### Heading 6 + +```md +#### Heading 4 +##### Heading 5 +###### Heading 6 +``` + +> All heading are enforced as **sentence case**. + +## Text Formatting + +**Bold Text** +*Italic Text* +~~Strikethrough~~ +`Inline Code` + +superscript^2^ / subscript~2~ + +```md +**Bold Text** +*Italic Text* +~~Strikethrough~~ +`Inline Code` + +superscript^2^ / subscript~2~ +``` + +## Lists + +### Ordered List +1. First item +2. Second item +3. Third item + +```md +1. First item +2. Second item +3. Third item +``` + +### Unordered List +- Item 1 +- Item 2 +- Item 3 + +```md +- Item 1 +- Item 2 +- Item 3 +``` + +* unordered list + + sub-item 1 + + sub-item 2 + - sub-sub-item 1 + +```md +* unordered list + + sub-item 1 + + sub-item 2 + - sub-sub-item 1 +``` + +* item 2 + + Continued (indent 4 spaces) + +```md +* item 2 + + Continued (indent 4 spaces) +``` + +(@) A list which numbering + +continues after + +(@) an interruption + +```md +(@) A list which numbering + +continues after + +(@) an interruption +``` + +### Tasks + +- [ ] Task 1 +- [x] Task 2 + +```md +- [ ] Task 1 +- [x] Task 2 +``` + +## Blockquotes + +### `>` Blockquote + +> This is a blockquote. +> It can span multiple lines. + +```md +> This is a blockquote. +> It can span multiple lines. +``` + +### Line Block + +| Line Block +| Spaces and newlines +| are preserved + +```md +| Line Block +| Spaces and newlines +| are preserved +``` + +## Footnotes + +Here is a footnote reference,[^1] and another.[^longnote] + +[^1]: Here is the footnote. + +[^longnote]: Here's one with multiple blocks. + + Subsequent paragraphs are indented to show that they +belong to the previous footnote. + + { some.code } + + The whole paragraph can be indented, or just the first + line. In this way, multi-paragraph footnotes work like + multi-paragraph list items. + +This paragraph won't be part of the note, because it +isn't indented. + +Here is an inline note.^[Inlines notes are easier to write, +since you don't have to pick an identifier and move down to +type the note.] + +```md +Here is a footnote reference,[^1] and another.[^longnote] + +[^1]: Here is the footnote. + +[^longnote]: Here's one with multiple blocks. + + Subsequent paragraphs are indented to show that they +belong to the previous footnote. + + { some.code } + + The whole paragraph can be indented, or just the first + line. In this way, multi-paragraph footnotes work like + multi-paragraph list items. + +This paragraph won't be part of the note, because it +isn't indented. + +Here is an inline note.^[Inlines notes are easier to write, +since you don't have to pick an identifier and move down to +type the note.] +``` + +## Tables + +### Default + +| Header 1 | Header 2 | Header 3 | +|----------|----------|----------| +| Row 1 | Data 1 | Data 2 | +| Row 2 | Data 3 | Data 4 | + +```md +| Header 1 | Header 2 | Header 3 | +|----------|----------|----------| +| Row 1 | Data 1 | Data 2 | +| Row 2 | Data 3 | Data 4 | +``` + +### Column Aligned + +| Default | Left | Right | Center | +|---------|:-----|------:|:------:| +| 12 | 12 | 12 | 12 | +| 123 | 123 | 123 | 123 | +| 1 | 1 | 1 | 1 | + +```md +| Default | Left | Right | Center | +|---------|:-----|------:|:------:| +| 12 | 12 | 12 | 12 | +| 123 | 123 | 123 | 123 | +| 1 | 1 | 1 | 1 | +``` + +### Pipe Format + + +fruit| price +-----|-----: +apple|2.05 +pear|1.37 +orange|3.09 + +: Demonstration of pipe table syntax + +```md +fruit| price +-----|-----: +apple|2.05 +pear|1.37 +orange|3.09 + +: Demonstration of pipe table syntax +``` + +### Pipe Format Striped + +| fruit | price | +|--------|--------| +| apple | 2.05 | +| pear | 1.37 | +| orange | 3.09 | + +: Fruit prices {.striped .hover} + +```md +| fruit | price | +|--------|--------| +| apple | 2.05 | +| pear | 1.37 | +| orange | 3.09 | + +: Fruit prices {.striped .hover} +``` + +### Pipe Format Custom Col widths + +| fruit | price | +|--------|--------| +| apple | 2.05 | +| pear | 1.37 | +| orange | 3.09 | + +: Fruit prices {tbl-colwidths="[75,25]"} + +```md +| fruit | price | +|--------|--------| +| apple | 2.05 | +| pear | 1.37 | +| orange | 3.09 | + +: Fruit prices {tbl-colwidths="[75,25]"} +``` + +### Grid Table + ++-----------+-----------+--------------------+ +| Fruit | Price | Advantages | ++===========+===========+====================+ +| Bananas | $1.34 | - built-in wrapper | +| | | - bright color | ++-----------+-----------+--------------------+ +| Oranges | $2.10 | - cures scurvy | +| | | - tasty | ++-----------+-----------+--------------------+ + +: Sample grid table. + +```md ++-----------+-----------+--------------------+ +| Fruit | Price | Advantages | ++===========+===========+====================+ +| Bananas | $1.34 | - built-in wrapper | +| | | - bright color | ++-----------+-----------+--------------------+ +| Oranges | $2.10 | - cures scurvy | +| | | - tasty | ++-----------+-----------+--------------------+ + +: Sample grid table. +``` + +## Cross Reference + +| Col1 | Col2 | Col3 | +|------|------|------| +| A | B | C | +| E | F | G | +| A | G | G | + +: My Caption {#tbl-letters} + +See @tbl-letters. + +```md +| Col1 | Col2 | Col3 | +|------|------|------| +| A | B | C | +| E | F | G | +| A | G | G | + +: My Caption {#tbl-letters} + +See @tbl-letters. +``` + +### Subtables + +::: {#tbl-panel layout-ncol=2} +| Col1 | Col2 | Col3 | +|------|------|------| +| A | B | C | +| E | F | G | +| A | G | G | + +: First Table {#tbl-first} + +| Col1 | Col2 | Col3 | +|------|------|------| +| A | B | C | +| E | F | G | +| A | G | G | + +: Second Table {#tbl-second} + +Main Caption +::: + +See @tbl-panel for details, especially @tbl-second. + +```md +::: {#tbl-panel layout-ncol=2} +| Col1 | Col2 | Col3 | +|------|------|------| +| A | B | C | +| E | F | G | +| A | G | G | + +: First Table {#tbl-first} + +| Col1 | Col2 | Col3 | +|------|------|------| +| A | B | C | +| E | F | G | +| A | G | G | + +: Second Table {#tbl-second} + +Main Caption +::: + +See @tbl-panel for details, especially @tbl-second. +``` + +## Links & Images + +### Links + +[GRASS Website]({{< var grass.website >}}) + +```md +[GRASS Website]({{< var grass.website >}}) +``` + +### Images + +![Width 25%]({{< var grass.logos.horizontal.gradient >}}){width=25%} + +```md +![Width 25%]({{< var grass.logos.horizontal.gradient >}}){width=25%} +``` + +![Width 50%]({{< var grass.logos.horizontal.gradient >}}){width=50%} + +```md +![Width 50%]({{< var grass.logos.horizontal.gradient >}}){width=50%} +``` + +![Width 75%]({{< var grass.logos.horizontal.gradient >}}){width=75%} + +```md +![Width 75%]({{< var grass.logos.horizontal.gradient >}}){width=75%} +``` + +![Width 100%]({{< var grass.logos.horizontal.gradient >}}){width=100%} + +```md +![Width 100%]({{< var grass.logos.horizontal.gradient >}}){width=100%} +``` + +### Image Link + +[![Caption]({{< var grass.logos.gradient >}}){width=20%}]({{< var grass.website >}}) + +```md +[![Caption]({{< var grass.logos.gradient >}}){width=20%}]({{< var grass.website >}}) +``` + +### Image Link with Alt-Text +[![Caption]({{< var grass.logos.gradient >}} "Alt text"){width=20%}]({{< var grass.website >}}) + +```md +[![Caption]({{< var grass.logos.gradient >}} "Alt text"){width=20%}]({{< var grass.website >}}) +``` + +### Aligned Images + +![Aligned Left]({{< var grass.logos.gradient >}} "Alt text"){width=20% fig-align="left"} +![Aligned Right]({{< var grass.logos.gradient >}} "Alt text"){width=20% fig-align="right"} + +```md +![Aligned Left]({{< var grass.logos.gradient >}} "Alt text"){width=20% fig-align="left"} +![Aligned Right]({{< var grass.logos.gradient >}} "Alt text"){width=20% fig-align="right"} +``` + +### Lightbox +![Lightbox]({{< var grass.logos.gradient >}} "Alt text"){width=20% fig-align="center" .lightbox} + +```md +![Lightbox]({{< var grass.logos.gradient >}} "Alt text"){width=20% fig-align="center" .lightbox} +``` + +### Placeholders + +{{< placeholder 400 200 format=svg >}} + +```md + +{{< placeholder 400 200 format=svg >}} +``` + +## Callouts + +Note that there are five types of callouts, including: +`note`, `tip`, `warning`, `caution`, and `important`. + +### Note + +::: {.callout-note} +This is a note callout. +::: + +```md +::: {.callout-note} +This is a note callout. +::: +``` + +### Tip + +::: {.callout-tip} +This is a tip callout. +::: + +```md +::: {.callout-tip} +This is a tip callout. +::: +``` + +### Warning + +::: {.callout-warning} +This is a warning callout. +::: + +```md +::: {.callout-warning} +This is a warning callout. +::: +``` + +### Important + +::: {.callout-important} +This is an important callout. +::: + +```md +::: {.callout-important} +This is an important callout. +::: +``` + +### Caution + +::: {.callout-caution} +This is a caution callout. +::: + +```md +::: {.callout-caution} +This is a caution callout. +::: +``` + +### Collapsable Callout + +::: {.callout-caution collapse="true"} +## Expand To Learn About Collapse +This is a caution callout. +::: + +```md +::: {.callout-caution collapse="true"} +## Expand To Learn About Collapse +This is a caution callout. +::: +``` + +## Math + +### Inline +Inline math: $E = mc^2$ + +### Block + +Block math: +$$ +\int_a^b f(x) dx = F(b) - F(a) +$$ + +## Buttons + +### Solid Color + +[Primary](#){.btn .btn-primary .btn role="button"} +[Secondary](#){.btn .btn-secondary .btn role="button"} +[Success](#){.btn .btn-success .btn role="button"} +[Danger](#){.btn .btn-danger .btn role="button"} +[Warning](#){.btn .btn-warning .btn role="button"} +[Info](#){.btn .btn-info .btn role="button"} +[Light](#){.btn .btn-light .btn role="button"} +[Dark](#){.btn .btn-dark .btn role="button"} +[Link](#){.btn .btn-link .btn role="button"} + + + +```md +[Primary](#){.btn .btn-primary .btn role="button"} +[Secondary](#){.btn .btn-secondary .btn role="button"} +[Success](#){.btn .btn-success .btn role="button"} +[Danger](#){.btn .btn-danger .btn role="button"} +[Warning](#){.btn .btn-warning .btn role="button"} +[Info](#){.btn .btn-info .btn role="button"} +[Light](#){.btn .btn-light .btn role="button"} +[Dark](#){.btn .btn-dark .btn role="button"} +[Link](#){.btn .btn-link .btn role="button"} +``` + +### Outline Color + +[Primary Outline](#){.btn .btn-outline-primary .btn role="button"} +[Secondary Outline](#){.btn .btn-outline-secondary .btn role="button"} +[Success Outline](#){.btn .btn-outline-success .btn role="button"} +[Danger Outline](#){.btn .btn-outline-danger .btn role="button"} +[Warning Outline](#){.btn .btn-outline-warning .btn role="button"} +[Info Outline](#){.btn .btn-outline-info .btn role="button"} +[Light Outline](#){.btn .btn-outline-light .btn role="button"} +[Dark Outline](#){.btn .btn-outline-dark .btn role="button"} +[Link Outline](#){.btn .btn-outline-link .btn role="button"} + +```md +[Primary Outline](#){.btn .btn-outline-primary .btn role="button"} +[Secondary Outline](#){.btn .btn-outline-secondary .btn role="button"} +[Success Outline](#){.btn .btn-outline-success .btn role="button"} +[Danger Outline](#){.btn .btn-outline-danger .btn role="button"} +[Warning Outline](#){.btn .btn-outline-warning .btn role="button"} +[Info Outline](#){.btn .btn-outline-info .btn role="button"} +[Light Outline](#){.btn .btn-outline-light .btn role="button"} +[Dark Outline](#){.btn .btn-outline-dark .btn role="button"} +[Link Outline](#){.btn .btn-outline-link .btn role="button"} +``` + +### Special Buttons + +We have custom support buttons ([More Info](#includes)) that link to GRASS's [Open Collective page]({{< var grass.support >}}) + +{{< include /content/include/_support-button.qmd >}} +{{< include /content/include/_support-outline-button.qmd >}} + +## Alerts + +::: {.alert .alert-success} +This is a success alert. +::: + +```md +::: {.alert .alert-success} +This is a success alert. +::: +``` + +::: {.alert .alert-danger} +This is a danger alert. +::: + +```md +::: {.alert .alert-danger} +This is a danger alert. +::: +``` + +## Code Blocks with Syntax Highlighting + +### Default + +```default +code +``` + +### Python +```python +# Comment +import sys +import subprocess + +sys.path.append( + subprocess.check_output(["grass", "--config", "python_path"], text=True).strip() +) + +import grass.script as gs +import grass.jupyter as gj +``` + +### Terminal +```bash +grass "~/grassdata/" --exec script.py +``` + +### R +```r +library(rgrass) + +session <- initGRASS(gisBase = "/usr/lib/grass84", # where grass binaries live, `grass --config path` + gisDbase = "/home/user/grassdata", # path to grass database or folder where your project lives + location = "nc_basic_spm_grass7", # existing project name + mapset = "PERMANENT" # mapset name + ) + +``` + +## Tabsets + +::: {.panel-tabset} +## R + +``` {.r} +execGRASS( + "r.slope.aspect", + parameters = list( + elevation = "elevation", + slope = "slope", + aspect="aspect" + ) +) +``` + +## Python + +``` {.python} +gs.run_command( + "r.slope.aspect", + elevation = "elevation", + slope = "slope", + aspect="aspect" +) +``` + +::: + +```md +::: {.panel-tabset} + +Your panel content here + +::: +``` + +For more information about tabsets refer to the Quarto Docs [here](https://quarto.org/docs/output-formats/html-basics.html#tabsets) + +## Raw Content + +```{=html} + +``` + +```md +\```{=html} + +```\ +``` + +## Diagrams + +### Flowchart +```{mermaid} +flowchart LR + A[Hard edge] --> B(Round edge) + B --> C{Decision} + C --> D[Result one] + C --> E[Result two] +``` + +### Sequence Diagram +```{mermaid} +sequenceDiagram + participant Alice + participant Bob + Alice->>John: Hello John, how are you? + loop Healthcheck + John->>John: Fight against hypochondria + end + Note right of John: Rational thoughts
prevail! + John-->>Alice: Great! + John->>Bob: How about you? + Bob-->>John: Jolly good! +``` + +### Dot + +```{dot} +graph G { + layout=neato + run -- intr; + intr -- runbl; + runbl -- run; + run -- kernel; + kernel -- zombie; + kernel -- sleep; + kernel -- runmem; + sleep -- swap; + swap -- runswap; + runswap -- new; + runswap -- runmem; + new -- runmem; + sleep -- runmem; +} +``` + +## Videos + +Use the [video shortcode](https://quarto.org/docs/authoring/videos.html) + +{{< video https://www.youtube.com/embed/zboP3Z7VBuU >}} + +## Page Break + +page 1 + +{{< pagebreak >}} + +page 2 + +## Divs & Spans + +### Border + +::: {.border} +This content can be styled with a border +::: + +```md +::: {.border} +This content can be styled with a border +::: +``` + +### Spans + +[This is *some text*]{.class key="val"} + +```md +[This is *some text*]{.class key="val"} +``` + +This is a custom span. + +```md +This is a custom span. +``` + +### Span Styling + +#### Small Caps + +[smallcaps]{.smallcaps} + +```md +[smallcaps]{.smallcaps} +``` + +#### Underline + +[underlined]{.underline} + +```md +[underlined]{.underline} +``` + +#### Highlight + +[highlighted]{.mark} + +``` +[highlighted]{.mark} +``` + +### Order of Attribute + +The order of attribute for divs and spans follow rules defined in the [pandoc](https://pandoc.org/MANUAL.html#divs-and-spans) documentation. + +#### Good + +```md +[Good]{#id .class key="val"} +``` + +#### Bad + +```md +[This is *some text*]{.class key="val"} +``` + +## Keyboard Shortcuts + +The [kbd]{.text-success} shortcode can be used to describe keyboard shortcuts in documentation. + +```md {.markdown shortcodes="false"} +To print, press {{< kbd Shift-Ctrl-P >}}. +To open an existing new project, +press {{< kbd mac=Shift-Command-O win=Shift-Control-O linux=Shift-Ctrl-L >}}. +``` + +To print, press {{< kbd Shift-Ctrl-P >}}. +To open an existing new project, press {{< kbd mac=Shift-Command-O win=Shift-Control-O linux=Shift-Ctrl-L >}}. + +## Listing + +### Table + +:::{#lab-reports} +::: + +### Grid + +:::{#meeting-notes} +::: + +### Default +:::{#default-notes} +::: + +## Layout + +### Column Full screen inset +::: {.column-screen-inset} +![A full screen image](images/LinkedIn-Post-Image.png) +::: + +### Column Full screen shaded inset +::: {.column-shaded-screen-inset} +![A full screen image](images/LinkedIn-Post-Image.png) +::: + +### Column Margin +::: {.column-margin} +![An image in the margin](images/LinkedIn-Post-Image.png) +::: + +## Lipsum + +Lipsum shortcode docs found [here](https://quarto.org/docs/authoring/lipsum.html). + +### Single Paragraph +{{< lipsum 1 >}} + +### Multi Paragraph +{{< lipsum 2 random=true >}} + +# Custom + +Quarto supports several shortcodes natively which allow us to access project varibles. + +| Shortcode | Description | +|---------------------------------------------------------------|------------------------------------------| +| [var](https://quarto.org/docs/authoring/variables.html#va) | Print value from `_variables.yml` file | +| [meta](https://quarto.org/docs/authoring/variables.html#meta) | Print value from document metadata | +| [env](https://quarto.org/docs/authoring/variables.html#env) | Print system environment variable | + +: More info found at [https://quarto.org/docs/authoring/](https://quarto.org/docs/authoring/). + +## Variables + +You can access variables located in `_variables.yml` using pre-defined [varible shortcodes](https://quarto.org/docs/authoring/variables.html). + +``` {.markdown shortcodes="false"} +{{< var grass.version >}} +``` + +Will render {{< var grass.version >}} + +## Includes + +The include [shortcode](https://quarto.org/docs/authoring/includes.html) allows us to use reusable markdown. + +### Support Button + +`{{< include /content/include/_support-button.qmd >}}` + +renders to + +``` {.markdown shortcodes="false"} +{{< include /content/include/_support-button.qmd >}} +``` + +which renders to the content of `/content/include/_support-button.qmd` + +``` {.markdown shortcodes="true"} +{{< include /content/include/_support-button.qmd >}} +``` + +and finally displays + +{{< include /content/include/_support-button.qmd >}} + +## Brand + +Brand data is defined in the `_brand.yml` file. + +### Logo small light + +``` {.markdown shortcodes="false"} +{{< brand logo small light >}} +``` + +{{< brand logo small light >}} diff --git a/images/favicon.ico b/images/favicon.ico new file mode 100644 index 0000000..7bf220f Binary files /dev/null and b/images/favicon.ico differ diff --git a/images/icons/grass-icon.svg b/images/icons/grass-icon.svg new file mode 100644 index 0000000..142b325 --- /dev/null +++ b/images/icons/grass-icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/images/logos/grass-green-on-white.png b/images/logos/grass-green-on-white.png new file mode 100644 index 0000000..aecdb59 Binary files /dev/null and b/images/logos/grass-green-on-white.png differ diff --git a/images/logos/large/grass-gradient-horizontal.svg b/images/logos/large/grass-gradient-horizontal.svg new file mode 100644 index 0000000..0cdf3e5 --- /dev/null +++ b/images/logos/large/grass-gradient-horizontal.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/logos/large/grass-gradient-no-text.svg b/images/logos/large/grass-gradient-no-text.svg new file mode 100644 index 0000000..e966279 --- /dev/null +++ b/images/logos/large/grass-gradient-no-text.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/images/logos/large/grass-gradient.svg b/images/logos/large/grass-gradient.svg new file mode 100644 index 0000000..6b7bf52 --- /dev/null +++ b/images/logos/large/grass-gradient.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/logos/large/grass-green-horizontal.svg b/images/logos/large/grass-green-horizontal.svg new file mode 100644 index 0000000..bfa6aba --- /dev/null +++ b/images/logos/large/grass-green-horizontal.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/images/logos/large/grass-green-no-text.svg b/images/logos/large/grass-green-no-text.svg new file mode 100644 index 0000000..af7e14a --- /dev/null +++ b/images/logos/large/grass-green-no-text.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/images/logos/large/grass-green.svg b/images/logos/large/grass-green.svg new file mode 100644 index 0000000..02dda5b --- /dev/null +++ b/images/logos/large/grass-green.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/images/logos/large/grass-white-horizontal.svg b/images/logos/large/grass-white-horizontal.svg new file mode 100644 index 0000000..2a3db6f --- /dev/null +++ b/images/logos/large/grass-white-horizontal.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/images/logos/large/grass-white-no-text.svg b/images/logos/large/grass-white-no-text.svg new file mode 100644 index 0000000..2a0b69d --- /dev/null +++ b/images/logos/large/grass-white-no-text.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/logos/large/grass-white.svg b/images/logos/large/grass-white.svg new file mode 100644 index 0000000..4d4b635 --- /dev/null +++ b/images/logos/large/grass-white.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/images/logos/medium/grass-logo-gradient-simple@1x.png b/images/logos/medium/grass-logo-gradient-simple@1x.png new file mode 100644 index 0000000..1ecd359 Binary files /dev/null and b/images/logos/medium/grass-logo-gradient-simple@1x.png differ diff --git a/images/logos/medium/grass-logo-green-simple@1x.png b/images/logos/medium/grass-logo-green-simple@1x.png new file mode 100644 index 0000000..4858714 Binary files /dev/null and b/images/logos/medium/grass-logo-green-simple@1x.png differ diff --git a/images/logos/medium/grass-logo-white-simple@1x.png b/images/logos/medium/grass-logo-white-simple@1x.png new file mode 100644 index 0000000..bed6043 Binary files /dev/null and b/images/logos/medium/grass-logo-white-simple@1x.png differ diff --git a/images/logos/small/grass-logo-gradient-simple@05x.png b/images/logos/small/grass-logo-gradient-simple@05x.png new file mode 100644 index 0000000..5eb0549 Binary files /dev/null and b/images/logos/small/grass-logo-gradient-simple@05x.png differ diff --git a/images/logos/small/grass-logo-green-simple@05x.png b/images/logos/small/grass-logo-green-simple@05x.png new file mode 100644 index 0000000..ace918a Binary files /dev/null and b/images/logos/small/grass-logo-green-simple@05x.png differ diff --git a/images/logos/small/grass-logo-white-simple@05x.png b/images/logos/small/grass-logo-white-simple@05x.png new file mode 100644 index 0000000..a465938 Binary files /dev/null and b/images/logos/small/grass-logo-white-simple@05x.png differ diff --git a/index.qmd b/index.qmd index a18a487..7f3e8dd 100644 --- a/index.qmd +++ b/index.qmd @@ -1,6 +1,10 @@ --- title: "Learn GRASS" listing: + - id: tests + contents: + - content/tests/styling.qmd + type: grid - id: get-started contents: content/tutorials/get_started type: grid @@ -30,3 +34,9 @@ title-block-banner: false ## All Tutorials :::{#all} ::: + +::: {.content-visible when-profile="local"} +## Tests +:::{#tests} +::: +::: \ No newline at end of file diff --git a/theme.scss b/theme.scss index 499b605..d49c65a 100644 --- a/theme.scss +++ b/theme.scss @@ -1,95 +1,826 @@ -/*-- scss:defaults --*/ -// Base document colors -$body-bg: #ffffff; -$banner-bg: #f0e3ce; -$grass-color-light: #f0e3ce; -// $grass-color-light: rgb(207, 207, 207); -$grass-color-black: #0a0a0a; -$grass-color-dark-grey: #A0A0A0; -$grass-color-light-grey: #CCCCCC; -$grass-color-light-green: #EFF4E8; -$grass-color-dark-green: #B8C6A5; -$grass-color-soft-green: #9ED29C; -$grass-color-primary: #088B36; -$primary: $grass-color-primary; - -$op-white:#fbfbfb; -// https://www.color-hex.com/color-palette/36240 -$op-primary: #657e96; -$op-secondary: #d07944; -$op-tan: #f0e3ce; -$op-brown: #a76a3a; -$op-mustard: #d49441; -$op-light-grey:rgb(207, 207, 207); - -// Revealjs theme colors -$link-color: $grass-color-primary; -$presentation-heading-color: $grass-color-primary; +//-- scss:defaults --*/ +// GRASS Theme +/* GRASS Variables +Use these variables to customize the GRASS theme. +----------------------------------------------------------------------------- */ +/* GRASS Font */ +$gs-grass-font: 'Fira Sans Regular', sans-serif; +$gs-grass-font--medium: 'Fira Sans Medium', sans-serif; +$gs-grass-font--bold: 'Fira Sans Bold', sans-serif; +$gs-grass-font--light: 'Fira Sans ExtraLight', sans-serif; +$gs-grass-font--mono: 'Fira Mono', monospace; -.highlight { - color: $grass-color-primary; - font-weight: bold; +/* Primary Color */ +$gs-primary-color: rgb(76, 176, 91); +$gs-primary-color--light: rgba(76, 176, 91, 0.541); +$gs-primary-color--lighter: rgba(76, 176, 91, 0.322); +$gs-primary-color--lightest: rgba(76, 176, 91, 0.071); + +/* Primary Alt Color */ +$gs-primary-alt-color: rgb(110, 208, 121); +$gs-primary-alt-color--light: rgba(110, 208, 121, 0.541); +$gs-primary-alt-color--lighter: rgba(110, 208, 121, 0.322); +$gs-primary-alt-color--lightest: rgba(110, 208, 121, 0.071); + +/* Primary Light Color */ +$gs-primary-light-color: rgb(135, 233, 145); +$gs-primary-light-color--light: rgba(135, 233, 145, 0.541); +$gs-primary-light-color--lighter: rgba(138, 233, 145, 0.322); +$gs-primary-light-color--lightest: rgba(138, 233, 145, 0.071); + +/* Primary Dark Color */ +$gs-primary-dark-color: rgb(8, 139, 54); +$gs-primary-dark-color--light: rgba(8, 139, 54, 0.541); +$gs-primary-dark-color--lighter: rgba(8, 139, 54, 0.322); +$gs-primary-dark-color--lightest: rgba(8, 139, 54, 0.071); + +/* Secondary Color */ +$gs-secondary-color: rgb(0, 57, 63); +$gs-secondary-color--light: rgba(0, 57, 63, 0.541); +$gs-secondary-color--lighter: rgba(0, 57, 63, 0.322); +$gs-secondary-color--lightest: rgba(0, 57, 63, 0.071); + +/* Secondary Alt Color */ +$gs-secondary-alt-color: rgb(39, 87, 92); +$gs-secondary-alt-color--light: rgba(39, 87, 92, 0.541); +$gs-secondary-alt-color--lighter: rgba(39, 87, 92, 0.322); +$gs-secondary-alt-color--lightest: rgba(39, 87, 92, 0.071); + +/* Secondary Light Color */ +$gs-secondary-light-color: rgb(74, 120, 125); +$gs-secondary-light-color--light: rgba(74, 121, 127, 0.541); +$gs-secondary-light-color--lighter: rgba(74, 121, 127, 0.322); +$gs-secondary-light-color--lightest: rgba(74, 121, 127, 0.071); + +/* Secondary Dark Color */ +$gs-secondary-dark-color: rgb(0, 32, 36); +$gs-secondary-dark-color--light: rgba(0, 32, 36, 0.541); +$gs-secondary-dark-color--lighter: rgba(0, 32, 36, 0.322); +$gs-secondary-dark-color--lightest: rgba(0, 32, 36, 0.071); + +/* White */ +$gs-white-base-color: rgb(255, 255, 255); +$gs-white-color: rgb(247, 247, 247); +$gs-white-color--light: rgba(247, 247, 247, 0.541); +$gs-white-color--lighter: rgba(247, 247, 247, 0.322); +$gs-white-color--lightest: rgba(247, 247, 247, 0.071); + +/* Black */ +$gs-black-base-color: rgb(0, 0, 0); +$gs-black-color: rgb(2, 25, 5); +$gs-black-color--light: rgba(2, 25, 5, 0.541); +$gs-black-color--lighter: rgba(2, 25, 5, 0.322); +$gs-black-color--lightest: rgba(2, 25, 5, 0.071); + +/* Grey */ +$gs-grey-color: rgb(145, 144, 143); +$gs-grey-color--light: rgba(145, 144, 143, 0.541); +$gs-grey-color--lighter: rgba(145, 144, 143, 0.322); +$gs-grey-color--lightest: rgba(145, 144, 143, 0.071); + +/* Grey Alt */ +$gs-grey-alt-color: rgb(216, 216, 216); +$gs-grey-alt-color--light: rgba(216, 216, 216, 0.541); +$gs-grey-alt-color--lighter: rgba(216, 216, 216, 0.322); +$gs-grey-alt-color--lightest: rgba(216, 216, 216, 0.071); + +/* Grey Light */ +$gs-grey-light-color: rgb(240, 240, 241); +$gs-grey-light-color--light: rgba(240, 240, 241, 0.541); +$gs-grey-light-color--lighter: rgba(240, 240, 241, 0.322); +$gs-grey-light-color--lightest: rgba(240, 240, 241, 0.071); + +/* Grey Dark */ +$gs-grey-dark-color: rgb(78, 77, 76); +$gs-grey-dark-color--light: rgba(78, 77, 76, 0.541); +$gs-grey-dark-color--lighter: rgba(78, 77, 76, 0.322); +$gs-grey-dark-color--lightest: rgba(78, 77, 76, 0.071); + +/* Special Colors */ +$gs-support-color: rgb(243, 57, 138); +$gs-support-color--dark: rgba(243, 57, 138, 0.541); +$gs-support-color--light: rgba(243, 57, 138, 0.322); +$gs-yard-sign-color: rgb(116, 93, 2); + +/* Bootstrap Mapping Colors */ +// $gs-primary-color: $gs-primary-color; Defined above +// $gs-secondonary-color: $gs-secondary-color; Defined above +$gs-danger-color: rgb(176, 76, 76); +$gs-warning-color: rgb(176, 154, 76); +$gs-success-color: $gs-primary-alt-color; +$gs-info-color: $gs-secondary-alt-color; +$gs-light-color: $gs-grey-light-color; +$gs-dark-color: $gs-grey-dark-color; + +/* Images */ +$gs-images-base-path: 'images'; +$gs-images-logos-small-path: $gs-images-base-path + '/logos/small'; +$gs-svg-logos-base-path: $gs-images-base-path + '/logos/large'; +$gs-icons-base-path: $gs-images-base-path + '/icons'; + + +/* Icons */ +$gs-grass-logo-white-simple: url($gs-images-logos-small-path + '/grass-logo-green-simple@05x.png'); +$gs-grass-logo-simple-svg: url($gs-svg-logos-base-path + '/grass-green-no-text.svg'); +$gs-grass-icon: url($gs-icons-base-path + '/grass-icon.svg'); + +// Description: This file defines Bootstrap theme variables by mapping them +// to custom color variables. These variables are used to +// customize the appearance of the Bootstrap framework. +// Bootstrap Variables: https: //github.com/twbs/bootstrap/blob/main/scss/_variables.scss +// Variables: +// - $primary: Primary theme color, mapped to $gs-primary-color. +// - $secondary: Secondary theme color, mapped to $gs-secondary-color. +// - $success: Success state color, mapped to $gs-success-color. +// - $info: Informational state color, mapped to $gs-info-color. +// - $warning: Warning state color, mapped to $gs-warning-color. +// - $danger: Danger/error state color, mapped to $gs-danger-color. +// - $light: Light theme color, mapped to $gs-grey-light-color. +// - $dark: Dark theme color, mapped to $gs-grey-dark-color. +// Bootstrap Variables +/*---------------------------------------------------------------------------*/ +$primary: $gs-primary-color; +$secondary: $gs-secondary-color; +$success: $gs-success-color; +$info: $gs-info-color; +$warning: $gs-warning-color; +$danger: $gs-danger-color; +$light: $gs-grey-light-color; +$dark: $gs-grey-dark-color; + +// Control the color of the active tab in a tabset +$nav-tabs-link-active-color: $gs-secondary-alt-color; + +// Control listing card title color +$card-title-color: $gs-grey-dark-color; + +// --------------------------------------------------------------------------- +// Quarto Variables +// --------------------------------------------------------------------------- +// This section defines the primary variables used throughout the theme, +// including body background, text color, link color, font families, and root +// font size. + +// Navbar +// --------------------------------------------------------------------------- +// Variables for styling the navigation bar, including foreground and highlight +// colors. + +// Footer +// --------------------------------------------------------------------------- +// Variables for styling the footer, including background, foreground, and link +// highlight colors. + +// Inputs +// --------------------------------------------------------------------------- +// Variables for input field styling, such as background color. + +// Popover +// --------------------------------------------------------------------------- +// Variables for popover styling, including background color. + +// Table of Contents +// --------------------------------------------------------------------------- +// Variables for styling the table of contents, such as font size. + +// Code +// --------------------------------------------------------------------------- +// Variables for code block styling, including text color, background color, +// and syntax highlighting for keywords and strings. + +// Callouts +// --------------------------------------------------------------------------- +// Variables for callout box styling, with specific colors for different types +// of callouts (e.g., note, warning, tip, caution, important). + +// Mermaid Theme +// --------------------------------------------------------------------------- +// Variables for Mermaid diagram styling, including background, edge, node, +// and label colors, as well as font family and transparency settings. +/* Quarto Variables + +---------------------------------------------------------------------------*/ + +$body-bg: $gs-white-color; +$body-color: $gs-black-color; +$link-color: $primary; +$font-family-sans-serif: $gs-grass-font; +$font-family-monospace: $gs-grass-font--mono; +$font-size-root: 16px; + +/* Navbar +-----------------------------------------------------------------------------*/ +$navbar-fg: $gs-white-color; +$navbar-hl: $gs-secondary-alt-color; + +/* Footer +-----------------------------------------------------------------------------*/ +$footer-bg: $gs-secondary-color; +$footer-fg: $gs-white-base-color; +$footer-link-hl: $gs-white-color--light; + +/* Inputs +-----------------------------------------------------------------------------*/ +$input-bg: $gs-white-base-color; + +/* Popover +-----------------------------------------------------------------------------*/ +$popover-bg: $body-bg; + +/* Table of Contents +-----------------------------------------------------------------------------*/ +$toc-font-size: 1rem; + +/* Code +-----------------------------------------------------------------------------*/ +$code-color: $gs-secondary-color; +$code-bg: $gs-grey-light-color; +$code-block-bg: $gs-grey-light-color; +$code-keyword-color: $gs-primary-color; +$code-string-color: $gs-primary-color; + +/* Code Copy +-----------------------------------------------------------------------------*/ +$btn-code-copy-color: $gs-secondary-alt-color; +$btn-code-copy-color-active: $gs-secondary-color; + +/* Callouts +Quarto Docs: https: //quarto.org/docs/authoring/callouts.html +-----------------------------------------------------------------------------*/ +$callout-color-note: $gs-primary-light-color; +$callout-color-warning: $gs-warning-color; +$callout-color-tip: $gs-info-color; +$callout-color-caution: $gs-danger-color; +$callout-color-important: $gs-primary-dark-color; + +/* Mermaid Theme +Quarto Docs: https: //quarto.org/docs/authoring/diagrams.html +-----------------------------------------------------------------------------*/ +$mermaid-bg-color: $body-bg; +$mermaid-edge-color: $secondary; +$mermaid-node-fg-color: $body-color; +$mermaid-fg-color: $body-color; +$mermaid-fg-color--lighter: lighten($body-color, 10%); +$mermaid-fg-color--lightest: lighten($body-color, 20%); +$mermaid-font-family: $gs-grass-font; +$mermaid-label-bg-color: $body-bg; +$mermaid-label-fg-color: $primary; +$mermaid-node-bg-color: rgba($primary, 0.1); +$mermaid-node-fg-color: $gs-primary-dark-color; + +/*-- scss:mixins --*/ +/* Mixin for custom button styles */ + +/// @mixin box-shadow-default +/// This mixin applies a default box-shadow styling to an element. +/// +/// The box-shadow consists of: +/// - A larger, softer shadow with a light black color. +/// - A smaller, sharper shadow with a lighter black color. +/// +/// Variables used: +/// - `$gs-black-color--light`: Represents the light black color for the larger shadow. +/// - `$gs-black-color--lightest`: Represents the lightest black color for the smaller shadow. +@mixin box-shadow-default { + box-shadow: 0 0.2rem 0.5rem $gs-black-color--light, 0 0 0.05rem $gs-black-color--lightest; +} + +/// @mixin apply-color-filter +/// Applies a CSS filter to an element based on a given source color. +/// +/// @param {Color} $source-color - The source color. +/// @param {Boolean} $important - If true, adds !important to the filter. +/// +/// This mixin: +/// - Extracts HSL components from the source color. +/// - Uses hue, saturation, and an adjusted brightness in a CSS filter. +@mixin apply-color-filter($source-color, +$important: false) { + $hue: hue($source-color); + $saturation: saturation($source-color); + $lightness: lightness($source-color); + + // Strip units from % values + $saturation-value: $saturation / 1%; + $lightness-value: $lightness / 1%; + + // Optional scaling to emphasize effect + $saturation-factor: floor($saturation-value) * 2 / 100; + $brightness-factor: floor($lightness-value) *2; + + // Check if the important flag is set + $important-flag: if($important, ' !important', ''); + + filter: hue-rotate(#{$hue}deg) saturate($saturation-factor) brightness(#{$brightness-factor})#{$important-flag}; +} + +@mixin sentence-case() { + text-transform: lowercase; + &::first-letter { + text-transform: uppercase; + } + // Insterted by Lua filter protect-terms + .no-transform, + span.no-transform { + text-transform: none !important; } +} + +/*-- scss:rules --*/ + +/* Header Styles +-----------------------------------------------------------------------------*/ +h1 { + color: $gs-secondary-alt-color; + font-family: $gs-grass-font--bold; + font-weight: bold; + font-size: 2.25em; + line-height: 1.3; + margin: 0 0 1em; + // @include sentence-case; +} + +h2 { + font-family: $gs-grass-font--light; + color: $gs-secondary-light-color; + font-size: 2em; + line-height: 1.4; + margin: .64em 0 .64em; + // @include sentence-case; +} -.circle-image-container { - position: relative; - // width: 100%; - height: auto; - display: inline-block; +h3 { + color: $gs-secondary-light-color; + font-size: 1.25em; + font-weight: 600; + letter-spacing: -.01em; + line-height: 1.5; + margin: 1.6em 0 .8em; + // @include sentence-case; +} + +// h4, h5, h6 { + // @include sentence-case; +// } + +/* Code Styles +If we want more control the next step would be to create a custom theme +for the syntax highlighter using skylighting https: //github.com/jgm/skylighting +-----------------------------------------------------------------------------*/ +code { + span { + .al { + color: $gs-primary-color; + font-style: inherit; + } + // Color of keywords in code blocks + .im { + color: $code-keyword-color; + font-style: inherit; + } + // Color of strings in code blocks + .st { + color: $code-string-color; + font-style: inherit; + } + // Color of titles in markdown code blocks + .fu { + color: $gs-secondary-alt-color; + } + // Color of pipes in markdown code blocks + .pp { + color: $code-keyword-color; + } + // Color of blockquotes in markdown code blocks and parameter names in R code blocks + .at { + color: $gs-secondary-color; + } } - - .circle-image { - border-radius: 50%; - width: 100%; - height: auto; - object-fit: cover; - display: block; +} + +/* +Button Styles +----------------------------------------------------------------------------- +Defines the styles for various button components used in the project. +Each button style is designed with specific colors, borders, and hover/focus effects +to match the theme's design system. + +General Button Styles: +- `.btn`: Base button styles including font, padding, and border-radius. + +Primary Buttons: +- `.btn-primary`: Primary button with theme's primary color. +- `.btn-outline-primary`: Outlined version of the primary button. + +Secondary Buttons: +- `.btn-secondary`: Secondary button with theme's secondary color. +- `.btn-outline-secondary`: Outlined version of the secondary button. + +Success Buttons: +- `.btn-success`: Success button with theme's success color. +- `.btn-outline-success`: Outlined version of the success button. + +Warning Buttons: +- `.btn-warning`: Warning button with theme's warning color. +- `.btn-outline-warning`: Outlined version of the warning button. + +Support Buttons: +- `.btn-support`: Support button with theme's support color. +- `.btn-outline-support`: Outlined version of the support button with icon support. + +Light Buttons: +- `.btn-outline-light`: Outlined button with light/grey color scheme. + +Link Buttons: +- `.btn-outline-link`: Outlined button styled as a link with underline. + +Hover and Focus States: +- Each button includes hover and focus states to enhance interactivity. +- Colors are adjusted (e.g., darkened or lightened) to provide visual feedback. + +Mixins and Utilities: +- `@include box-shadow-default`: Applied to certain buttons for shadow effects. +- `gap`: Used in `.btn-outline-support` for spacing between icon and text. +*/ +/* Button Styles +-----------------------------------------------------------------------------*/ +.btn { + font-family: $gs-grass-font--medium; + font-size: 1em; + font-weight: 700; + padding: .5rem 1rem; + border-radius: .25rem; +} + +.btn-primary { + background-color: $gs-primary-color; + border-color: $gs-primary-color; + color: $gs-white-base-color; + &:hover, + &:focus { + background-color: $gs-primary-alt-color; + border-color: $gs-primary-alt-color; + color: $gs-white-base-color; } - - .circle-image-container::before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - border-radius: 60%; - background: linear-gradient(to bottom, $op-white, $grass-color-soft-green); - opacity: 1; - z-index: -1; +} + +.btn-secondary { + background-color: $gs-secondary-color; + border-color: $gs-secondary-color; + color: $gs-white-base-color; + &:hover, + &:focus { + background-color: $gs-secondary-light-color; + border-color: $gs-secondary-light-color; + color: $gs-white-base-color; } +} + +.btn-success { + background-color: $gs-success-color; + border-color: $gs-success-color; + color: $gs-white-color; + &:hover, + &:focus { + background-color: darken($gs-success-color, 10%); + border-color: darken($gs-success-color, 10%); + color: $gs-white-color; + } +} + +.btn-warning { + background-color: $gs-warning-color; + border-color: $gs-warning-color; + color: $gs-white-color; + &:hover, + &:focus { + background-color: darken($gs-warning-color, 10%); + border-color: darken($gs-warning-color, 10%); + color: $gs-white-color; + } +} + +.btn-support { + background-color: $gs-support-color; + border-color: $gs-support-color; + color: $gs-white-base-color; + &:hover, + &:focus { + @include box-shadow-default; + background-color: $gs-support-color; + border-color: $gs-support-color; + color: $gs-white-base-color; + } +} + +.btn-outline-primary { + background-color: $gs-white-base-color; + border-color: $gs-primary-color; + color: $gs-primary-color; + &:hover, + &:focus { + background-color: $gs-primary-color; + border-color: $gs-primary-alt-color; + color: $gs-white-base-color; + } +} + +.btn-outline-secondary { + background-color: $gs-white-base-color; + border-color: $gs-secondary-color; + color: $gs-secondary-color; + &:hover, + &:focus { + background-color: $gs-secondary-light-color; + border-color: $gs-secondary-light-color; + color: $gs-white-base-color; + } +} + +.btn-outline-success { + background-color: $gs-white-color; + border-color: $gs-success-color; + color: $gs-success-color; + &:hover, + &:focus { + background-color: $gs-success-color; + border-color: $gs-success-color; + color: $gs-white-base-color; + } +} + +.btn-outline-warning { + background-color: $gs-white-color; + border-color: $gs-warning-color; + color: $gs-warning-color; + &:hover, + &:focus { + background-color: $gs-warning-color; + border-color: $gs-warning-color; + color: $gs-white-base-color; + } +} + +.btn-outline-light { + background-color: $gs-white-base-color; + border-color: $gs-grey-color; + color: $gs-grey-color; + &:hover, + &:focus { + background-color: $gs-grey-color; + border-color: $gs-grey-color; + color: $gs-white-base-color; + } +} + +.btn-outline-link { + border-color: $gs-primary-color; + color: $gs-primary-color; + text-decoration: underline; + &:hover, + &:focus { + border-color: $gs-primary-dark-color; + color: $gs-primary-dark-color; + } +} + +.btn-outline-support { + background-color: $gs-white-base-color; + border-color: $gs-support-color; + color: $gs-support-color; + display: inline-flex; + align-items: center; + gap: 0.5rem; // Space between icon and text + &:hover, + &:focus { + @include box-shadow-default; + background-color: $gs-support-color; + border-color: $gs-support-color; + color: $gs-white-base-color; + } +} + +/* Listings +-----------------------------------------------------------------------------*/ +ul.pagination li.disabled a, +ul.pagination li.active a { + background-color: $gs-primary-color !important; + color: $gs-white-base-color !important; +} + +#quarto-margin-sidebar .quarto-listing-category-title { + color: $gs-secondary-alt-color; +} + +/* Table of Contents +-----------------------------------------------------------------------------*/ +.sidebar nav[role=doc-toc]>h2 { + color: $gs-secondary-alt-color; + font-weight: 700; +} + +/* Navbar +-----------------------------------------------------------------------------*/ +.navbar-brand:hover, +.navbar-brand:focus { + color: $gs-white-base-color; +} .quarto-title-banner { - background-color: $banner-bg !important; - color: $grass-color-black !important; + margin-bottom: 1em; + color: $gs-secondary-alt-color; + background: $gs-primary-dark-color--lightest; + h1 { - color: $grass-color-black !important; + color: $gs-secondary-alt-color; + } + + .code-tools-button { + color: $gs-white-color; + background-color: $gs-secondary-alt-color !important; + } + + .dropdown-item { + color: $gs-secondary-alt-color !important; + } + + .dropdown-item:hover, + .dropdown-item:focus { + background-color: $gs-primary-alt-color !important; + color: $gs-white-base-color !important; + } + + .quarto-categories { + color: $gs-secondary-alt-color !important; } } -.reveal { - h3 { - color: $grass-color-black !important; +/* Cards +-----------------------------------------------------------------------------*/ +.card { + .card-body { + background-color: $gs-white-base-color; + color: $gs-black-color; + } +} + +/* Input Styles +-----------------------------------------------------------------------------*/ + +.input-group-text { + background-color: $gs-primary-color; + color: $gs-white-base-color; + font-weight: 700; +} + +input[type=checkbox] { + appearance: none; // Ensure custom styles apply + height: 0.9rem; + border: 2px solid $gs-primary-color; + border-radius: 0.2rem; + background-color: $gs-white-base-color; + padding: 0.2rem; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + + &:checked { + background-color: $gs-primary-color; + border-color: $gs-primary-color; + + &::after { + font-family: 'Font Awesome 6 Free'; // Ensure Font Awesome is loaded + content: '\f00c'; // Add a checkmark when selected + color: $gs-white-base-color; + font-size: 0.75rem; // Adjust size of the checkmark + } + } + + &:disabled { + background-color: $gs-primary-light-color; + border-color: $gs-primary-light-color; + cursor: not-allowed; + } + &:disabled:checked { + background-color: $gs-primary-light-color; + border-color: $gs-primary-light-color; + } +} + +.form-control:focus { + color: $gs-black-color; + background-color: $gs-white-base-color; + border-color: $gs-primary-alt-color; + outline: 0; + box-shadow: 0 0 0 .05rem $gs-primary-color--lighter; +} + +/* Callouts +-----------------------------------------------------------------------------*/ +.callout { + &.callout-style-default { + @include box-shadow-default; + transition: box-shadow 125ms; + border-radius: .2rem; + + >div.callout-header { + font-weight: 700; + } + } +} + +.callout-note { + border-color: $callout-color-note; + + &.callout-titled { + color: $gs-primary-dark-color; + .callout-icon { + &::before { + background-image: $gs-grass-logo-white-simple !important; + } + } + .callout-body { + color: $gs-black-color; + } + } +} + +.callout-tip { + border-color: $callout-color-tip; + color: $callout-color-tip; + + &.callout-titled { + .callout-icon { + &::before { + background-image: $gs-grass-logo-white-simple !important; + } + } + .callout-body { + color: $gs-black-color; } - .columns { - .column { - background-color: rgba(251, 252, 250, 0.5) !important; - } - + } +} + +.callout-warning { + border-color: $callout-color-warning; + color: $callout-color-warning; + + &.callout-titled { + .callout-body { + color: $gs-black-color; } - .quarto-title-block { + } +} - .quarto-title-acknowledgements { - color: $grass-color-primary !important; - font-size: 0.6em; - } +.callout-important { + border-color: $callout-color-important; + color: $callout-color-important; + + &.callout-titled { + .callout-body { + color: $gs-black-color; } + } } -.text-white { - color: $op-white !important; +.callout-caution { + border-color: $callout-color-caution; + color: $callout-color-caution; + + &.callout-titled { + .callout-body { + color: $gs-black-color; + } + } } -.text-center { - text-align: center !important; -} \ No newline at end of file +.highlight { + color: $primary; + font-weight: bold; +} + +// Front Matter +.quarto-title .quarto-categories { + color: $gs-primary-dark-color; +} + +.quarto-title-meta-heading { + color: $gs-primary-dark-color; + font-family: $gs-grass-font--medium; + font-weight: 700; +} + +/* Footer +-----------------------------------------------------------------------------*/ +footer { + + a, i { + + &:hover, + &:focus { + color: $footer-link-hl; + text-decoration: underline; + } + } +}