+ "markdown": "---\ntitle: \"Making plots with GRASS GIS\"\nauthor: \"Veronica Andreo\"\ndate: 2024-04-25\ndate-modified: today\nformat: \n html:\n toc: true\n code-tools: true\n code-copy: true\n code-fold: false\ncategories: [statistics, matplotlib, beginner]\nengine: knitr\nexecute: \n eval: false\n---\n\n\nIn previous tutorials we saw examples of how to convert GRASS GIS\nraster and vector maps into Python and R objects to perform data \nanalysis and visualizations. \nThere are some GRASS GIS 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 GIS:\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 GIS 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\n::: {.cell}\n\n```{.bash .cell-code}\ng.extension extension=r.boxplot\nr.boxplot -oc input=elevation zones=landclass96 output=r.boxplot.png\n```\n:::\n\n\n# Python\n\n::: {.cell}\n\n```{.python .cell-code}\ngs.run_command(\"g.extension\", extension=\"r.boxplot\")\ngs.run_command(\"r.boxplot\", \n input=\"elevation\", \n zones=\"landclass96\", \n raster_statistics=\"median,IQR\", \n output=\"r.boxplot.png\",\n flags=\"oc\")\n```\n:::\n\n:::\n\n\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\n::: {.cell}\n\n```{.bash .cell-code}\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\n\n# Python\n\n\n::: {.cell}\n\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::: {layout-ncol=2}\n\n\n\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\n::: {.cell}\n\n```{.bash .cell-code}\ng.extension extension=v.histogram\n\nv.boxplot -o -r map=bridges column=WIDTH group_by=YEAR_BUILT where=\"YEAR_BUILT < '1920'\" order=ascending plot_output=boxplot_bridges_width_per_year.png\n```\n:::\n\n\n# Python\n\n\n::: {.cell}\n\n```{.python .cell-code}\ngs.run_command(\"g.extension\", extension=\"v.histogram\")\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 plot_output=\"boxplot_bridges_width_per_year.png\", \n flags=\"or\")\n```\n:::\n\n:::\n\n\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\n::: {.cell}\n\n```{.bash .cell-code}\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\n\n# Python\n\n\n::: {.cell}\n\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\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\n::: {.cell}\n\n```{.bash .cell-code}\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\n\n# Python\n\n\n::: {.cell}\n\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\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 GIS 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\n::: {.cell}\n\n```{.bash .cell-code}\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\n\n# Python\n\n\n::: {.cell}\n\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\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\n::: {.cell}\n\n```{.bash .cell-code}\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\n\n# Python\n\n\n::: {.cell}\n\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\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\n::: {.cell}\n\n```{.bash .cell-code}\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\n\n# Python\n\n\n::: {.cell}\n\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### [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\n::: {.cell}\n\n```{.bash .cell-code}\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\n\n# Python\n\n\n::: {.cell}\n\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\n \n",
0 commit comments