<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://grasswiki.osgeo.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=%E2%9A%A0%EF%B8%8FBaharmon</id>
	<title>GRASS-Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://grasswiki.osgeo.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=%E2%9A%A0%EF%B8%8FBaharmon"/>
	<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/wiki/Special:Contributions/%E2%9A%A0%EF%B8%8FBaharmon"/>
	<updated>2026-05-26T06:55:34Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Open-Source_Ecosystem_Working_Group&amp;diff=27259</id>
		<title>Open-Source Ecosystem Working Group</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Open-Source_Ecosystem_Working_Group&amp;diff=27259"/>
		<updated>2023-10-13T03:46:53Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Open-source ecosystem working group is established to foster relations with other software communities and collaborate with them on improving the software integrations.&lt;br /&gt;
&lt;br /&gt;
== Scope ==&lt;br /&gt;
* foster relation with other software communities such as R and QGIS&lt;br /&gt;
* provide guidance to communities how to best integrate GRASS GIS&lt;br /&gt;
* identify issues other communities are facing when integrating GRASS GIS&lt;br /&gt;
* lower maintenance of GRASS integrations with other software&lt;br /&gt;
&lt;br /&gt;
== Members ==&lt;br /&gt;
Let us know who you are and what are your interests and topics you want to discuss and develop as part of this group.&lt;br /&gt;
&lt;br /&gt;
; [https://wiki.osgeo.org/wiki/Anna_Petrasova Anna Petrasova] (working group coordinator)&lt;br /&gt;
: Researcher, educator and software developer at North Carolina State University&lt;br /&gt;
: Topics of interest include lowering maintenance of R-GRASS and QGIS-GRASS integrations.&lt;br /&gt;
&lt;br /&gt;
; [https://wiki.osgeo.org/wiki/User:Wenzeslaus Vaclav (Vashek) Petras]&lt;br /&gt;
: Researcher and software developer at North Carolina State University&lt;br /&gt;
: Interested in ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; Loïc Bartoletti&lt;br /&gt;
:&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Florian Betz&lt;br /&gt;
:&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Hernán De Angelis&lt;br /&gt;
:&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Micha Silver&lt;br /&gt;
:&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Helmut Kudrnovsky&lt;br /&gt;
:&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Stefan Blumentrath&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Arnd Weber&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; [https://grasswiki.osgeo.org/wiki/User:Baharmon Brendan Harmon]&lt;br /&gt;
: Researcher and educator at Louisiana State University&lt;br /&gt;
: Topics of interest include the QGIS-GRASS integration&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To be added to this working group, please contact the group coordinator.&lt;br /&gt;
&lt;br /&gt;
== Communication Channels ==&lt;br /&gt;
* [https://lists.osgeo.org/mailman/listinfo/grass-user grass-user] and [https://lists.osgeo.org/mailman/listinfo/grass-dev grass-dev] mailing lists&lt;br /&gt;
* [https://github.com/OSGeo/grass OSGeo/grass GitHub issues and pull requests]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Community]]&lt;br /&gt;
[[Category:Working_Groups]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=User:Baharmon&amp;diff=27258</id>
		<title>User:Baharmon</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=User:Baharmon&amp;diff=27258"/>
		<updated>2023-10-13T03:45:50Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Brendan Harmon ===&lt;br /&gt;
&lt;br /&gt;
* Position: Assistant Professor&lt;br /&gt;
* Institution: Louisiana State University&lt;br /&gt;
* Location: Baton Rouge, Louisiana, USA&lt;br /&gt;
* Email: baharmon@lsu.edu&lt;br /&gt;
* Website: https://baharmon.github.io/&lt;br /&gt;
* Github: https://github.com/baharmon&lt;br /&gt;
* Orcid: 0000-0002-6218-9318&lt;br /&gt;
&lt;br /&gt;
;Profile last updated: October 2023&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=User:Baharmon&amp;diff=27257</id>
		<title>User:Baharmon</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=User:Baharmon&amp;diff=27257"/>
		<updated>2023-10-13T03:44:05Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
{{OSGeo Member&lt;br /&gt;
|Name=Brendan Harmon&lt;br /&gt;
|JobTitle=Assistant Professor&lt;br /&gt;
|Company=Louisiana State University&lt;br /&gt;
|Country=USA&lt;br /&gt;
|State=LA&lt;br /&gt;
|City=Baton Rouge&lt;br /&gt;
|Coordinate=30.411777, -91.180905&lt;br /&gt;
|LocalChapter=North America&lt;br /&gt;
|Email=baharmon@lsu.edu&lt;br /&gt;
|Website=https://baharmon.github.io/&lt;br /&gt;
|Languages=English&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Brendan Harmon ===&lt;br /&gt;
&lt;br /&gt;
* Orcid: 0000-0002-6218-9318&lt;br /&gt;
* Github: https://github.com/baharmon&lt;br /&gt;
* Web: https://baharmon.github.io/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Profile last updated: October 2023&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=User:Baharmon&amp;diff=27256</id>
		<title>User:Baharmon</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=User:Baharmon&amp;diff=27256"/>
		<updated>2023-10-13T03:40:54Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{OSGeo Member&lt;br /&gt;
|Name=Brendan Harmon&lt;br /&gt;
|JobTitle=Assistant Professor&lt;br /&gt;
|Company=Louisiana State University&lt;br /&gt;
|Country=USA&lt;br /&gt;
|State=LA&lt;br /&gt;
|City=Baton Rouge&lt;br /&gt;
|Coordinate=30.411777, -91.180905&lt;br /&gt;
|LocalChapter=North America&lt;br /&gt;
|Email=baharmon@lsu.edu&lt;br /&gt;
|Website=https://baharmon.github.io/&lt;br /&gt;
|Languages=English&lt;br /&gt;
}}&lt;br /&gt;
{{OSGeo Experience&lt;br /&gt;
|User=Yes&lt;br /&gt;
|Committee=No&lt;br /&gt;
|Board=No&lt;br /&gt;
|Coder=No&lt;br /&gt;
|Translate=No&lt;br /&gt;
|PSC=No&lt;br /&gt;
|ExBoard=No&lt;br /&gt;
|Charter=No&lt;br /&gt;
|Chair=No&lt;br /&gt;
|SolKatz=No&lt;br /&gt;
|Committer=No&lt;br /&gt;
}}&lt;br /&gt;
=== Brendan Harmon ===&lt;br /&gt;
&lt;br /&gt;
* Orcid: 0000-0002-6218-9318&lt;br /&gt;
* Github: https://github.com/baharmon&lt;br /&gt;
* Web: https://baharmon.github.io/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Profile last updated: October 2023&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Open-Source_Ecosystem_Working_Group&amp;diff=27255</id>
		<title>Open-Source Ecosystem Working Group</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Open-Source_Ecosystem_Working_Group&amp;diff=27255"/>
		<updated>2023-10-13T03:07:54Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Open-source ecosystem working group is established to foster relations with other software communities and collaborate with them on improving the software integrations.&lt;br /&gt;
&lt;br /&gt;
== Scope ==&lt;br /&gt;
* foster relation with other software communities such as R and QGIS&lt;br /&gt;
* provide guidance to communities how to best integrate GRASS GIS&lt;br /&gt;
* identify issues other communities are facing when integrating GRASS GIS&lt;br /&gt;
* lower maintenance of GRASS integrations with other software&lt;br /&gt;
&lt;br /&gt;
== Members ==&lt;br /&gt;
Let us know who you are and what are your interests and topics you want to discuss and develop as part of this group.&lt;br /&gt;
&lt;br /&gt;
; [https://wiki.osgeo.org/wiki/Anna_Petrasova Anna Petrasova] (working group coordinator)&lt;br /&gt;
: Researcher, educator and software developer at North Carolina State University&lt;br /&gt;
: Topics of interest include lowering maintenance of R-GRASS and QGIS-GRASS integrations.&lt;br /&gt;
&lt;br /&gt;
; [https://wiki.osgeo.org/wiki/User:Wenzeslaus Vaclav (Vashek) Petras]&lt;br /&gt;
: Researcher and software developer at North Carolina State University&lt;br /&gt;
: Interested in ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; Loïc Bartoletti&lt;br /&gt;
:&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Florian Betz&lt;br /&gt;
:&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Hernán De Angelis&lt;br /&gt;
:&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Micha Silver&lt;br /&gt;
:&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Helmut Kudrnovsky&lt;br /&gt;
:&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Stefan Blumentrath&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Arnd Weber&lt;br /&gt;
:&lt;br /&gt;
&lt;br /&gt;
; Brendan Harmon&lt;br /&gt;
: Researcher and educator at Louisiana State University&lt;br /&gt;
: Topics of interest include the QGIS-GRASS integration&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To be added to this working group, please contact the group coordinator.&lt;br /&gt;
&lt;br /&gt;
== Communication Channels ==&lt;br /&gt;
* [https://lists.osgeo.org/mailman/listinfo/grass-user grass-user] and [https://lists.osgeo.org/mailman/listinfo/grass-dev grass-dev] mailing lists&lt;br /&gt;
* [https://github.com/OSGeo/grass OSGeo/grass GitHub issues and pull requests]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Community]]&lt;br /&gt;
[[Category:Working_Groups]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_Community_Meeting_Prague_2023&amp;diff=26992</id>
		<title>GRASS Community Meeting Prague 2023</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_Community_Meeting_Prague_2023&amp;diff=26992"/>
		<updated>2023-05-29T19:27:04Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: /* Via chat or hangout */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{toc|right}}&lt;br /&gt;
The GRASS GIS team is organizing the ''GRASS GIS Community Meeting with contributors, power users and developers'' from '''June 2 to June 6, 2023''' to celebrate GRASS GIS '''40th birthday''' (by contributing to GRASS GIS of course).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;slideshow&amp;quot;&amp;gt;&lt;br /&gt;
Image:grass-sprint-prague.jpg|Prague 2013&lt;br /&gt;
Image:Grass_sprint2018_bonn_fotowall.jpg|Bonn 2018&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
GRASS GIS Community Meeting is a great occasion for folks to support the development by actively contributing to the source code, documentation (manuals, wiki, tutorials), translations, website or likewise. The '''community''' meeting is also a get-together where supporters, contributors, power users and developers make decisions and tackle larger problems related to the project, discuss and collaboratively resolve bugs, plan the direction for the project and work on new features. We welcome people committed to improving the GRASS GIS project and the interfaces to QGIS, GDAL, PostGIS, R, OGC Services and desiring to '''celebrate with us the 40th GRASS GIS birthday!!'''&lt;br /&gt;
&lt;br /&gt;
In this meeting, we will work on GRASS GIS and integrations with related OSGeo projects. We will revise connection to QGIS to make it easier to maintain, and we will work on migration of the build to CMake to improve Windows builds including PDAL support. Furthermore, we will start moving documentation to Markdown to make it easier to contribute to and we will add images and examples for tools and workflows which still miss them. Finally, we will automate and document maintenance processes to reduce the burden on maintainers and thus improve the project sustainability. &lt;br /&gt;
&lt;br /&gt;
Note that while we have our general plan, we can't accept any earmarked donations, i.e., we can't make any promises for a specific work to be done. We do require participants to work on GRASS GIS or connections to other projects. However, we leave them the freedom to work on what they think is the best contribution to the project at that time given their skills and time available.&lt;br /&gt;
&lt;br /&gt;
For the detailed agenda and individual's plans, see below.&lt;br /&gt;
&lt;br /&gt;
== Sponsors ==&lt;br /&gt;
&lt;br /&gt;
We welcome '''financial contributions''' to support the meeting and we are looking for sponsors to cover costs such as meals or to help reducing travel and accommodation expenses for GRASS developers who volunteer their time. If you are interested in sponsoring the GRASS Community Meeting, please see our&lt;br /&gt;
&lt;br /&gt;
::: '''[https://opencollective.com/osgeo/projects/grass/contribute/grass-community-meeting-prague-2023-55074 OpenCollective GRASS Community Meeting Prague 2023 Tier]'''&lt;br /&gt;
&lt;br /&gt;
Any surplus at the end of the event will used for future activities of the GRASS GIS project such as the successful [[Student Grants|student mini grant program]].&lt;br /&gt;
&lt;br /&gt;
This GRASS Community Meeting is a great occasion for you to support the development of GRASS. With your contribution you'll enable more developers to meet. Community meetings are important opportunities for developers to discuss, fix bugs, plan the direction for the project and work on new features. Please see below for the detailed agenda. The developers and contributors are donating their valuable time, so it would be great if in-kind funding can be made available from within the community to cover out-of-pocket expenses. All of the work that takes place at the community meeting will be directly contributed back into the GRASS project to the benefit of everyone who uses it.&lt;br /&gt;
&lt;br /&gt;
=== Thanks to our sponsors ===&lt;br /&gt;
&lt;br /&gt;
We are grateful for the support which we have received to organize this GRASS Community Meeting:&lt;br /&gt;
&lt;br /&gt;
[[File:Osgeo logo.png|none|left|alt=Light and dark green logo of OSGeo saying Your Open Source Compass|Open Source Geospatial Foundation]]&lt;br /&gt;
* [https://www.osgeo.org/ OSGeo]: 7303 USD (approved budget contribution, [https://www.loomio.com/p/2m75BZkL/motion-to-approve-7303-to-support-grass-gis-community-meeting motion])&lt;br /&gt;
&lt;br /&gt;
[[File:FOSSGIS_eV_logo.png|none|left|400px|alt=Logo of FOSSGIS e.V.|FOSSGIS e.V.]]&lt;br /&gt;
* [https://www.fossgis.de/ FOSSGIS e.V.]: 5000 EUR (approved budget contribution, [https://www.fossgis.de/wiki/F%C3%B6rderantr%C3%A4ge/GRASS_GIS_Community_Meeting_2023 request])&lt;br /&gt;
&lt;br /&gt;
[[File:OSGeo JP logo for web.png|none|left|400px|alt=OSGeo.JP]]&lt;br /&gt;
* [https://www.osgeo.jp/ OSGeo Japan]: 550 USD (through Open Collective)&lt;br /&gt;
&lt;br /&gt;
Individuals:&lt;br /&gt;
* MarWe 50 USD&lt;br /&gt;
* Nick Brady 50 USD&lt;br /&gt;
* José Ramón 50 USD&lt;br /&gt;
* Johannes Brauner 30 USD&lt;br /&gt;
* Peter Löwe 30 USD&lt;br /&gt;
* Evan Kay 10 USD&lt;br /&gt;
* Joaquin Perez Valera 5 USD&lt;br /&gt;
* Anonymous sponsors 2750 USD&lt;br /&gt;
&lt;br /&gt;
In-kind contributions:&lt;br /&gt;
&lt;br /&gt;
* Faculty of Civil Engineering Czech Technical University in Prague (FCE CTU) - space and personnel time (planning, preparation)&lt;br /&gt;
* North Carolina State University - personnel time (planning, preparation)&lt;br /&gt;
* mundialis GmbH &amp;amp; Co. KG - personnel time (planning, preparation)&lt;br /&gt;
* CONICET - personnel time (planning, preparation)&lt;br /&gt;
&lt;br /&gt;
== Timing  ==&lt;br /&gt;
&lt;br /&gt;
'''When''': June 2-6, 2023&lt;br /&gt;
&lt;br /&gt;
Of course you are invited to join or leave the meeting whenever you want.&lt;br /&gt;
&lt;br /&gt;
== Venue ==&lt;br /&gt;
&lt;br /&gt;
[[Image:logo_cvut.jpg|130px|left]]&lt;br /&gt;
Department of Geomatics&amp;lt;br&amp;gt;&lt;br /&gt;
[https://www.fsv.cvut.cz/?lang=en Faculty of Civil Engineering]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://www.cvut.cz/en Czech Technical University in Prague], {{wikipedia|Czech Republic}}&amp;lt;br&amp;gt;&lt;br /&gt;
Thákurova 7/2077, Prague&amp;lt;br&amp;gt;&lt;br /&gt;
Room B868&amp;lt;br&amp;gt;&lt;br /&gt;
[https://en.mapy.cz/s/debazefuse Map]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prague has an international [http://www.prg.aero/en/ airport] and is also reachable by train, bus or car.&lt;br /&gt;
&lt;br /&gt;
== Accommodation and Costs ==&lt;br /&gt;
&lt;br /&gt;
Participants should plan for the following costs:&lt;br /&gt;
&lt;br /&gt;
* The participation is free of charge&lt;br /&gt;
* Travel to Prague, variable depending on where you come from, reimbursements depending on the financial contributions provided by the community&lt;br /&gt;
* Accommodation and meals (with the donated sponsorship money we will try to cover some expenses of the participants)&lt;br /&gt;
'''Please note''': The currency in Czech Republic is {{wikipedia|Czech crown}} (CZK, koruna, Kč). 100 Czech crowns are about 4 Euros (see [https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/ current rates]).&lt;br /&gt;
&lt;br /&gt;
Please let us know your time of arrival and departure, so we can book accommodations and organize the logistics.&lt;br /&gt;
&lt;br /&gt;
Financial support: (partial) travel grants can be payed upon request thanks to our sponsors!&lt;br /&gt;
&lt;br /&gt;
== Agenda - What we plan to do ==&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The program is generally open for your ideas. Please write an email to the [http://lists.osgeo.org/mailman/listinfo/grass-dev GRASS developer list] to discuss your contribution.&lt;br /&gt;
&lt;br /&gt;
During the meeting we will work on GRASS GIS on these tasks (please add more!):&lt;br /&gt;
&lt;br /&gt;
* We will update and revise the [https://github.com/qgis/QGIS/tree/master/python/plugins/grassprovider GRASS GIS Integration with QGIS] to simplify maintenance.&lt;br /&gt;
* Furthermore, we will migrate the compilation technology to CMake to significantly improve the Windows builds including PDAL support and become binary compatible with OSGeo4W.&lt;br /&gt;
* The extensive GRASS documentation will be converted from HTML to Markdown to facilitate future collaboration.&lt;br /&gt;
* Pictures, examples and workflows will be added to the documentation where they are still missing.&lt;br /&gt;
* Software maintenance processes are automated and documented to reduce the burden on maintainers and thus improve the sustainability of the project.&lt;br /&gt;
&lt;br /&gt;
This means that there are tasks from both the programming and documentation areas to appeal to a wide range of interested parties.&lt;br /&gt;
&lt;br /&gt;
Further details about the action items you '''find [[Talk:GRASS Community Meeting Prague 2023|here]]''' and below. Topics cover non-technical, semi-technical, and technical issues.&lt;br /&gt;
&lt;br /&gt;
=== Timeline ===&lt;br /&gt;
&lt;br /&gt;
(agenda is under development, but also flexible)&lt;br /&gt;
&lt;br /&gt;
==== Thursday, 1 June ====&lt;br /&gt;
&lt;br /&gt;
* Arrival&lt;br /&gt;
&lt;br /&gt;
==== Friday, 2 June ====&lt;br /&gt;
&lt;br /&gt;
* 10:00 meeting starts in the room B-868&lt;br /&gt;
* Review the plan for the next days&lt;br /&gt;
* API for use in Python and in other projects (e.g., QGIS)&lt;br /&gt;
* Parallelizations&lt;br /&gt;
&lt;br /&gt;
==== Saturday, 3 June ====&lt;br /&gt;
&lt;br /&gt;
* Reducing cost of distribution on Windows&lt;br /&gt;
* Group photo 1&lt;br /&gt;
&lt;br /&gt;
==== Sunday, 4 June ====&lt;br /&gt;
&lt;br /&gt;
* Compilation CMake (Windows, Linux)&lt;br /&gt;
* Connections in general, rgrass,  qgisprocess&lt;br /&gt;
* Group photo 2&lt;br /&gt;
&lt;br /&gt;
==== Monday, 5 June ====&lt;br /&gt;
&lt;br /&gt;
* Connections in general, QGIS, rgrass, qgisprocess&lt;br /&gt;
* Parallelizations&lt;br /&gt;
* grass.jupyter&lt;br /&gt;
&lt;br /&gt;
==== Tuesday, 6 June ====&lt;br /&gt;
&lt;br /&gt;
* Connections in general, QGIS&lt;br /&gt;
* Parallelizations&lt;br /&gt;
* grass.jupyter&lt;br /&gt;
&lt;br /&gt;
==== Wednesday, 7 June ====&lt;br /&gt;
&lt;br /&gt;
* Departure&lt;br /&gt;
&lt;br /&gt;
== Participation ==&lt;br /&gt;
&lt;br /&gt;
We are planning for an attendance of 20 people (i.e., coding places) but of course you are welcome to join us and bring new ideas with you: we'll make more places available. Please add your name here or contact [[User:Landa|Martin Landa]] &amp;lt;tt&amp;gt;&amp;lt;landa.martin at gmail.com&amp;gt;&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
=== In person ===&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable sortable&amp;quot;   border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;4&amp;quot; rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:1em 1em 1em 0; border:solid 1px #AAAAAA; border-collapse:collapse; background-color:#edf9c7; font-size:95%; empty-cells:show;&amp;quot; &lt;br /&gt;
!width=50px|'''Number'''&lt;br /&gt;
!width=130px|'''Participant '''&lt;br /&gt;
!width=100px|'''Country'''&lt;br /&gt;
!width=100px|'''Arrival'''&lt;br /&gt;
!width=100px|'''Departure'''&lt;br /&gt;
!'''Topics'''&lt;br /&gt;
!'''Notes'''&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|[[User:Landa|Martin Landa]]&lt;br /&gt;
| Czech Republic&lt;br /&gt;
| June 1&lt;br /&gt;
| June 7&lt;br /&gt;
| Python: create_location ([https://github.com/OSGeo/grass/issues/1987 #1987]), Graphical Modeler improvements and single window layout integration&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
| Micha Silver&lt;br /&gt;
| Israel&lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| Addon to derive soil moisture from Sentinel 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|[https://www.osgeo.org/member/kudrnovsky/ Helmut Kudrnovsky]&lt;br /&gt;
| Austria&lt;br /&gt;
| June 2 (18:37) by train&lt;br /&gt;
| June 4 (18:24) by train &lt;br /&gt;
| support CMake transition&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|[[User:Neteler|Markus Neteler]]&lt;br /&gt;
| Germany&lt;br /&gt;
| June 2 (17:17)&lt;br /&gt;
| June 6 (12:43)&lt;br /&gt;
| translations, manual pages, ..., see [[Talk:GRASS_Community_Meeting_Prague_2023#Markus_Neteler|my list in &amp;quot;Discussion&amp;quot; page]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|[[User:pesekon2|Ondřej Pešek]]&lt;br /&gt;
| Czech Republic&lt;br /&gt;
| June 2 (17:17)&lt;br /&gt;
| June 6 (12:43)&lt;br /&gt;
| Python 3.12-connected issues, gmodeler&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
| [[User:helena|Helena Mitasova]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
| [[User:wenzeslaus|Vaclav Petras]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 1&lt;br /&gt;
| June 7&lt;br /&gt;
| init and other Python API topics, support CMake transition, revise connection with QGIS and other tools, funding&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
| [[User:Annakrat|Anna Petrasova]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 1&lt;br /&gt;
| June 7&lt;br /&gt;
| parallelization documentation, grass.jupyter, R and QGIS integration&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
| [[User:Ctwhite|Corey White]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 2 (10:55)&lt;br /&gt;
| June 7&lt;br /&gt;
| Connections with other tools, OpenPlains, JSON outputs&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
| [[User:MarisN|Maris Nartiss]]&lt;br /&gt;
| Latvia&lt;br /&gt;
| June 2 (14:30)&lt;br /&gt;
| June 6 (12:00)&lt;br /&gt;
| Improvements of imagery modules (push i.svm.*; i.signatures; ?)&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
| [[User:Aaronsms|Aaron Saw Min Sern]]&lt;br /&gt;
| Singapore&lt;br /&gt;
| June 1&lt;br /&gt;
| June 7&lt;br /&gt;
| Support CMake transition, r.mapcalc parallelization&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
| [[User:Ldesousa|Luís de Sousa]]&lt;br /&gt;
| The Netherlands&lt;br /&gt;
| June 1 (20:00)&lt;br /&gt;
| June 5 (20:45)&lt;br /&gt;
| Update r.mblend add-on; test CMake transition.&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
|13&lt;br /&gt;
| Caitlin Haedrich&lt;br /&gt;
| United States&lt;br /&gt;
| June 1&lt;br /&gt;
| June 7&lt;br /&gt;
| grass.jupyter&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
| Linda Kladivová&lt;br /&gt;
| Czech Republic&lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| Single-Window layout issues and improvements&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
| Carmen Tawalika&lt;br /&gt;
| Germany&lt;br /&gt;
| June 2 (17:17)&lt;br /&gt;
| June 6 (12:43)&lt;br /&gt;
| Happy to assist with general topics like documentation + automation, in doubt something related to actinia&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
| Floris Vanderhaeghe&lt;br /&gt;
| Belgium&lt;br /&gt;
| June 3 (train 19:17)&lt;br /&gt;
| June 6 (train 8:25)&lt;br /&gt;
| Helping in interfacing GRASS from R (rgrass &amp;amp; qgisprocess packages)&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If you are arriving or departing on the days of the event, please specify the time, too.&lt;br /&gt;
&lt;br /&gt;
=== Via chat or hangout ===&lt;br /&gt;
&lt;br /&gt;
Join our [https://app.gitter.im/#/room/#grassgis_community:gitter.im Gitter chatroom]&lt;br /&gt;
&lt;br /&gt;
Gitter has a video (and backup will be Zoom).&lt;br /&gt;
&lt;br /&gt;
Participating virtually:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable sortable&amp;quot;   border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;4&amp;quot; rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:1em 1em 1em 0; border:solid 1px #AAAAAA; border-collapse:collapse; background-color:#edf9c7; font-size:95%; empty-cells:show;&amp;quot; &lt;br /&gt;
!width=50px|'''Number'''&lt;br /&gt;
!width=130px|'''Participant '''&lt;br /&gt;
!width=100px|'''Country'''&lt;br /&gt;
!'''Topics'''&lt;br /&gt;
!'''Times, synchronous or fully asynchronous'''&lt;br /&gt;
!'''Notes'''&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|[[User:Baharmon|Brendan Harmon]]&lt;br /&gt;
| United States&lt;br /&gt;
| Update integration with QGIS&lt;br /&gt;
| Available 8:00 AM CST (UTC-6) onwards&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|[[User:veroandreo|Veronica Andreo]]&lt;br /&gt;
| Argentina&lt;br /&gt;
| Mission and vision, interfaces with QGIS and R, sponsoring, ... [https://grasswiki.osgeo.org/wiki/Talk:GRASS_Community_Meeting_Prague_2023#Vero see discussion tab]&lt;br /&gt;
| available from 8:00 AM ART (UTC-3) onward&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|[[User:Nobeeakon|Daniel T]]&lt;br /&gt;
| Mexico&lt;br /&gt;
| &lt;br /&gt;
| some availability through the days :/&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|[[User:LBartoletti|Loïc Bartoletti]]&lt;br /&gt;
| France&lt;br /&gt;
| QGIS Integration, support CMake transition&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Timing of hangout meetings ====&lt;br /&gt;
&lt;br /&gt;
Vero: available from 8:00 AM ART (UTC-3) onward&lt;br /&gt;
&lt;br /&gt;
=== Collaborative document scratching ===&lt;br /&gt;
&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
== Individual Preparation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Bring your own computer&lt;br /&gt;
* Bring {{wikipedia|AC adapter|power connector adapter}} if needed (Czech Republic: 230V, 50Hz, {{wikipedia|File:Euro-Flachstecker_2.jpg|Type C Europlugs}} are common and also {{wikipedia|File:French_plug_and_socket.jpg|Type E}})&lt;br /&gt;
* Install git and the compiler tools, and come with a working GRASS development environment if possible.&lt;br /&gt;
&lt;br /&gt;
== Broadcast &amp;amp; Video ==&lt;br /&gt;
&lt;br /&gt;
During the event :)&lt;br /&gt;
&lt;br /&gt;
== Photos ==&lt;br /&gt;
&lt;br /&gt;
Also during the event :)&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
* '''How was it last time?'''&lt;br /&gt;
** Very nice, see [[GRASS_GIS at OSGeo Virtual Community Sprint 2020]]!&lt;br /&gt;
* ''Is the GRASS Community Meeting just a coding event?''&lt;br /&gt;
** It is mainly a coding and documentation event. It is a working session for people who are already participants in the GRASS project and/or are committed to improving the GRASS project.&lt;br /&gt;
** On demand we can do some presentations of current working GRASS implementation and new upcoming features to spread the idea of Open Source GIS software.&lt;br /&gt;
* ''Is the GRASS Community Meeting for developers only?''&lt;br /&gt;
** No: anybody can help, with testing, checking out bugs and fixes, documentation and more.&lt;br /&gt;
* ''Where can I get help and more information about the community meeting?''&lt;br /&gt;
** Contact [[User:Landa|Martin Landa]] &amp;lt;tt&amp;gt;&amp;lt;landa.martin at gmail.com&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Report and press release ==&lt;br /&gt;
&lt;br /&gt;
TBD: After the event :-)&lt;br /&gt;
&lt;br /&gt;
We'll esp. craft a report for our sponsors.&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Code Sprint]]&lt;br /&gt;
[[Category: 2023]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_Community_Meeting_Prague_2023&amp;diff=26856</id>
		<title>GRASS Community Meeting Prague 2023</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_Community_Meeting_Prague_2023&amp;diff=26856"/>
		<updated>2023-04-04T02:23:17Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: /* Via chat or hangout */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{toc|right}}&lt;br /&gt;
The GRASS GIS team is organizing the ''GRASS GIS Community Meeting with contributors, power users and developers'' from '''June 2 to June 6, 2023''' to celebrate GRASS GIS '''40th birthday'''. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;slideshow&amp;quot;&amp;gt;&lt;br /&gt;
Image:grass-sprint-prague.jpg|Prague 2013&lt;br /&gt;
Image:Grass_sprint2018_bonn_fotowall.jpg|Bonn 2018&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
GRASS GIS Community Meeting is a great occasion for folks to support the development by actively contributing to the source code, documentation (manuals, wiki, tutorials), translations, website or likewise. The '''community''' meeting is also a get-together where supporters, contributors, power users and developers make decisions and tackle larger problems related to the project, discuss and collaboratively resolve bugs, plan the direction for the project and work on new features. We welcome people committed to improving the GRASS GIS project and the interfaces to QGIS, GDAL, PostGIS, R statistics, OGC Services and willing to '''celebrate with us the 40th GRASS GIS birthday!!'''&lt;br /&gt;
&lt;br /&gt;
For the detailed agenda, see below.&lt;br /&gt;
&lt;br /&gt;
== Sponsors ==&lt;br /&gt;
&lt;br /&gt;
We welcome '''financial contributions''' to support the meeting and we are looking for sponsors to cover costs such as meals or to help reducing travelling and accommodation expenses for GRASS developers with far arrival. If you are interested in sponsoring the GRASS Community Meeting, please read about&lt;br /&gt;
&lt;br /&gt;
:::'''sponsoring the GRASS GIS project''' at '''[https://grass.osgeo.org/contribute/sponsoring/ https://grass.osgeo.org/contribute/sponsoring/]'''&lt;br /&gt;
&lt;br /&gt;
Note that it is also possible to &amp;lt;b&amp;gt;buy a round of beers for the developers with a quick click&amp;lt;/b&amp;gt; using the Open Collective &amp;quot;Contribute Money&amp;quot; button https://opencollective.com/osgeo/projects/grass&lt;br /&gt;
&lt;br /&gt;
Any surplus at the end of the event will be turned over to the GRASS GIS project.&lt;br /&gt;
&lt;br /&gt;
This GRASS Community Meeting is a great occasion for you to support the development of GRASS. With your contribution you'll enable more developers to meet. Community meetings are important opportunities for developers to discuss, fix bugs, plan the direction for the project and work on new features. Please see below for the detailed agenda. The developers and contributors are donating their valuable time, so it would be great if in-kind funding can be made available from within the community to cover out-of-pocket expenses. All of the work that takes place at the community meeting will be directly contributed back into the GRASS project to the benefit of everyone who uses it.&lt;br /&gt;
&lt;br /&gt;
=== Thanks to our sponsors ===&lt;br /&gt;
&lt;br /&gt;
We are grateful for the support which we have received to organize this GRASS Community Meeting:&lt;br /&gt;
&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
== Timing  ==&lt;br /&gt;
&lt;br /&gt;
'''When''': June 2-6, 2023&lt;br /&gt;
&lt;br /&gt;
Of course you are invited to join or leave the meeting whenever you want.&lt;br /&gt;
&lt;br /&gt;
== Venue ==&lt;br /&gt;
&lt;br /&gt;
[[Image:logo_cvut.jpg|130px|left]]&lt;br /&gt;
Department of Geomatics&amp;lt;br&amp;gt;&lt;br /&gt;
[https://www.fsv.cvut.cz/?lang=en Faculty of Civil Engineering]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://www.cvut.cz/en Czech Technical University in Prague], {{wikipedia|Czech Republic}}&amp;lt;br&amp;gt;&lt;br /&gt;
Thákurova 7/2077, Prague&amp;lt;br&amp;gt;&lt;br /&gt;
Room B868&amp;lt;br&amp;gt;&lt;br /&gt;
[https://en.mapy.cz/s/debazefuse Map]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prague has an international [http://www.prg.aero/en/ airport] and is also reachable by train, bus or car.&lt;br /&gt;
&lt;br /&gt;
== Accommodation and Costs ==&lt;br /&gt;
&lt;br /&gt;
Participants should plan for the following costs:&lt;br /&gt;
&lt;br /&gt;
* The participation is free of charge&lt;br /&gt;
* Travel to Prague, variable depending on where you come from&lt;br /&gt;
* Accommodation and meals (with the donated sponsorship money we will try to cover some expenses of the participants)&lt;br /&gt;
'''Please note''': The currency in Czech Republic is {{wikipedia|Czech crown}} (CZK, koruna, Kč). 100 Czech crowns are about 4 Euros (see [https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/ current rates]).&lt;br /&gt;
&lt;br /&gt;
Please let us know your time of arrival and departure, so we can book accommodations and organize the logistics.&lt;br /&gt;
&lt;br /&gt;
Financial support: (partial) travel grants can be payed upon request thanks to our sponsors!&lt;br /&gt;
&lt;br /&gt;
== Agenda - What we plan to do ==&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The program is generally open for your ideas. Please write an email to the [http://lists.osgeo.org/mailman/listinfo/grass-dev GRASS developer list] to discuss your contribution.&lt;br /&gt;
&lt;br /&gt;
During the meeting we will work on GRASS GIS on these tasks (please add more!):&lt;br /&gt;
&lt;br /&gt;
* We will update and revise the [https://github.com/qgis/QGIS/tree/master/python/plugins/grassprovider GRASS GIS Integration with QGIS] to simplify maintenance.&lt;br /&gt;
* Furthermore, we will migrate the compilation technology to CMake to significantly improve the Windows builds including PDAL support and become binary compatible with OSGeo4W.&lt;br /&gt;
* The extensive GRASS documentation will be converted from HTML to Markdown to facilitate future collaboration.&lt;br /&gt;
* Pictures, examples and workflows will be added to the documentation where they are still missing.&lt;br /&gt;
* Software maintenance processes are automated and documented to reduce the burden on maintainers and thus improve the sustainability of the project.&lt;br /&gt;
&lt;br /&gt;
This means that there are tasks from both the programming and documentation areas to appeal to a wide range of interested parties.&lt;br /&gt;
&lt;br /&gt;
Further details about the action items you '''find [[Talk:GRASS Community Meeting Prague 2023|here]]''' and below. Topics cover non-technical, semi-technical, and technical issues.&lt;br /&gt;
&lt;br /&gt;
=== Timeline ===&lt;br /&gt;
&lt;br /&gt;
Will be specified later.&lt;br /&gt;
&lt;br /&gt;
==== Friday, 2 June ====&lt;br /&gt;
&lt;br /&gt;
==== Saturday, 3 June ====&lt;br /&gt;
&lt;br /&gt;
==== Sunday, 4 June ====&lt;br /&gt;
&lt;br /&gt;
==== Monday, 5 June ====&lt;br /&gt;
&lt;br /&gt;
==== Tuesday, 6 June ====&lt;br /&gt;
&lt;br /&gt;
== Participation ==&lt;br /&gt;
&lt;br /&gt;
We are planning for an attendance of 20 people (i.e., coding places) but of course you are welcome to join us and bring new ideas with you: we'll make more places available. Please add your name here or contact [[User:Landa|Martin Landa]] &amp;lt;tt&amp;gt;&amp;lt;landa.martin at gmail.com&amp;gt;&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
=== In person ===&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable sortable&amp;quot;   border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;4&amp;quot; rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:1em 1em 1em 0; border:solid 1px #AAAAAA; border-collapse:collapse; background-color:#edf9c7; font-size:95%; empty-cells:show;&amp;quot; &lt;br /&gt;
!width=50px|'''Number'''&lt;br /&gt;
!width=130px|'''Participant '''&lt;br /&gt;
!width=100px|'''Country'''&lt;br /&gt;
!width=100px|'''Arrival'''&lt;br /&gt;
!width=100px|'''Departure'''&lt;br /&gt;
!'''Topics'''&lt;br /&gt;
!width=75px|'''T-Shirt'''&lt;br /&gt;
!'''Notes'''&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|[[User:Landa|Martin Landa]]&lt;br /&gt;
| Czech Republic&lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| &lt;br /&gt;
| XL&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
| Micha Silver&lt;br /&gt;
| Israel&lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| Addon to derive soil moisture from Sentinel 2&lt;br /&gt;
| XXL&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|[https://www.osgeo.org/member/kudrnovsky/ Helmut Kudrnovsky]&lt;br /&gt;
| Austria&lt;br /&gt;
| June 2&lt;br /&gt;
| June 4&lt;br /&gt;
| &lt;br /&gt;
| L&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|[[User:Neteler|Markus Neteler]]&lt;br /&gt;
| Germany&lt;br /&gt;
| June 2&lt;br /&gt;
| June 6 (12:43)&lt;br /&gt;
| see [[Talk:GRASS_Community_Meeting_Prague_2023#Markus_Neteler|my list in &amp;quot;Discussion&amp;quot; page]]&lt;br /&gt;
| L&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|[[User:pesekon2|Ondřej Pešek]]&lt;br /&gt;
| Czech Republic&lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| &lt;br /&gt;
| M&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
| [[User:helena|Helena Mitasova]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
|&lt;br /&gt;
| S&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
| [[User:wenzeslaus|Vaclav Petras]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| Support CMake transition, revise connection with QGIS and other tools&lt;br /&gt;
| M&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
| [[User:Annakrat|Anna Petrasova]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| parallelization, grass.jupyter&lt;br /&gt;
| S&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
| [[User:Ctwhite|Corey White]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
|&lt;br /&gt;
| XL&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Via chat or hangout ===&lt;br /&gt;
&lt;br /&gt;
Join our [https://app.gitter.im/#/room/#grassgis_community:gitter.im Gitter chatroom]&lt;br /&gt;
&lt;br /&gt;
TBD: Google Meet / Zoom / ???&lt;br /&gt;
&lt;br /&gt;
Participating virtually:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable sortable&amp;quot;   border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;4&amp;quot; rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:1em 1em 1em 0; border:solid 1px #AAAAAA; border-collapse:collapse; background-color:#edf9c7; font-size:95%; empty-cells:show;&amp;quot; &lt;br /&gt;
!width=50px|'''Number'''&lt;br /&gt;
!width=130px|'''Participant '''&lt;br /&gt;
!width=100px|'''Country'''&lt;br /&gt;
!'''Topics'''&lt;br /&gt;
!'''Notes'''&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|[[User:Baharmon|Brendan Harmon]]&lt;br /&gt;
| United States&lt;br /&gt;
| Update integration with QGIS&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Timing of hangout meetings ====&lt;br /&gt;
&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
=== Collaborative document scratching ===&lt;br /&gt;
&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
== Individual Preparation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Bring your own computer&lt;br /&gt;
* Bring {{wikipedia|AC adapter|power connector adapter}} if needed (Czech Republic: 230V, 50Hz, {{wikipedia|File:Euro-Flachstecker_2.jpg|Type C Europlugs}} are common and also {{wikipedia|File:French_plug_and_socket.jpg|Type E}})&lt;br /&gt;
* Install subversion and the compiler tools, and come with a working GRASS development environment if possible.&lt;br /&gt;
&lt;br /&gt;
== Broadcast &amp;amp; Video ==&lt;br /&gt;
&lt;br /&gt;
During the event :)&lt;br /&gt;
&lt;br /&gt;
== Photos ==&lt;br /&gt;
&lt;br /&gt;
Also during the event :)&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
* '''How was it last time?'''&lt;br /&gt;
** Very nice, see [[GRASS_GIS at OSGeo Virtual Community Sprint 2020]]!&lt;br /&gt;
* ''Is the GRASS Community Meeting just a coding event?''&lt;br /&gt;
** It is mainly a coding and documentation event. It is a working session for people who are already participants in the GRASS project and/or are committed to improving the GRASS project.&lt;br /&gt;
** On demand we can do some presentations of current working GRASS implementation and new upcoming features to spread the idea of Open Source GIS software.&lt;br /&gt;
* ''Is the GRASS Community Meeting for developers only?''&lt;br /&gt;
** No: anybody can help, with testing, checking out bugs and fixes, documentation and more.&lt;br /&gt;
* ''Where can I get help and more information about the community meeting?''&lt;br /&gt;
** Contact [[User:Landa|Martin Landa]] &amp;lt;tt&amp;gt;&amp;lt;landa.martin at gmail.com&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Press Release ==&lt;br /&gt;
&lt;br /&gt;
TBD: After the event :-)&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Code Sprint]]&lt;br /&gt;
[[Category: 2023]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_Community_Meeting_Prague_2023&amp;diff=26855</id>
		<title>GRASS Community Meeting Prague 2023</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_Community_Meeting_Prague_2023&amp;diff=26855"/>
		<updated>2023-04-04T02:22:34Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: /* Via chat or hangout */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{toc|right}}&lt;br /&gt;
The GRASS GIS team is organizing the ''GRASS GIS Community Meeting with contributors, power users and developers'' from '''June 2 to June 6, 2023''' to celebrate GRASS GIS '''40th birthday'''. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery mode=&amp;quot;slideshow&amp;quot;&amp;gt;&lt;br /&gt;
Image:grass-sprint-prague.jpg|Prague 2013&lt;br /&gt;
Image:Grass_sprint2018_bonn_fotowall.jpg|Bonn 2018&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
GRASS GIS Community Meeting is a great occasion for folks to support the development by actively contributing to the source code, documentation (manuals, wiki, tutorials), translations, website or likewise. The '''community''' meeting is also a get-together where supporters, contributors, power users and developers make decisions and tackle larger problems related to the project, discuss and collaboratively resolve bugs, plan the direction for the project and work on new features. We welcome people committed to improving the GRASS GIS project and the interfaces to QGIS, GDAL, PostGIS, R statistics, OGC Services and willing to '''celebrate with us the 40th GRASS GIS birthday!!'''&lt;br /&gt;
&lt;br /&gt;
For the detailed agenda, see below.&lt;br /&gt;
&lt;br /&gt;
== Sponsors ==&lt;br /&gt;
&lt;br /&gt;
We welcome '''financial contributions''' to support the meeting and we are looking for sponsors to cover costs such as meals or to help reducing travelling and accommodation expenses for GRASS developers with far arrival. If you are interested in sponsoring the GRASS Community Meeting, please read about&lt;br /&gt;
&lt;br /&gt;
:::'''sponsoring the GRASS GIS project''' at '''[https://grass.osgeo.org/contribute/sponsoring/ https://grass.osgeo.org/contribute/sponsoring/]'''&lt;br /&gt;
&lt;br /&gt;
Note that it is also possible to &amp;lt;b&amp;gt;buy a round of beers for the developers with a quick click&amp;lt;/b&amp;gt; using the Open Collective &amp;quot;Contribute Money&amp;quot; button https://opencollective.com/osgeo/projects/grass&lt;br /&gt;
&lt;br /&gt;
Any surplus at the end of the event will be turned over to the GRASS GIS project.&lt;br /&gt;
&lt;br /&gt;
This GRASS Community Meeting is a great occasion for you to support the development of GRASS. With your contribution you'll enable more developers to meet. Community meetings are important opportunities for developers to discuss, fix bugs, plan the direction for the project and work on new features. Please see below for the detailed agenda. The developers and contributors are donating their valuable time, so it would be great if in-kind funding can be made available from within the community to cover out-of-pocket expenses. All of the work that takes place at the community meeting will be directly contributed back into the GRASS project to the benefit of everyone who uses it.&lt;br /&gt;
&lt;br /&gt;
=== Thanks to our sponsors ===&lt;br /&gt;
&lt;br /&gt;
We are grateful for the support which we have received to organize this GRASS Community Meeting:&lt;br /&gt;
&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
== Timing  ==&lt;br /&gt;
&lt;br /&gt;
'''When''': June 2-6, 2023&lt;br /&gt;
&lt;br /&gt;
Of course you are invited to join or leave the meeting whenever you want.&lt;br /&gt;
&lt;br /&gt;
== Venue ==&lt;br /&gt;
&lt;br /&gt;
[[Image:logo_cvut.jpg|130px|left]]&lt;br /&gt;
Department of Geomatics&amp;lt;br&amp;gt;&lt;br /&gt;
[https://www.fsv.cvut.cz/?lang=en Faculty of Civil Engineering]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://www.cvut.cz/en Czech Technical University in Prague], {{wikipedia|Czech Republic}}&amp;lt;br&amp;gt;&lt;br /&gt;
Thákurova 7/2077, Prague&amp;lt;br&amp;gt;&lt;br /&gt;
Room B868&amp;lt;br&amp;gt;&lt;br /&gt;
[https://en.mapy.cz/s/debazefuse Map]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Prague has an international [http://www.prg.aero/en/ airport] and is also reachable by train, bus or car.&lt;br /&gt;
&lt;br /&gt;
== Accommodation and Costs ==&lt;br /&gt;
&lt;br /&gt;
Participants should plan for the following costs:&lt;br /&gt;
&lt;br /&gt;
* The participation is free of charge&lt;br /&gt;
* Travel to Prague, variable depending on where you come from&lt;br /&gt;
* Accommodation and meals (with the donated sponsorship money we will try to cover some expenses of the participants)&lt;br /&gt;
'''Please note''': The currency in Czech Republic is {{wikipedia|Czech crown}} (CZK, koruna, Kč). 100 Czech crowns are about 4 Euros (see [https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/ current rates]).&lt;br /&gt;
&lt;br /&gt;
Please let us know your time of arrival and departure, so we can book accommodations and organize the logistics.&lt;br /&gt;
&lt;br /&gt;
Financial support: (partial) travel grants can be payed upon request thanks to our sponsors!&lt;br /&gt;
&lt;br /&gt;
== Agenda - What we plan to do ==&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The program is generally open for your ideas. Please write an email to the [http://lists.osgeo.org/mailman/listinfo/grass-dev GRASS developer list] to discuss your contribution.&lt;br /&gt;
&lt;br /&gt;
During the meeting we will work on GRASS GIS on these tasks (please add more!):&lt;br /&gt;
&lt;br /&gt;
* We will update and revise the [https://github.com/qgis/QGIS/tree/master/python/plugins/grassprovider GRASS GIS Integration with QGIS] to simplify maintenance.&lt;br /&gt;
* Furthermore, we will migrate the compilation technology to CMake to significantly improve the Windows builds including PDAL support and become binary compatible with OSGeo4W.&lt;br /&gt;
* The extensive GRASS documentation will be converted from HTML to Markdown to facilitate future collaboration.&lt;br /&gt;
* Pictures, examples and workflows will be added to the documentation where they are still missing.&lt;br /&gt;
* Software maintenance processes are automated and documented to reduce the burden on maintainers and thus improve the sustainability of the project.&lt;br /&gt;
&lt;br /&gt;
This means that there are tasks from both the programming and documentation areas to appeal to a wide range of interested parties.&lt;br /&gt;
&lt;br /&gt;
Further details about the action items you '''find [[Talk:GRASS Community Meeting Prague 2023|here]]''' and below. Topics cover non-technical, semi-technical, and technical issues.&lt;br /&gt;
&lt;br /&gt;
=== Timeline ===&lt;br /&gt;
&lt;br /&gt;
Will be specified later.&lt;br /&gt;
&lt;br /&gt;
==== Friday, 2 June ====&lt;br /&gt;
&lt;br /&gt;
==== Saturday, 3 June ====&lt;br /&gt;
&lt;br /&gt;
==== Sunday, 4 June ====&lt;br /&gt;
&lt;br /&gt;
==== Monday, 5 June ====&lt;br /&gt;
&lt;br /&gt;
==== Tuesday, 6 June ====&lt;br /&gt;
&lt;br /&gt;
== Participation ==&lt;br /&gt;
&lt;br /&gt;
We are planning for an attendance of 20 people (i.e., coding places) but of course you are welcome to join us and bring new ideas with you: we'll make more places available. Please add your name here or contact [[User:Landa|Martin Landa]] &amp;lt;tt&amp;gt;&amp;lt;landa.martin at gmail.com&amp;gt;&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
=== In person ===&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable sortable&amp;quot;   border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;4&amp;quot; rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:1em 1em 1em 0; border:solid 1px #AAAAAA; border-collapse:collapse; background-color:#edf9c7; font-size:95%; empty-cells:show;&amp;quot; &lt;br /&gt;
!width=50px|'''Number'''&lt;br /&gt;
!width=130px|'''Participant '''&lt;br /&gt;
!width=100px|'''Country'''&lt;br /&gt;
!width=100px|'''Arrival'''&lt;br /&gt;
!width=100px|'''Departure'''&lt;br /&gt;
!'''Topics'''&lt;br /&gt;
!width=75px|'''T-Shirt'''&lt;br /&gt;
!'''Notes'''&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|[[User:Landa|Martin Landa]]&lt;br /&gt;
| Czech Republic&lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| &lt;br /&gt;
| XL&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
| Micha Silver&lt;br /&gt;
| Israel&lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| Addon to derive soil moisture from Sentinel 2&lt;br /&gt;
| XXL&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|[https://www.osgeo.org/member/kudrnovsky/ Helmut Kudrnovsky]&lt;br /&gt;
| Austria&lt;br /&gt;
| June 2&lt;br /&gt;
| June 4&lt;br /&gt;
| &lt;br /&gt;
| L&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|[[User:Neteler|Markus Neteler]]&lt;br /&gt;
| Germany&lt;br /&gt;
| June 2&lt;br /&gt;
| June 6 (12:43)&lt;br /&gt;
| see [[Talk:GRASS_Community_Meeting_Prague_2023#Markus_Neteler|my list in &amp;quot;Discussion&amp;quot; page]]&lt;br /&gt;
| L&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|[[User:pesekon2|Ondřej Pešek]]&lt;br /&gt;
| Czech Republic&lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| &lt;br /&gt;
| M&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
| [[User:helena|Helena Mitasova]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
|&lt;br /&gt;
| S&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
| [[User:wenzeslaus|Vaclav Petras]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| Support CMake transition, revise connection with QGIS and other tools&lt;br /&gt;
| M&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
| [[User:Annakrat|Anna Petrasova]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
| parallelization, grass.jupyter&lt;br /&gt;
| S&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
| [[User:Ctwhite|Corey White]]&lt;br /&gt;
| United States &lt;br /&gt;
| June 2&lt;br /&gt;
| June 6&lt;br /&gt;
|&lt;br /&gt;
| XL&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Via chat or hangout ===&lt;br /&gt;
&lt;br /&gt;
Join our [https://app.gitter.im/#/room/#grassgis_community:gitter.im Gitter chatroom]&lt;br /&gt;
&lt;br /&gt;
TBD: Google Meet / Zoom / ???&lt;br /&gt;
&lt;br /&gt;
Participating virtually:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable sortable&amp;quot;   border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;4&amp;quot; rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:1em 1em 1em 0; border:solid 1px #AAAAAA; border-collapse:collapse; background-color:#edf9c7; font-size:95%; empty-cells:show;&amp;quot; &lt;br /&gt;
!width=50px|'''Number'''&lt;br /&gt;
!width=130px|'''Participant '''&lt;br /&gt;
!width=100px|'''Country'''&lt;br /&gt;
!'''Topics'''&lt;br /&gt;
!'''Notes'''&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|[[User:Baharmon|Brendan Harmon]]&lt;br /&gt;
| United States&lt;br /&gt;
| Integration with QGIS&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Timing of hangout meetings ====&lt;br /&gt;
&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
=== Collaborative document scratching ===&lt;br /&gt;
&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
== Individual Preparation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Bring your own computer&lt;br /&gt;
* Bring {{wikipedia|AC adapter|power connector adapter}} if needed (Czech Republic: 230V, 50Hz, {{wikipedia|File:Euro-Flachstecker_2.jpg|Type C Europlugs}} are common and also {{wikipedia|File:French_plug_and_socket.jpg|Type E}})&lt;br /&gt;
* Install subversion and the compiler tools, and come with a working GRASS development environment if possible.&lt;br /&gt;
&lt;br /&gt;
== Broadcast &amp;amp; Video ==&lt;br /&gt;
&lt;br /&gt;
During the event :)&lt;br /&gt;
&lt;br /&gt;
== Photos ==&lt;br /&gt;
&lt;br /&gt;
Also during the event :)&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
&lt;br /&gt;
* '''How was it last time?'''&lt;br /&gt;
** Very nice, see [[GRASS_GIS at OSGeo Virtual Community Sprint 2020]]!&lt;br /&gt;
* ''Is the GRASS Community Meeting just a coding event?''&lt;br /&gt;
** It is mainly a coding and documentation event. It is a working session for people who are already participants in the GRASS project and/or are committed to improving the GRASS project.&lt;br /&gt;
** On demand we can do some presentations of current working GRASS implementation and new upcoming features to spread the idea of Open Source GIS software.&lt;br /&gt;
* ''Is the GRASS Community Meeting for developers only?''&lt;br /&gt;
** No: anybody can help, with testing, checking out bugs and fixes, documentation and more.&lt;br /&gt;
* ''Where can I get help and more information about the community meeting?''&lt;br /&gt;
** Contact [[User:Landa|Martin Landa]] &amp;lt;tt&amp;gt;&amp;lt;landa.martin at gmail.com&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Press Release ==&lt;br /&gt;
&lt;br /&gt;
TBD: After the event :-)&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Code Sprint]]&lt;br /&gt;
[[Category: 2023]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_Python_Scripting_Library&amp;diff=26756</id>
		<title>GRASS Python Scripting Library</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_Python_Scripting_Library&amp;diff=26756"/>
		<updated>2022-11-23T20:40:02Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: /* Interfacing with NumPy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Python}}&lt;br /&gt;
Python API documentation:&lt;br /&gt;
&lt;br /&gt;
* [https://grass.osgeo.org/grass78/manuals/libpython/ Python API for GRASS GIS 7] and [http://grass.osgeo.org/grass78/manuals/libpython/script_intro.html Python Scripting Library]&lt;br /&gt;
* (old: [https://grass.osgeo.org/programming6/pythonlib.html for GRASS GIS 6]: core.py, db.py, raster.py, vector.py, setup.py, array.py task.py)&lt;br /&gt;
&lt;br /&gt;
The GRASS Python Scripting Library can be imported by statement&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The other packages such as PyGRASS can be imported in a similar way.&lt;br /&gt;
&lt;br /&gt;
The code in {{src|lib/python/|lib/python}} provides &amp;lt;tt&amp;gt;grass.script&amp;lt;/tt&amp;gt; and other packages in order to support GRASS scripts written in Python. The {{src|scripts}} directory of GRASS GIS 7 contains a series of examples actually provided to the end users (while the script in GRASS GIS 6 are shell scripts).&lt;br /&gt;
&lt;br /&gt;
For more general info, see also [[GRASS and Python]] and see also [[Converting Bash scripts to Python]] if you have some Bash scripts you want to rewrite to Python.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Calling a GRASS module in Python ===&lt;br /&gt;
&lt;br /&gt;
Imagine, you wanted to execute this command in Python:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  r.profile -g input=mymap output=newfile profile=12244.256,-295112.597,12128.012,-295293.77&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All arguments except the first (which is a flag) are keyword arguments, i.e. &amp;lt;tt&amp;gt;arg = val&amp;lt;/tt&amp;gt;. For the flag, use &amp;lt;tt&amp;gt;flags = 'g'&amp;lt;/tt&amp;gt; (note that &amp;quot;-g&amp;quot; would be the negative of a Python variable named &amp;quot;g&amp;quot;!). So:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('r.profile',&lt;br /&gt;
               input = input_map,&lt;br /&gt;
               output = output_file,&lt;br /&gt;
               profile = [12244.256,-295112.597,12128.012,-295293.77]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
or:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
               profile = [(12244.256,-295112.597),(12128.012,-295293.77)]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i.e. you need to provide the keyword, and the argument must be a valid Python expression. Function &amp;lt;code&amp;gt;run_command()&amp;lt;/code&amp;gt; etc accept lists and tuples.&lt;br /&gt;
&lt;br /&gt;
'''What is the proper way to include keyword-arguments tuples?'''&lt;br /&gt;
&lt;br /&gt;
For example, &amp;quot;g.list -f type=rast,vect&amp;quot; translates into:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;g.list&amp;quot;, flags=&amp;quot;f&amp;quot;, type=&amp;quot;rast,vect&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
or:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;g.list&amp;quot;, flags=&amp;quot;f&amp;quot;, type=[&amp;quot;rast&amp;quot;,&amp;quot;vect&amp;quot;])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The various *_command() functions accept arbitrary keyword arguments. Any keywords which don't have a specific meaning to either the *_command() function or the Popen constructor are treated as arguments to the GRASS module.&lt;br /&gt;
&lt;br /&gt;
'''What is the proper way to use multiple flags?'''&lt;br /&gt;
&lt;br /&gt;
How can I call a module with multiple flags set (e.g., -a and -b) in GRASS-Python?&lt;br /&gt;
&lt;br /&gt;
  flags = &amp;quot;ab&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;r.info&amp;quot;, flags=&amp;quot;eg&amp;quot;, map=[&amp;quot;elevation&amp;quot;])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Differences between ''run_command()'' and ''read_command()'':'''&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|run_command}} executes the command and waits for it to terminate; it doesn't redirect any of the standard streams.&lt;br /&gt;
* {{pyapi|script|script.core|read_command}} executes the command with stdout redirected to a pipe, and reads everything written to it. Once the command terminates, it returns the data written to stdout as a string.&lt;br /&gt;
&lt;br /&gt;
'''How to retrieve error messages from ''read_command()'':'''&lt;br /&gt;
&lt;br /&gt;
None of the existing *_command functions redirect stderr. You can do so with e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
def read2_command(*args, **kwargs):&lt;br /&gt;
   kwargs['stdout'] = grass.PIPE&lt;br /&gt;
   kwargs['stderr'] = grass.PIPE&lt;br /&gt;
   ps = grass.start_command(*args, **kwargs)&lt;br /&gt;
   return ps.communicate()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This behaves like &amp;lt;tt&amp;gt;read_command()&amp;lt;/tt&amp;gt; except that it returns a tuple of (stdout, stderr) rather than just stdout.&lt;br /&gt;
&lt;br /&gt;
== Uses for read, feed and pipe, start and exec commands ==&lt;br /&gt;
&lt;br /&gt;
All of the &amp;lt;tt&amp;gt;*_command&amp;lt;/tt&amp;gt; functions use {{pyapi|script|script.core|make_command}} to construct a command&lt;br /&gt;
line for a program which uses the {{cmd|g.parser|desc=GRASS parser}}. Most of them then pass&lt;br /&gt;
that command line to &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; via {{pyapi|script|script.core|start_command}}, except&lt;br /&gt;
for {{pyapi|script|script.core|exec_command}} which uses &amp;lt;tt&amp;gt;os.execvpe()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[To be precise, they use &amp;lt;tt&amp;gt;grass.Popen()&amp;lt;/tt&amp;gt;, which just calls&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; with 'shell=True' on Windows and 'shell=False'&lt;br /&gt;
otherwise. On Windows, you need to use 'shell=True' to be able to&lt;br /&gt;
execute scripts (including batch files); 'shell=False' only works with&lt;br /&gt;
binary executables.]&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.core|start_command}} separates the arguments into those which&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; understands and the rest. The rest are passed to&lt;br /&gt;
&amp;lt;tt&amp;gt;make_command()&amp;lt;/tt&amp;gt; to construct a command line which is passed as the&lt;br /&gt;
&amp;quot;args&amp;quot; parameter to &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, {{pyapi|script|script.core|start_command}} is a GRASS-oriented interface to&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt;. It should be suitable for any situation where you&lt;br /&gt;
would use &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; to execute a normal GRASS command (one&lt;br /&gt;
which uses the GRASS parser, which is almost all of them; the main&lt;br /&gt;
exception is {{cmd|r.mapcalc}} in 6.x).&lt;br /&gt;
&lt;br /&gt;
Most of the others are convenience wrappers around &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt;, for common use cases.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|run_command}} calls the wait() method on the process, so it doesn't return until the command has finished, and returns the command's exit code. Similar to &amp;lt;tt&amp;gt;system()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|pipe_command}} calls &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; with 'stdout=PIPE' and returns the process object. You can use the process' .stdout member to read the command's stdout. Similar to popen(..., &amp;quot;r&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|feed_command}} calls &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; with stdin=PIPE and returns the process object. You can use the process' .stdin member to write to the command's stdout. Similar to popen(..., &amp;quot;w&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|read_command}} calls &amp;lt;tt&amp;gt;pipe_command()&amp;lt;/tt&amp;gt;, reads the data from the command's stdout, and returns it as a string. Similar to `backticks` in the shell.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|write_command}} calls &amp;lt;tt&amp;gt;feed_command()&amp;lt;/tt&amp;gt;, sends the string specified by the &amp;quot;stdin&amp;quot; argument to the command's stdin, waits for the command to finish and returns its exit code. Similar to &amp;quot;echo ... | command&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|parse_command}} calls &amp;lt;tt&amp;gt;read_command()&amp;lt;/tt&amp;gt; and parses its output as key-value pairs. Useful for obtaining information from {{cmd|g.region}}, {{cmd|g.proj}}, {{cmd|r.info}}, etc.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|exec_command}} doesn't use &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; but &amp;lt;tt&amp;gt;os.execvpe()&amp;lt;/tt&amp;gt;. This causes the specified command to replace the current program (i.e. the Python script), so &amp;lt;tt&amp;gt;exec_command()&amp;lt;/tt&amp;gt; never returns. Similar to bash's &amp;quot;exec&amp;quot; command. This can be useful if the script is a &amp;quot;wrapper&amp;quot; around a single command, where you construct the command line and execute the command as the final step. Notes: exec_command() is rarely appropriate. You probably want run_command() instead. On Windows, exec_command() will probably require the &amp;quot;.exe&amp;quot; suffix.&lt;br /&gt;
&lt;br /&gt;
If you have any other questions, you might want to look at the code ({{src|lib/python/script/core.py}}). Most of these functions are only a few lines long.&lt;br /&gt;
&lt;br /&gt;
=== Hints for parse_command() ===&lt;br /&gt;
&lt;br /&gt;
To turn this command&lt;br /&gt;
        g.rename raster=old_name,new_name&lt;br /&gt;
into a g.parse_command() call, you need to consider that it is a function call with three arguments:&lt;br /&gt;
# &amp;quot;g.rename&amp;quot;&lt;br /&gt;
# raster=old_name&lt;br /&gt;
# new_name&lt;br /&gt;
&lt;br /&gt;
The second argument is a keyword argument, the first and third are&lt;br /&gt;
positional (non-keyword) arguments. Python doesn't allow positional&lt;br /&gt;
arguments to follow keyword arguments; positional arguments come&lt;br /&gt;
first, keyword arguments last.&lt;br /&gt;
&lt;br /&gt;
Given the context, it's safe to assume that you want to pass a pair of&lt;br /&gt;
map names as the value to the rast= option. This requires explicit&lt;br /&gt;
parentheses so that the comma is treated as forming a tuple rather&lt;br /&gt;
than as an argument separator:&lt;br /&gt;
&lt;br /&gt;
        g.parse_command(&amp;quot;g.rename&amp;quot;, raster=(old_name,new_name))&lt;br /&gt;
&lt;br /&gt;
The parentheses in a tuple value can only be omitted if it doesn't&lt;br /&gt;
result in the comma being ambiguous (as is the case in a function&lt;br /&gt;
call).&lt;br /&gt;
&lt;br /&gt;
== Interfacing ==&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy ===&lt;br /&gt;
&lt;br /&gt;
The {{pyapi|script|script.array|array}} module defines a &amp;lt;code&amp;gt;class array&amp;lt;/code&amp;gt; which is a subclass of [http://docs.scipy.org/doc/numpy/reference/generated/numpy.memmap.html numpy.memmap] that reads/writes the underlying file via {{cmd|r.out.bin}}/{{cmd|r.in.bin}}. Metadata can be read with {{pyapi|script|script.raster|raster_info}}:&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
import grass.script.array as garray&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    map = &amp;quot;elevation&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # read map&lt;br /&gt;
    a = garray.array(map)&lt;br /&gt;
&lt;br /&gt;
    # get raster map info&lt;br /&gt;
    print(grass.raster_info(map)['datatype'])&lt;br /&gt;
    i = grass.raster_info(map)&lt;br /&gt;
    &lt;br /&gt;
    # get computational region info&lt;br /&gt;
    c = grass.region()&lt;br /&gt;
    print(&amp;quot;rows: %d&amp;quot; % c['rows'])&lt;br /&gt;
    print(&amp;quot;cols: %d&amp;quot; % c['cols'])&lt;br /&gt;
&lt;br /&gt;
    # new array for result&lt;br /&gt;
    b = garray.array()&lt;br /&gt;
    # calculate new map from input map and store as GRASS raster map&lt;br /&gt;
    b[...] = (a / 50).astype(int) * 50&lt;br /&gt;
    b.write(&amp;quot;elev.50m&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The size of the array is taken from the current region ([[computational region]]).&lt;br /&gt;
&lt;br /&gt;
The main drawback of using numpy is that you're limited by available&lt;br /&gt;
memory. Using a subclass of &amp;lt;code&amp;gt;numpy.memmap&amp;lt;/code&amp;gt; lets you use files which may&lt;br /&gt;
be much larger, but processing the entire array in one go is likely to&lt;br /&gt;
produce in-memory results of a similar size.&lt;br /&gt;
&lt;br /&gt;
'''NULL (no data) management:'''&lt;br /&gt;
&lt;br /&gt;
For integer maps, the NULL value is -2^31 = -2147483648. For floating-point maps, the NULL value is NaN. Note that the null= parameter for read() and write() specifies the value in the numpy array which is mapped to/from null values in the GRASS raster map.&lt;br /&gt;
&lt;br /&gt;
If you're using floating-point numpy arrays, then use (Note: This assumes that atof() and sscanf(&amp;quot;%lf&amp;quot;) recognise &amp;quot;nan&amp;quot;; this is the case on Linux, but doesn't appear to work on Windows)&lt;br /&gt;
 null=numpy.nan&lt;br /&gt;
&lt;br /&gt;
For integer arrays, using&lt;br /&gt;
 null=-2147483648&lt;br /&gt;
will ensure that valid values don't collide with NYLLs.&lt;br /&gt;
&lt;br /&gt;
'''MASK support:'''&lt;br /&gt;
&lt;br /&gt;
Reading and writing use r.out.bin and r.in.bin respectively. r.out.bin respects the MASK.&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy and SciPy  ===&lt;br /&gt;
&lt;br /&gt;
[http://docs.scipy.org/doc/scipy/reference/index.html SciPy] offers simple access to complex calculations. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from scipy import stats&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
import grass.script.array as garray&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    map = &amp;quot;elevation&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    x = garray.array(map)&lt;br /&gt;
&lt;br /&gt;
    # Descriptive Statistics:&lt;br /&gt;
    print(&amp;quot;max, min, mean, var:&amp;quot;)&lt;br /&gt;
    print(x.max(), x.min(), x.mean(), x.var())&lt;br /&gt;
    print(&amp;quot;Skewness test: z-score and 2-sided p-value:&amp;quot;)&lt;br /&gt;
    print(stats.skewtest(stats.skew(x)))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy, SciPy and Matlab ===&lt;br /&gt;
&lt;br /&gt;
One may also use the SciPy - Matlab interface:&lt;br /&gt;
    &lt;br /&gt;
    r.out.mat input=elevation output=elev.mat&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    ### PY ###&lt;br /&gt;
    import scipy.io as sio&lt;br /&gt;
    # load data&lt;br /&gt;
    elev = sio.loadmat('elev.mat')&lt;br /&gt;
    # retrive the actual array. the data set contains also the spatial reference&lt;br /&gt;
    elev.get('map_data')&lt;br /&gt;
    data = elev.get('map_data')&lt;br /&gt;
    # a first simple plot&lt;br /&gt;
    import pylab&lt;br /&gt;
    pylab.plot(data)&lt;br /&gt;
    pylab.show()&lt;br /&gt;
    # the contour plot&lt;br /&gt;
    pylab.contour(data)&lt;br /&gt;
    # obviously data needs to ne reversed&lt;br /&gt;
    import numpy as np&lt;br /&gt;
    data_rev = data[::-1]&lt;br /&gt;
    pylab.contour(data_rev)&lt;br /&gt;
    # =&amp;gt; this is a quick plot. basemap mapping may provide a nicer map!&lt;br /&gt;
    #######&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Usage Examples ==&lt;br /&gt;
&lt;br /&gt;
=== Display example ===&lt;br /&gt;
Example of Python script, which is processed by {{cmd|g.parser}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
#&lt;br /&gt;
############################################################################&lt;br /&gt;
#&lt;br /&gt;
# MODULE:      d.shadedmap&lt;br /&gt;
# AUTHOR(S):   Unknown; updated to GRASS 5.7 by Michael Barton&lt;br /&gt;
#              Converted to Python by Glynn Clements&lt;br /&gt;
# PURPOSE:     Uses d.his to drape a color raster over a shaded relief map&lt;br /&gt;
# COPYRIGHT:   (C) 2004,2008,2009 by the GRASS Development Team&lt;br /&gt;
#&lt;br /&gt;
#              This program is free software under the GNU General Public&lt;br /&gt;
#              License (&amp;gt;=v2). Read the file COPYING that comes with GRASS&lt;br /&gt;
#              for details.&lt;br /&gt;
#&lt;br /&gt;
#############################################################################&lt;br /&gt;
&lt;br /&gt;
#%Module&lt;br /&gt;
#% description: Drapes a color raster over a shaded relief map using d.his&lt;br /&gt;
#% keyword: display&lt;br /&gt;
#% keyword: raster&lt;br /&gt;
#%End&lt;br /&gt;
#%option&lt;br /&gt;
#% key: reliefmap&lt;br /&gt;
#% type: string&lt;br /&gt;
#% gisprompt: old,cell,raster&lt;br /&gt;
#% description: Name of shaded relief or aspect map&lt;br /&gt;
#% required : yes&lt;br /&gt;
#%end&lt;br /&gt;
#%option&lt;br /&gt;
#% key: drapemap&lt;br /&gt;
#% type: string&lt;br /&gt;
#% gisprompt: old,cell,raster&lt;br /&gt;
#% description: Name of raster to drape over relief map&lt;br /&gt;
#% required : yes&lt;br /&gt;
#%end&lt;br /&gt;
#%option&lt;br /&gt;
#% key: brighten&lt;br /&gt;
#% type: integer&lt;br /&gt;
#% description: Percent to brighten&lt;br /&gt;
#% options: -99-99&lt;br /&gt;
#% answer: 0&lt;br /&gt;
#%end&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    drape_map = options['drapemap']&lt;br /&gt;
    relief_map = options['reliefmap']&lt;br /&gt;
    brighten = options['brighten']&lt;br /&gt;
    ret = grass.run_command(&amp;quot;d.his&amp;quot;, h_map = drape_map,  i_map = relief_map, brighten = brighten)&lt;br /&gt;
    sys.exit(ret)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    options, flags = grass.parser()&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parsing the options and flags  ===&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.core|parser}} is an interface to {{cmd|g.parser}}, and allows to parse the ''options'' and ''flags'' passed to your script on the command line. It is to be called at the top-level:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    options, flags = grass.parser()&lt;br /&gt;
    main()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Global variables &amp;quot;options&amp;quot; and &amp;quot;flags&amp;quot; are Python dictionaries containing the options/flags values, keyed by lower-case option/flag names. The values in &amp;quot;options&amp;quot; are strings, those in &amp;quot;flags&amp;quot; are Python booleans. All those variables have to be previously declared in the header of your script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; options, flags = grass.parser()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; options&lt;br /&gt;
{'input': 'my_map', 'output': 'map_out', 'option1': '21.472', 'option2': ''}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; flags&lt;br /&gt;
{'c': True, 'm': False}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Accessing the --quiet and --verbose flags:'''&lt;br /&gt;
&lt;br /&gt;
See {{pyapi|script|script.core|verbosity}} for the 5 verbosity levels:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
&lt;br /&gt;
# to hide non-error messages from subprocesses&lt;br /&gt;
if grass.verbosity() &amp;lt;= 2:&lt;br /&gt;
    outdev = open(os.devnull, 'w')&lt;br /&gt;
else:&lt;br /&gt;
    outdev = sys.stdout&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Passing several floats to a single option ===&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
python my.module.py input=input output=output myoption=0.1,0.2,0.5&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The values in the &amp;quot;options&amp;quot; dictionary returned from the parser()&lt;br /&gt;
function are always strings. You can parse the string with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        myoption = map(float, options['myoption'].split(','))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The option definition in the script should have:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        #% type: double&lt;br /&gt;
        #% multiple: yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This allows g.parser to validate the option syntax, so you can rely&lt;br /&gt;
upon the string being in the correct format. If the values have a&lt;br /&gt;
fixed range, you can use e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        #% options: 0.0-1.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to have the parser check that the values fall within the range.&lt;br /&gt;
&lt;br /&gt;
For more information on option definitions, see:&lt;br /&gt;
&lt;br /&gt;
https://grass.osgeo.org/programming7/gislib.html#Complete_Structure_Members_Table&lt;br /&gt;
&lt;br /&gt;
=== Example for embedding r.mapcalc (map algebra) ===&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.raster|mapcalc}} accepts a template string followed by keyword&lt;br /&gt;
arguments for the substitutions, e.g. (code snippets):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
grass.mapcalc(&amp;quot;${out} = ${rast1} + ${rast2}&amp;quot;,&lt;br /&gt;
              out = options['output'],&lt;br /&gt;
              rast1 = options['raster1'],&lt;br /&gt;
              rast2 = options['raster2'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Best practice'': first copy all of the options[] into separate variables at the beginning of main(), i.e.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def main():&lt;br /&gt;
    output = options['output']&lt;br /&gt;
    raster1 = options['raster1']&lt;br /&gt;
    raster2 = options['raster2']&lt;br /&gt;
 &lt;br /&gt;
    ...&lt;br /&gt;
 &lt;br /&gt;
    grass.mapcalc(&amp;quot;${out} = ${rast1} + ${rast2}&amp;quot;,&lt;br /&gt;
                  out = output,&lt;br /&gt;
                  rast1 = raster1,&lt;br /&gt;
                  rast2 = raster2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Performing multiple computations using &amp;lt;tt&amp;gt;grass.script.raster.mapcalc()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
expr = &amp;quot;;&amp;quot;.join([&lt;br /&gt;
        &amp;quot;$out.r = r#$first * $frac + (1.0 - $frac) * r#$second&amp;quot;,&lt;br /&gt;
        &amp;quot;$out.g = g#$first * $frac + (1.0 - $frac) * g#$second&amp;quot;,&lt;br /&gt;
        &amp;quot;$out.b = b#$first * $frac + (1.0 - $frac) * b#$second&amp;quot;])&lt;br /&gt;
grass.mapcalc(expr, out=out, first=first, second=second, frac=percent/100.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hint: multi-line strings can be separated by using a semicolon instead of a newline.&lt;br /&gt;
&lt;br /&gt;
=== Looping over file names stored in an ASCII file ===&lt;br /&gt;
&lt;br /&gt;
When looping over file names stored in an ASCII file and getting the error&lt;br /&gt;
&lt;br /&gt;
   WARNING: Illegal filename &amp;lt;map.f1jan.05216.something&lt;br /&gt;
          &amp;gt;. Character &amp;lt;&lt;br /&gt;
          &amp;gt; not allowed.&lt;br /&gt;
&lt;br /&gt;
then the line terminators may be the reason.&lt;br /&gt;
When you iterate over a file, the strings include the line terminators (e.g. '\n' or '\r\n'). Use e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    for line in gl:&lt;br /&gt;
        renamed = line.rstrip().replace('.','_')&lt;br /&gt;
        ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to remove any trailing whitespace (including newlines) from each line.&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing raster category labels ===&lt;br /&gt;
&lt;br /&gt;
How to obtain the text labels&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    # dump cats to file to avoid &amp;quot;too many argument&amp;quot; problem:&lt;br /&gt;
    p = grass.pipe_command('r.category', map = rastertmp, separator = ';', quiet = True)&lt;br /&gt;
    cats = []&lt;br /&gt;
    for line in p.stdout:&lt;br /&gt;
        cats.append(line.rstrip('\r\n').split(';')[0])&lt;br /&gt;
    p.wait()&lt;br /&gt;
&lt;br /&gt;
    number = len(cats)&lt;br /&gt;
    if number &amp;lt; 1:&lt;br /&gt;
        grass.fatal(_(&amp;quot;No categories found in raster map&amp;quot;))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing category numbers ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' How to obtain the number of cells of a certain category?&lt;br /&gt;
&lt;br /&gt;
'''A:''' It is recommended to use {{pyapi|script|script.core|pipe_command}} and parse the output, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       p = grass.pipe_command('r.stats',flags='c',input='map')&lt;br /&gt;
       result = {}&lt;br /&gt;
       for line in p.stdout:&lt;br /&gt;
           val,count = line.strip().split()&lt;br /&gt;
           result[int(val)] = int(count)&lt;br /&gt;
       p.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing the region output of a module ===&lt;br /&gt;
&lt;br /&gt;
Some of the GRASS GIS modules are delivering region information (e.g. {{cmd|r.in.xyz}} which scans a LiDAR file for the extent of the point cloud). The retrieved region settings (using '''-g''' flag for script style output) can be parsed in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
from grass.script import core as gcore&lt;br /&gt;
&lt;br /&gt;
from grass.pygrass.modules.shortcuts import general as g&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
&lt;br /&gt;
# scan a LiDAR xyz point file for its extent&lt;br /&gt;
compregion = gcore.parse_command(&amp;quot;r.in.xyz&amp;quot;, input=&amp;quot;tmp.xyz&amp;quot;, separator=&amp;quot;space&amp;quot;, flags=&amp;quot;sg&amp;quot;, output=&amp;quot;bbox&amp;quot;,&lt;br /&gt;
                                  parse=(gcore.parse_key_val, {'sep': '=', 'vsep': ' '}))&lt;br /&gt;
print(compregion)&lt;br /&gt;
# set computational region from LiDAR extent&lt;br /&gt;
# hint: we turn here the dictionary to a region by unpacking the dictionary:&lt;br /&gt;
g.region(res=&amp;quot;1&amp;quot;, flags=&amp;quot;p&amp;quot;, **compregion)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the two '''*''' above which unpack the dictionary (see also the related [https://docs.python.org/2/tutorial/controlflow.html#keyword-arguments Python manual] page).&lt;br /&gt;
&lt;br /&gt;
=== Example for getting the region's number of rows and columns ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' How to obtain the number of rows and columns of the current region?&lt;br /&gt;
&lt;br /&gt;
'''A:''' It is recommended to use the {{pyapi|script|script.core|region}} function which will create a dictionary with values for extents and resolution, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
#-*- coding:utf-8 -*-&lt;br /&gt;
#&lt;br /&gt;
############################################################################&lt;br /&gt;
#&lt;br /&gt;
# MODULE:       g.region.resolution&lt;br /&gt;
# AUTHOR(S):    based on a post at GRASS-USER mailing list [1]               &lt;br /&gt;
# PURPOSE:	Parses &amp;quot;g.region -g&amp;quot;, prints out number of rows, cols&lt;br /&gt;
# COPYLEFT:     ;-)&lt;br /&gt;
# COMMENT:      ...a lot of comments to be easy-to-read for/by beginners&lt;br /&gt;
#&lt;br /&gt;
#############################################################################&lt;br /&gt;
#&lt;br /&gt;
#%Module&lt;br /&gt;
#% description: Print number of rows, cols of current geographic region&lt;br /&gt;
#% keyword: region&lt;br /&gt;
#%end&lt;br /&gt;
&lt;br /&gt;
# importing required modules&lt;br /&gt;
import sys # the sys module [2]&lt;br /&gt;
from grass.script import core as grass # the core module [3]&lt;br /&gt;
&lt;br /&gt;
# information about imported modules can be obtained using the dir() function&lt;br /&gt;
# e.g.: dir(sys)&lt;br /&gt;
&lt;br /&gt;
# define the &amp;quot;main&amp;quot; function: get number of rows, cols of region&lt;br /&gt;
def main():&lt;br /&gt;
    &lt;br /&gt;
    # #######################################################################&lt;br /&gt;
    # the following commented code works but is kept only for learning purposes&lt;br /&gt;
     &lt;br /&gt;
    ## assigning the output of the command &amp;quot;g.region -g&amp;quot; in a string called &amp;quot;return_rows_x_cols&amp;quot;&lt;br /&gt;
    # return_rows_x_cols = grass.read_command('g.region', flags = 'g')&lt;br /&gt;
    &lt;br /&gt;
    ## parsing arguments of interest (rows, cols) in a dictionary named &amp;quot;rows_x_cols&amp;quot;&lt;br /&gt;
    # rows_x_cols = grass.parse_key_val(return_rows_x_cols)&lt;br /&gt;
    &lt;br /&gt;
    ## selectively print rows, cols from the dictionary &amp;quot;rows_x_cols&amp;quot;&lt;br /&gt;
    # print 'rows=%d \ncols=%d' % (int(rows_x_cols['rows']), int(rows_x_cols['cols']))&lt;br /&gt;
    &lt;br /&gt;
    # #######################################################################&lt;br /&gt;
    &lt;br /&gt;
    # faster/ easier way: use of the &amp;quot;grass.region()&amp;quot; function&lt;br /&gt;
    gregion = grass.region()&lt;br /&gt;
    rows = gregion['rows']&lt;br /&gt;
    cols = gregion['cols']&lt;br /&gt;
    &lt;br /&gt;
    # print rows, cols properly formatted &lt;br /&gt;
    print 'rows=%d \ncols=%d' % (rows, cols)&lt;br /&gt;
&lt;br /&gt;
    # average resolution (in case of non-square pixels)&lt;br /&gt;
    avg_res=(gregion['nsres'] + gregion['ewres']) / 2.0&lt;br /&gt;
&lt;br /&gt;
# this &amp;quot;if&amp;quot; condition instructs execution of code contained in this script, *only* if the script is being executed directly &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;: # this allows the script to be used as a module in other scripts or as a standalone script&lt;br /&gt;
    options, flags = grass.parser() #&lt;br /&gt;
    sys.exit(main()) #&lt;br /&gt;
&lt;br /&gt;
# Links&lt;br /&gt;
# [1] http://n2.nabble.com/Getting-rows-cols-of-a-region-in-a-script-tp2787474p2787509.html&lt;br /&gt;
# [2] http://www.python.org/doc/2.5.2/lib/module-sys.html&lt;br /&gt;
# [3] https://grass.osgeo.org/grass78/manuals/libpython&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Managing mapsets ===&lt;br /&gt;
&lt;br /&gt;
To check if a certain mapset exists in the active location, use {{pyapi|script|script.core|mapsets}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.mapsets(False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
... returns a list of mapsets in the current location.&lt;br /&gt;
&lt;br /&gt;
=== r.mapcalc example ===&lt;br /&gt;
&lt;br /&gt;
Example of Python script, which is processed by {{cmd|g.parser}}:&lt;br /&gt;
&lt;br /&gt;
The shell script line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  r.mapcalc &amp;quot;MASK = if(($cloudResampName &amp;lt; 0.01000),1,null())&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would be written like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       ...&lt;br /&gt;
&lt;br /&gt;
       grass.mapcalc(&amp;quot;MASK=if(($cloudResampName &amp;lt; 0.01000),1,null())&amp;quot;,&lt;br /&gt;
                     cloudResampName = cloudResampName)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first argument to the mapcalc function is a template (see the Python library documentation for [http://docs.python.org/library/string.html string.Template]). Any keyword arguments (other than &amp;lt;tt&amp;gt;quiet&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;verbose&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;overwrite&amp;lt;/tt&amp;gt;) specify substitutions.&lt;br /&gt;
&lt;br /&gt;
=== r.mapcalc example: defining a moving window ===&lt;br /&gt;
&lt;br /&gt;
Moving window of 4 cell in every 8 direction and do a boolean comparison. Boolean value (e.g. the result of a comparison) is an integer, with 1 for true, 0 for false.&lt;br /&gt;
Then do a r.mapcalc calculation with the moving window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
           &lt;br /&gt;
       # define a moving window of 4 cell in every 8 direction&lt;br /&gt;
       #&lt;br /&gt;
       # map[4,4]                                    map[4,0]                                    map[4,-4]		&lt;br /&gt;
       # 	    map[3,3]                         map[3,0]                         map[3,-3]			&lt;br /&gt;
       # 		       map[2,2]              map[2,0]              map[2,-2]				&lt;br /&gt;
       #                                  map[1,1]   map[1,0]   map[1,-1]	 				&lt;br /&gt;
       # map[0,4]   map[0,3]   map[0,2]   map[0,1]       x      map[0,-1]  map[0,-2]  map[0,-3]  map[0,-4]&lt;br /&gt;
       #                                  map[-1,1]  map[-1,0]  map[-1,-1]					&lt;br /&gt;
       #                       map[-2,2]             map[-2,0]             map[-2,-2]				&lt;br /&gt;
       #            map[-3,3]                        map[-3,0]                        map[-3,-3]			&lt;br /&gt;
       # map[-4,4]                                   map[-4,0]                                   map[-4,-4]&lt;br /&gt;
       &lt;br /&gt;
       # define the offet duplets&lt;br /&gt;
       &lt;br /&gt;
       offsets = [d&lt;br /&gt;
           for j in xrange(1,4+1)&lt;br /&gt;
           for i in [j,-j]&lt;br /&gt;
           for d in [(i,0),(0,i),(i,i),(i,-i)]]&lt;br /&gt;
       	&lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;offsets&lt;br /&gt;
       # [(1, 0), (0, 1), (1, 1), (1, -1), (-1, 0), (0, -1), (-1, -1), (-1, 1), (2, 0), (0, 2), (2, 2), (2, -2), (-2, 0), (0, -2), \&lt;br /&gt;
       # (-2, -2), (-2, 2), (3, 0), (0, 3), (3, 3), (3, -3), (-3, 0), (0, -3), (-3, -3), (-3, 3), (4, 0), (0, 4), (4, 4), (4, -4), \&lt;br /&gt;
       # (-4, 0), (0, -4), (-4, -4), (-4, 4)]&lt;br /&gt;
       &lt;br /&gt;
       # define the calculation term&lt;br /&gt;
       &lt;br /&gt;
       terms = [&amp;quot;(myelevnc[%d,%d] &amp;lt; myelevnc)&amp;quot; % d&lt;br /&gt;
                for d in offsets]&lt;br /&gt;
       &lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;terms&lt;br /&gt;
       # ['(myelevnc[1,0] &amp;lt; myelevnc)', '(myelevnc[0,1] &amp;lt; myelevnc)', '(myelevnc[1,1] &amp;lt; myelevnc)', '(myelevnc[1,-1] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-1,0] &amp;lt; myelevnc)', '(myelevnc[0,-1] &amp;lt; myelevnc)', '(myelevnc[-1,-1] &amp;lt; myelevnc)', '(myelevnc[-1,1] &amp;lt; myelevnc)',\&lt;br /&gt;
       # '(myelevnc[2,0] &amp;lt; myelevnc)', '(myelevnc[0,2] &amp;lt; myelevnc)', '(myelevnc[2,2] &amp;lt; myelevnc)', '(myelevnc[2,-2] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-2,0] &amp;lt; myelevnc)', '(myelevnc[0,-2] &amp;lt; myelevnc)', '(myelevnc[-2,-2] &amp;lt; myelevnc)', '(myelevnc[-2,2] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[3,0] &amp;lt; myelevnc)', '(myelevnc[0,3] &amp;lt; myelevnc)', '(myelevnc[3,3] &amp;lt; myelevnc)', '(myelevnc[3,-3] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-3,0] &amp;lt; myelevnc)', '(myelevnc[0,-3] &amp;lt; myelevnc)', '(myelevnc[-3,-3] &amp;lt; myelevnc)', '(myelevnc[-3,3] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[4,0] &amp;lt; myelevnc)', '(myelevnc[0,4] &amp;lt; myelevnc)', '(myelevnc[4,4] &amp;lt; myelevnc)', '(myelevnc[4,-4] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-4,0] &amp;lt; myelevnc)', '(myelevnc[0,-4] &amp;lt; myelevnc)', '(myelevnc[-4,-4] &amp;lt; myelevnc)', '(myelevnc[-4,4] &amp;lt; myelevnc)']&lt;br /&gt;
       &lt;br /&gt;
       # define the calculation expression&lt;br /&gt;
       &lt;br /&gt;
       expr = &amp;quot;elevation_percentile4 = (100.0 / 48.0) * (%s)&amp;quot; % &amp;quot; + &amp;quot;.join(terms)&lt;br /&gt;
       &lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;expr&lt;br /&gt;
       #  elevation_percentile4 = (100.0 / 48.0) * ((myelevnc[1,0] &amp;lt; myelevnc) + (myelevnc[0,1] &amp;lt; myelevnc) + (myelevnc[1,1] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[1,-1] &amp;lt; myelevnc) + (myelevnc[-1,0] &amp;lt; myelevnc) + (myelevnc[0,-1] &amp;lt; myelevnc) + (myelevnc[-1,-1] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-1,1] &amp;lt; myelevnc) + (myelevnc[2,0] &amp;lt; myelevnc) + (myelevnc[0,2] &amp;lt; myelevnc) + (myelevnc[2,2] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[2,-2] &amp;lt; myelevnc) + (myelevnc[-2,0] &amp;lt; myelevnc) + (myelevnc[0,-2] &amp;lt; myelevnc) + (myelevnc[-2,-2] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-2,2] &amp;lt; myelevnc) + (myelevnc[3,0] &amp;lt; myelevnc) + (myelevnc[0,3] &amp;lt; myelevnc) + (myelevnc[3,3] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[3,-3] &amp;lt; myelevnc) + (myelevnc[-3,0] &amp;lt; myelevnc) + (myelevnc[0,-3] &amp;lt; myelevnc) + (myelevnc[-3,-3] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-3,3] &amp;lt; myelevnc) + (myelevnc[4,0] &amp;lt; myelevnc) + (myelevnc[0,4] &amp;lt; myelevnc) + (myelevnc[4,4] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[4,-4] &amp;lt; myelevnc) + (myelevnc[-4,0] &amp;lt; myelevnc) + (myelevnc[0,-4] &amp;lt; myelevnc) + (myelevnc[-4,-4] &amp;lt; myelevnc)\&lt;br /&gt;
       #  + (myelevnc[-4,4] &amp;lt; myelevnc))&lt;br /&gt;
       &lt;br /&gt;
       # do the r.mapcalc calculation with the moving window&lt;br /&gt;
       &lt;br /&gt;
       grass.mapcalc( expr )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using output from GRASS modules in the script ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you need to use the output of a module for the next step. There are dedicated functions to obtain the result of, for example, a statistical analysis.&lt;br /&gt;
&lt;br /&gt;
Example: get the range of a raster map and use it in {{cmd|r.mapcalc}}. Here you can use {{pyapi|script|script.raster|raster_info}}, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       max = grass.raster_info(inmap)['max']&lt;br /&gt;
       grass.mapcalc(&amp;quot;$outmap = $inmap / $max&amp;quot;,&lt;br /&gt;
                     inmap = inmap, outmap = outmap, max = max)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using output from r.what ===&lt;br /&gt;
&lt;br /&gt;
''Q: How does one return attribute values from a call to the 'r.what' module running in a python script?''&lt;br /&gt;
&lt;br /&gt;
A: If you use &amp;lt;tt&amp;gt;grass.script.raster_what()&amp;lt;/tt&amp;gt;, it returns a list of dictionaries.&lt;br /&gt;
&lt;br /&gt;
PyGRASS which requires you to add &amp;lt;tt&amp;gt;stdout_=PIPE&amp;lt;/tt&amp;gt;, then you can get the output as a string from &amp;lt;tt&amp;gt;module.outputs.stdout&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Or using directly the C API through python with (North Carolina dataset example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.vector import VectorTopo&lt;br /&gt;
from grass.pygrass.raster import RasterRow&lt;br /&gt;
from grass.pygrass.gis.region import Region&lt;br /&gt;
&lt;br /&gt;
with RasterRow('elevation', mode='r') as rast:&lt;br /&gt;
    with VectorTopo('hospitals', mode='r') as hospitals:&lt;br /&gt;
        region = Region()&lt;br /&gt;
        for hosp in hospitals:&lt;br /&gt;
            value = rast.get_value(hosp, region)&lt;br /&gt;
            if value is not None:&lt;br /&gt;
                print(hosp.cat, value)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoiding a syntax error for r.rescale ===&lt;br /&gt;
&lt;br /&gt;
''Q: How to avoid a syntax error for r.rescale related to &amp;quot;from=&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
A: &amp;quot;from&amp;quot; is a reserved word, use from_ instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
grass.run_command('r.rescale', input=mis1, output=mis1_8bit, from_='0,2048', to='0,255')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interface to copying maps (g.copy) ===&lt;br /&gt;
&lt;br /&gt;
Copy a raster map (for vector, replace &amp;quot;rast&amp;quot; with &amp;quot;vect&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('g.copy', rast = (input, output))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To generalize it, &amp;quot;datatype&amp;quot; is the form of grass data to copy (eg, rast, vect, etc)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('g.copy', **{datatype: (input, output)})&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interface to listing maps (g.list) ===&lt;br /&gt;
&lt;br /&gt;
You may use the functions in [https://grass.osgeo.org/grass-stable/manuals/libpython/script.html?highlight=list_grouped#script.core.list_grouped script.core.list_grouped()]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# list all&lt;br /&gt;
list_grouped('raster')['PERMANENT']&lt;br /&gt;
[..., 'lakes', ..., 'slope', ...&lt;br /&gt;
&lt;br /&gt;
# list with pattern&lt;br /&gt;
list_grouped('vect', pattern='*roads*')['PERMANENT']&lt;br /&gt;
['railroads', 'roadsmajor']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For temporal data, see likewise [https://grass.osgeo.org/grass-stable/manuals/libpython/temporal.html?highlight=list_grouped#temporal.gui_support.tlist_grouped temporal.gui_support.tlist_grouped()]&lt;br /&gt;
&lt;br /&gt;
See also [[Python/pygrass#Sample_PyGRASS_scripts|Sample PyGRASS scripts]] for an alternative solution.&lt;br /&gt;
&lt;br /&gt;
=== i.group with patterns as name for input ===&lt;br /&gt;
&lt;br /&gt;
Imagery groups can be populated like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.gis import Mapset&lt;br /&gt;
&lt;br /&gt;
run_command(&amp;quot;i.group&amp;quot;, group=&amp;quot;mygroup&amp;quot;, input=mset.glist(&amp;quot;raster&amp;quot;, pattern=&amp;quot;mypattern_*&amp;quot;))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Percentage output for progress of computation ===&lt;br /&gt;
&lt;br /&gt;
A) Within a Python script, the {{pyapi|script|script.core|percent}} module method wraps the &amp;lt;tt&amp;gt;g.message -p&amp;lt;/tt&amp;gt; command.&lt;br /&gt;
&lt;br /&gt;
B) If you call a GRASS command within the Python code, you have to parse the output by setting &amp;lt;tt&amp;gt;GRASS_MESSAGE_FORMAT=gui&amp;lt;/tt&amp;gt; in the environment when running the command and read from the command's stderr; e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       env = os.environ.copy()&lt;br /&gt;
       env['GRASS_MESSAGE_FORMAT'] = 'gui'&lt;br /&gt;
       p = grass.start_command(..., stderr = grass.PIPE, env = env)&lt;br /&gt;
       # read from p.stderr&lt;br /&gt;
       p.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need to capture both stdout and stderr, you need to use threads, select, or non-blocking I/O to consume data from both streams as it is generated in order to avoid deadlock.&lt;br /&gt;
&lt;br /&gt;
ALTERNATIVE:&lt;br /&gt;
&lt;br /&gt;
Redirect both stdout and stderr to the same pipe (and hope that the normal output doesn't include anything which will be mistaken for progress/error/etc messages):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       p = grass.start_command(..., stdout = grass.PIPE, stderr = grass.STDOUT, env = env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NULL data management ===&lt;br /&gt;
&lt;br /&gt;
How to analyse if there are only NULL cells in a map:&lt;br /&gt;
&lt;br /&gt;
If a map contains only null cells, its minimum and maximum will be &amp;quot;NULL&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
       $ r.mapcalc 'foo = null()'&lt;br /&gt;
       $ r.info -r foo&lt;br /&gt;
       min=NULL&lt;br /&gt;
       max=NULL&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using the Python API, The 'min' and 'max' values in the result of the {{pyapi|script|script.raster|raster_info}} function will be &amp;lt;tt&amp;gt;None&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Counting cells ===&lt;br /&gt;
&lt;br /&gt;
Counting cells is far more expensive than simply determining whether&lt;br /&gt;
there are any non-null cells. Counting cells requires reading the&lt;br /&gt;
entire map, while the {{cmd|r.info}} approach only needs to read the metadata&lt;br /&gt;
files.&lt;br /&gt;
&lt;br /&gt;
If you do need to count cells, {{cmd|r.stats}} is likely to be more efficient than {{cmd|r.univar}}.&lt;br /&gt;
&lt;br /&gt;
A count loop:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       while grass.raster_info(inmap)['max'] is not None:&lt;br /&gt;
           ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Display: overlayed map display with labels ===&lt;br /&gt;
&lt;br /&gt;
Example: display a vector map and overlay its labels on top of the map.&lt;br /&gt;
&lt;br /&gt;
If the environment contains the setting GRASS_PNG_READ=TRUE, d.* commands should overlay their output on an existing image (otherwise the first command creates the file map.png but the second command overwrites the file with only the labels). So the following should work:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('d.vect', map='my_shape')&lt;br /&gt;
       env = os.environ.copy()&lt;br /&gt;
       env['GRASS_PNG_READ'] = 'TRUE'&lt;br /&gt;
       grass.run_command('d.labels', labels='my_shape_labels', env = env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Path to GISDBASE ===&lt;br /&gt;
In order to a avoid hardcoded paths to GRASS mapset files like the SQLite DB file, you can get the GISDBASE variable from the environment:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       import os.path&lt;br /&gt;
&lt;br /&gt;
       env = grass.gisenv()&lt;br /&gt;
&lt;br /&gt;
       gisdbase = env['GISDBASE']&lt;br /&gt;
       location = env['LOCATION_NAME']&lt;br /&gt;
       mapset = env['MAPSET']&lt;br /&gt;
&lt;br /&gt;
       path = os.path.join(gisdbase, location, mapset, 'sqlite.db')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parse the GRASS GIS version or revision or path to library ===&lt;br /&gt;
&lt;br /&gt;
In order to a avoid hardcoded versions or to scan the SVN revision of the GRASS GIS version used, you can query the {{cmd|helptext|startup script}}:&lt;br /&gt;
&lt;br /&gt;
'''Variant 1 (pure Python solution) - svn_revision:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
cmd = subprocess.Popen('grass78 --config svn_revision', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
revision = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(revision)&lt;br /&gt;
# the result is for example: '72327'.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Variant 2 (GRASS GIS-Python solution) - svn_revision:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
cmd = grass.Popen('grass78 --config svn_revision', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
revision = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(revision)&lt;br /&gt;
# the result is for example: '72327'.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Path to GRASS GIS library (GRASS GIS-Python solution):'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
cmd = grass.Popen('grass78 --config path', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
version = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(version)&lt;br /&gt;
# the result is for example: '/usr/local/grass-7.6.svn'&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a new location ===&lt;br /&gt;
&lt;br /&gt;
Use {{pyapi|script|script.core|create_location}} to create a new location.&lt;br /&gt;
&lt;br /&gt;
=== Use Python reserved keyword ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' ''r.resamp.bspline'' uses 'lambda' as a command line parameter name, but when you try to use it with {{pyapi|script|script.core|run_command}} or {{pyapi|script|script.core|start_command}} you get an error as lambda is a python reserved keyword. How to work around that?&lt;br /&gt;
&lt;br /&gt;
'''A:''' Append an underscore to the name, i.e.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('r.resamp.bspline', lambda_ = ...)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this follows Python [http://legacy.python.org/dev/peps/pep-0008/#descriptive-naming-styles PEP8] style guide. In GRASS GIS version 6, you have to prepend the underscore.&lt;br /&gt;
&lt;br /&gt;
=== Controlling the PNG display driver ===&lt;br /&gt;
&lt;br /&gt;
Code fragment to control the {{cmd|pngdriver}} in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
def main():&lt;br /&gt;
       os.environ['GRASS_PNGFILE'] = filename&lt;br /&gt;
       os.environ['GRASS_WIDTH'] = str(width)&lt;br /&gt;
       os.environ['GRASS_HEIGHT'] = str(height)&lt;br /&gt;
       grass.run_command('d.his', i='elevation_shade', h='elevation')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sophisticated cleanup procedure ===&lt;br /&gt;
&lt;br /&gt;
Scripts which create several temporary files need a more sophisticated cleanup procedure which deletes all the tmp maps which have been created. This procedure should also work if the script stops (e.g due to an error).&lt;br /&gt;
&lt;br /&gt;
Solution: Define a list of map names which starts out empty and has names appended to it as the names are generated. Code fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import atexit, sys&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       tmp_rast = []&lt;br /&gt;
&lt;br /&gt;
       def cleanup():&lt;br /&gt;
           for rast in tmp_rast:&lt;br /&gt;
               grass.run_command(&amp;quot;g.remove&amp;quot;,&lt;br /&gt;
                                 flags = 'f',&lt;br /&gt;
                                 type = 'raster',&lt;br /&gt;
                                 name = rast,&lt;br /&gt;
                                 quiet = True)&lt;br /&gt;
&lt;br /&gt;
       def main():&lt;br /&gt;
           ...&lt;br /&gt;
           while ...:&lt;br /&gt;
               next_rast = ...&lt;br /&gt;
               tmp_rast.append(next_rast)&lt;br /&gt;
               ...&lt;br /&gt;
&lt;br /&gt;
       if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
           options, flags = grass.parser()&lt;br /&gt;
           atexit.register(cleanup)&lt;br /&gt;
           sys.exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using temporary region for computations ===&lt;br /&gt;
&lt;br /&gt;
There are two possible ways how to define temporary region for raster-based computations within your scripts. First method uses environmental variable WIND_OVERRIDE, the second GRASS_REGION, see {{cmd|variables|desc=GRASS variables}} for more info. The key point is to recover the current region when the script is finished or terminated.&lt;br /&gt;
&lt;br /&gt;
* ''First method'' (WIND_OVERRIDE) is implemented as {{pyapi|script|script.core|use_temp_region}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
# store the current region settings and installs an atexit&lt;br /&gt;
# handler to recover the current region on script termination&lt;br /&gt;
grass.use_temp_region()&lt;br /&gt;
&lt;br /&gt;
grass.run_command('g.region', region='detail')&lt;br /&gt;
&lt;br /&gt;
grass.mapcalc('map = 1', overwrite=True)&lt;br /&gt;
&lt;br /&gt;
# after making operations using the temporary region,&lt;br /&gt;
# to unset the temporary WIND_OVERRIDE file and remove any &lt;br /&gt;
# region named by it, it is possible to use del_temp_region&lt;br /&gt;
grass.del_temp_region()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* ''Second method'' (GRASS_REGION) doesn't store current region settings to any temporary region, it just defines GRASS_REGION which forces GIS Library to use this settings for raster-based computations instead of the settings stored in WIND file (ie. current region). See {{pyapi|script|script.core|region_env}}.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
# copy environment and define GRASS_REGION environmental variable&lt;br /&gt;
# same as `g.region region=detail`&lt;br /&gt;
env = os.environ.copy()&lt;br /&gt;
env['GRASS_REGION'] = grass.region_env(region='detail')&lt;br /&gt;
 &lt;br /&gt;
grass.mapcalc('map = 1', overwrite=True, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using predefined constants ===&lt;br /&gt;
&lt;br /&gt;
Some constants are wrapped from C to Python through ctypes.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
from grass.lib.gis import GRASS_EPSILON&lt;br /&gt;
GRASS_EPSILON&lt;br /&gt;
1e-15&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting a list of wrapped C functions and constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import pprint&lt;br /&gt;
import grass.lib.gis as grass_gis&lt;br /&gt;
&lt;br /&gt;
# simple list&lt;br /&gt;
dir(grass_gis)&lt;br /&gt;
&lt;br /&gt;
# pretty printing&lt;br /&gt;
pprint.pprint(dir(grass_gis))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direct Access from wxGUI ==&lt;br /&gt;
&lt;br /&gt;
[[wxGUI]] Layer Manager in GRASS GIS comes with &amp;quot;Python shell&amp;quot; which enables users to type and execute python commands directly in wxGUI environment.&lt;br /&gt;
&lt;br /&gt;
[[Image:wxgui-pyshell.png|center|400px|Embedded interactive Python Shell in wxGUI Layer Manager]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[GRASS GIS Jupyter notebooks]]&lt;br /&gt;
* [[Working with GRASS without starting it explicitly‎]]&lt;br /&gt;
* Many more tutorials under [[:Category:Python]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_Python_Scripting_Library&amp;diff=26755</id>
		<title>GRASS Python Scripting Library</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_Python_Scripting_Library&amp;diff=26755"/>
		<updated>2022-11-23T20:39:33Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: /* Interfacing with NumPy and SciPy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Python}}&lt;br /&gt;
Python API documentation:&lt;br /&gt;
&lt;br /&gt;
* [https://grass.osgeo.org/grass78/manuals/libpython/ Python API for GRASS GIS 7] and [http://grass.osgeo.org/grass78/manuals/libpython/script_intro.html Python Scripting Library]&lt;br /&gt;
* (old: [https://grass.osgeo.org/programming6/pythonlib.html for GRASS GIS 6]: core.py, db.py, raster.py, vector.py, setup.py, array.py task.py)&lt;br /&gt;
&lt;br /&gt;
The GRASS Python Scripting Library can be imported by statement&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The other packages such as PyGRASS can be imported in a similar way.&lt;br /&gt;
&lt;br /&gt;
The code in {{src|lib/python/|lib/python}} provides &amp;lt;tt&amp;gt;grass.script&amp;lt;/tt&amp;gt; and other packages in order to support GRASS scripts written in Python. The {{src|scripts}} directory of GRASS GIS 7 contains a series of examples actually provided to the end users (while the script in GRASS GIS 6 are shell scripts).&lt;br /&gt;
&lt;br /&gt;
For more general info, see also [[GRASS and Python]] and see also [[Converting Bash scripts to Python]] if you have some Bash scripts you want to rewrite to Python.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Calling a GRASS module in Python ===&lt;br /&gt;
&lt;br /&gt;
Imagine, you wanted to execute this command in Python:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  r.profile -g input=mymap output=newfile profile=12244.256,-295112.597,12128.012,-295293.77&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All arguments except the first (which is a flag) are keyword arguments, i.e. &amp;lt;tt&amp;gt;arg = val&amp;lt;/tt&amp;gt;. For the flag, use &amp;lt;tt&amp;gt;flags = 'g'&amp;lt;/tt&amp;gt; (note that &amp;quot;-g&amp;quot; would be the negative of a Python variable named &amp;quot;g&amp;quot;!). So:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('r.profile',&lt;br /&gt;
               input = input_map,&lt;br /&gt;
               output = output_file,&lt;br /&gt;
               profile = [12244.256,-295112.597,12128.012,-295293.77]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
or:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
               profile = [(12244.256,-295112.597),(12128.012,-295293.77)]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i.e. you need to provide the keyword, and the argument must be a valid Python expression. Function &amp;lt;code&amp;gt;run_command()&amp;lt;/code&amp;gt; etc accept lists and tuples.&lt;br /&gt;
&lt;br /&gt;
'''What is the proper way to include keyword-arguments tuples?'''&lt;br /&gt;
&lt;br /&gt;
For example, &amp;quot;g.list -f type=rast,vect&amp;quot; translates into:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;g.list&amp;quot;, flags=&amp;quot;f&amp;quot;, type=&amp;quot;rast,vect&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
or:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;g.list&amp;quot;, flags=&amp;quot;f&amp;quot;, type=[&amp;quot;rast&amp;quot;,&amp;quot;vect&amp;quot;])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The various *_command() functions accept arbitrary keyword arguments. Any keywords which don't have a specific meaning to either the *_command() function or the Popen constructor are treated as arguments to the GRASS module.&lt;br /&gt;
&lt;br /&gt;
'''What is the proper way to use multiple flags?'''&lt;br /&gt;
&lt;br /&gt;
How can I call a module with multiple flags set (e.g., -a and -b) in GRASS-Python?&lt;br /&gt;
&lt;br /&gt;
  flags = &amp;quot;ab&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;r.info&amp;quot;, flags=&amp;quot;eg&amp;quot;, map=[&amp;quot;elevation&amp;quot;])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Differences between ''run_command()'' and ''read_command()'':'''&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|run_command}} executes the command and waits for it to terminate; it doesn't redirect any of the standard streams.&lt;br /&gt;
* {{pyapi|script|script.core|read_command}} executes the command with stdout redirected to a pipe, and reads everything written to it. Once the command terminates, it returns the data written to stdout as a string.&lt;br /&gt;
&lt;br /&gt;
'''How to retrieve error messages from ''read_command()'':'''&lt;br /&gt;
&lt;br /&gt;
None of the existing *_command functions redirect stderr. You can do so with e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
def read2_command(*args, **kwargs):&lt;br /&gt;
   kwargs['stdout'] = grass.PIPE&lt;br /&gt;
   kwargs['stderr'] = grass.PIPE&lt;br /&gt;
   ps = grass.start_command(*args, **kwargs)&lt;br /&gt;
   return ps.communicate()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This behaves like &amp;lt;tt&amp;gt;read_command()&amp;lt;/tt&amp;gt; except that it returns a tuple of (stdout, stderr) rather than just stdout.&lt;br /&gt;
&lt;br /&gt;
== Uses for read, feed and pipe, start and exec commands ==&lt;br /&gt;
&lt;br /&gt;
All of the &amp;lt;tt&amp;gt;*_command&amp;lt;/tt&amp;gt; functions use {{pyapi|script|script.core|make_command}} to construct a command&lt;br /&gt;
line for a program which uses the {{cmd|g.parser|desc=GRASS parser}}. Most of them then pass&lt;br /&gt;
that command line to &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; via {{pyapi|script|script.core|start_command}}, except&lt;br /&gt;
for {{pyapi|script|script.core|exec_command}} which uses &amp;lt;tt&amp;gt;os.execvpe()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[To be precise, they use &amp;lt;tt&amp;gt;grass.Popen()&amp;lt;/tt&amp;gt;, which just calls&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; with 'shell=True' on Windows and 'shell=False'&lt;br /&gt;
otherwise. On Windows, you need to use 'shell=True' to be able to&lt;br /&gt;
execute scripts (including batch files); 'shell=False' only works with&lt;br /&gt;
binary executables.]&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.core|start_command}} separates the arguments into those which&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; understands and the rest. The rest are passed to&lt;br /&gt;
&amp;lt;tt&amp;gt;make_command()&amp;lt;/tt&amp;gt; to construct a command line which is passed as the&lt;br /&gt;
&amp;quot;args&amp;quot; parameter to &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, {{pyapi|script|script.core|start_command}} is a GRASS-oriented interface to&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt;. It should be suitable for any situation where you&lt;br /&gt;
would use &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; to execute a normal GRASS command (one&lt;br /&gt;
which uses the GRASS parser, which is almost all of them; the main&lt;br /&gt;
exception is {{cmd|r.mapcalc}} in 6.x).&lt;br /&gt;
&lt;br /&gt;
Most of the others are convenience wrappers around &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt;, for common use cases.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|run_command}} calls the wait() method on the process, so it doesn't return until the command has finished, and returns the command's exit code. Similar to &amp;lt;tt&amp;gt;system()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|pipe_command}} calls &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; with 'stdout=PIPE' and returns the process object. You can use the process' .stdout member to read the command's stdout. Similar to popen(..., &amp;quot;r&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|feed_command}} calls &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; with stdin=PIPE and returns the process object. You can use the process' .stdin member to write to the command's stdout. Similar to popen(..., &amp;quot;w&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|read_command}} calls &amp;lt;tt&amp;gt;pipe_command()&amp;lt;/tt&amp;gt;, reads the data from the command's stdout, and returns it as a string. Similar to `backticks` in the shell.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|write_command}} calls &amp;lt;tt&amp;gt;feed_command()&amp;lt;/tt&amp;gt;, sends the string specified by the &amp;quot;stdin&amp;quot; argument to the command's stdin, waits for the command to finish and returns its exit code. Similar to &amp;quot;echo ... | command&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|parse_command}} calls &amp;lt;tt&amp;gt;read_command()&amp;lt;/tt&amp;gt; and parses its output as key-value pairs. Useful for obtaining information from {{cmd|g.region}}, {{cmd|g.proj}}, {{cmd|r.info}}, etc.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|exec_command}} doesn't use &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; but &amp;lt;tt&amp;gt;os.execvpe()&amp;lt;/tt&amp;gt;. This causes the specified command to replace the current program (i.e. the Python script), so &amp;lt;tt&amp;gt;exec_command()&amp;lt;/tt&amp;gt; never returns. Similar to bash's &amp;quot;exec&amp;quot; command. This can be useful if the script is a &amp;quot;wrapper&amp;quot; around a single command, where you construct the command line and execute the command as the final step. Notes: exec_command() is rarely appropriate. You probably want run_command() instead. On Windows, exec_command() will probably require the &amp;quot;.exe&amp;quot; suffix.&lt;br /&gt;
&lt;br /&gt;
If you have any other questions, you might want to look at the code ({{src|lib/python/script/core.py}}). Most of these functions are only a few lines long.&lt;br /&gt;
&lt;br /&gt;
=== Hints for parse_command() ===&lt;br /&gt;
&lt;br /&gt;
To turn this command&lt;br /&gt;
        g.rename raster=old_name,new_name&lt;br /&gt;
into a g.parse_command() call, you need to consider that it is a function call with three arguments:&lt;br /&gt;
# &amp;quot;g.rename&amp;quot;&lt;br /&gt;
# raster=old_name&lt;br /&gt;
# new_name&lt;br /&gt;
&lt;br /&gt;
The second argument is a keyword argument, the first and third are&lt;br /&gt;
positional (non-keyword) arguments. Python doesn't allow positional&lt;br /&gt;
arguments to follow keyword arguments; positional arguments come&lt;br /&gt;
first, keyword arguments last.&lt;br /&gt;
&lt;br /&gt;
Given the context, it's safe to assume that you want to pass a pair of&lt;br /&gt;
map names as the value to the rast= option. This requires explicit&lt;br /&gt;
parentheses so that the comma is treated as forming a tuple rather&lt;br /&gt;
than as an argument separator:&lt;br /&gt;
&lt;br /&gt;
        g.parse_command(&amp;quot;g.rename&amp;quot;, raster=(old_name,new_name))&lt;br /&gt;
&lt;br /&gt;
The parentheses in a tuple value can only be omitted if it doesn't&lt;br /&gt;
result in the comma being ambiguous (as is the case in a function&lt;br /&gt;
call).&lt;br /&gt;
&lt;br /&gt;
== Interfacing ==&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy ===&lt;br /&gt;
&lt;br /&gt;
The {{pyapi|script|script.array|array}} module defines a &amp;lt;code&amp;gt;class array&amp;lt;/code&amp;gt; which is a subclass of [http://docs.scipy.org/doc/numpy/reference/generated/numpy.memmap.html numpy.memmap] that reads/writes the underlying file via {{cmd|r.out.bin}}/{{cmd|r.in.bin}}. Metadata can be read with {{pyapi|script|script.raster|raster_info}}:&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
import grass.script.array as garray&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    map = &amp;quot;elevation.dem&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # read map&lt;br /&gt;
    a = garray.array(map)&lt;br /&gt;
&lt;br /&gt;
    # get raster map info&lt;br /&gt;
    print(grass.raster_info(map)['datatype'])&lt;br /&gt;
    i = grass.raster_info(map)&lt;br /&gt;
    &lt;br /&gt;
    # get computational region info&lt;br /&gt;
    c = grass.region()&lt;br /&gt;
    print(&amp;quot;rows: %d&amp;quot; % c['rows'])&lt;br /&gt;
    print(&amp;quot;cols: %d&amp;quot; % c['cols'])&lt;br /&gt;
&lt;br /&gt;
    # new array for result&lt;br /&gt;
    b = garray.array()&lt;br /&gt;
    # calculate new map from input map and store as GRASS raster map&lt;br /&gt;
    b[...] = (a / 50).astype(int) * 50&lt;br /&gt;
    b.write(&amp;quot;elev.50m&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The size of the array is taken from the current region ([[computational region]]).&lt;br /&gt;
&lt;br /&gt;
The main drawback of using numpy is that you're limited by available&lt;br /&gt;
memory. Using a subclass of &amp;lt;code&amp;gt;numpy.memmap&amp;lt;/code&amp;gt; lets you use files which may&lt;br /&gt;
be much larger, but processing the entire array in one go is likely to&lt;br /&gt;
produce in-memory results of a similar size.&lt;br /&gt;
&lt;br /&gt;
'''NULL (no data) management:'''&lt;br /&gt;
&lt;br /&gt;
For integer maps, the NULL value is -2^31 = -2147483648. For floating-point maps, the NULL value is NaN. Note that the null= parameter for read() and write() specifies the value in the numpy array which is mapped to/from null values in the GRASS raster map.&lt;br /&gt;
&lt;br /&gt;
If you're using floating-point numpy arrays, then use (Note: This assumes that atof() and sscanf(&amp;quot;%lf&amp;quot;) recognise &amp;quot;nan&amp;quot;; this is the case on Linux, but doesn't appear to work on Windows)&lt;br /&gt;
 null=numpy.nan&lt;br /&gt;
&lt;br /&gt;
For integer arrays, using&lt;br /&gt;
 null=-2147483648&lt;br /&gt;
will ensure that valid values don't collide with NYLLs.&lt;br /&gt;
&lt;br /&gt;
'''MASK support:'''&lt;br /&gt;
&lt;br /&gt;
Reading and writing use r.out.bin and r.in.bin respectively. r.out.bin respects the MASK.&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy and SciPy  ===&lt;br /&gt;
&lt;br /&gt;
[http://docs.scipy.org/doc/scipy/reference/index.html SciPy] offers simple access to complex calculations. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from scipy import stats&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
import grass.script.array as garray&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    map = &amp;quot;elevation&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    x = garray.array(map)&lt;br /&gt;
&lt;br /&gt;
    # Descriptive Statistics:&lt;br /&gt;
    print(&amp;quot;max, min, mean, var:&amp;quot;)&lt;br /&gt;
    print(x.max(), x.min(), x.mean(), x.var())&lt;br /&gt;
    print(&amp;quot;Skewness test: z-score and 2-sided p-value:&amp;quot;)&lt;br /&gt;
    print(stats.skewtest(stats.skew(x)))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy, SciPy and Matlab ===&lt;br /&gt;
&lt;br /&gt;
One may also use the SciPy - Matlab interface:&lt;br /&gt;
    &lt;br /&gt;
    r.out.mat input=elevation output=elev.mat&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    ### PY ###&lt;br /&gt;
    import scipy.io as sio&lt;br /&gt;
    # load data&lt;br /&gt;
    elev = sio.loadmat('elev.mat')&lt;br /&gt;
    # retrive the actual array. the data set contains also the spatial reference&lt;br /&gt;
    elev.get('map_data')&lt;br /&gt;
    data = elev.get('map_data')&lt;br /&gt;
    # a first simple plot&lt;br /&gt;
    import pylab&lt;br /&gt;
    pylab.plot(data)&lt;br /&gt;
    pylab.show()&lt;br /&gt;
    # the contour plot&lt;br /&gt;
    pylab.contour(data)&lt;br /&gt;
    # obviously data needs to ne reversed&lt;br /&gt;
    import numpy as np&lt;br /&gt;
    data_rev = data[::-1]&lt;br /&gt;
    pylab.contour(data_rev)&lt;br /&gt;
    # =&amp;gt; this is a quick plot. basemap mapping may provide a nicer map!&lt;br /&gt;
    #######&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Usage Examples ==&lt;br /&gt;
&lt;br /&gt;
=== Display example ===&lt;br /&gt;
Example of Python script, which is processed by {{cmd|g.parser}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
#&lt;br /&gt;
############################################################################&lt;br /&gt;
#&lt;br /&gt;
# MODULE:      d.shadedmap&lt;br /&gt;
# AUTHOR(S):   Unknown; updated to GRASS 5.7 by Michael Barton&lt;br /&gt;
#              Converted to Python by Glynn Clements&lt;br /&gt;
# PURPOSE:     Uses d.his to drape a color raster over a shaded relief map&lt;br /&gt;
# COPYRIGHT:   (C) 2004,2008,2009 by the GRASS Development Team&lt;br /&gt;
#&lt;br /&gt;
#              This program is free software under the GNU General Public&lt;br /&gt;
#              License (&amp;gt;=v2). Read the file COPYING that comes with GRASS&lt;br /&gt;
#              for details.&lt;br /&gt;
#&lt;br /&gt;
#############################################################################&lt;br /&gt;
&lt;br /&gt;
#%Module&lt;br /&gt;
#% description: Drapes a color raster over a shaded relief map using d.his&lt;br /&gt;
#% keyword: display&lt;br /&gt;
#% keyword: raster&lt;br /&gt;
#%End&lt;br /&gt;
#%option&lt;br /&gt;
#% key: reliefmap&lt;br /&gt;
#% type: string&lt;br /&gt;
#% gisprompt: old,cell,raster&lt;br /&gt;
#% description: Name of shaded relief or aspect map&lt;br /&gt;
#% required : yes&lt;br /&gt;
#%end&lt;br /&gt;
#%option&lt;br /&gt;
#% key: drapemap&lt;br /&gt;
#% type: string&lt;br /&gt;
#% gisprompt: old,cell,raster&lt;br /&gt;
#% description: Name of raster to drape over relief map&lt;br /&gt;
#% required : yes&lt;br /&gt;
#%end&lt;br /&gt;
#%option&lt;br /&gt;
#% key: brighten&lt;br /&gt;
#% type: integer&lt;br /&gt;
#% description: Percent to brighten&lt;br /&gt;
#% options: -99-99&lt;br /&gt;
#% answer: 0&lt;br /&gt;
#%end&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    drape_map = options['drapemap']&lt;br /&gt;
    relief_map = options['reliefmap']&lt;br /&gt;
    brighten = options['brighten']&lt;br /&gt;
    ret = grass.run_command(&amp;quot;d.his&amp;quot;, h_map = drape_map,  i_map = relief_map, brighten = brighten)&lt;br /&gt;
    sys.exit(ret)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    options, flags = grass.parser()&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parsing the options and flags  ===&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.core|parser}} is an interface to {{cmd|g.parser}}, and allows to parse the ''options'' and ''flags'' passed to your script on the command line. It is to be called at the top-level:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    options, flags = grass.parser()&lt;br /&gt;
    main()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Global variables &amp;quot;options&amp;quot; and &amp;quot;flags&amp;quot; are Python dictionaries containing the options/flags values, keyed by lower-case option/flag names. The values in &amp;quot;options&amp;quot; are strings, those in &amp;quot;flags&amp;quot; are Python booleans. All those variables have to be previously declared in the header of your script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; options, flags = grass.parser()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; options&lt;br /&gt;
{'input': 'my_map', 'output': 'map_out', 'option1': '21.472', 'option2': ''}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; flags&lt;br /&gt;
{'c': True, 'm': False}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Accessing the --quiet and --verbose flags:'''&lt;br /&gt;
&lt;br /&gt;
See {{pyapi|script|script.core|verbosity}} for the 5 verbosity levels:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
&lt;br /&gt;
# to hide non-error messages from subprocesses&lt;br /&gt;
if grass.verbosity() &amp;lt;= 2:&lt;br /&gt;
    outdev = open(os.devnull, 'w')&lt;br /&gt;
else:&lt;br /&gt;
    outdev = sys.stdout&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Passing several floats to a single option ===&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
python my.module.py input=input output=output myoption=0.1,0.2,0.5&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The values in the &amp;quot;options&amp;quot; dictionary returned from the parser()&lt;br /&gt;
function are always strings. You can parse the string with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        myoption = map(float, options['myoption'].split(','))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The option definition in the script should have:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        #% type: double&lt;br /&gt;
        #% multiple: yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This allows g.parser to validate the option syntax, so you can rely&lt;br /&gt;
upon the string being in the correct format. If the values have a&lt;br /&gt;
fixed range, you can use e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        #% options: 0.0-1.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to have the parser check that the values fall within the range.&lt;br /&gt;
&lt;br /&gt;
For more information on option definitions, see:&lt;br /&gt;
&lt;br /&gt;
https://grass.osgeo.org/programming7/gislib.html#Complete_Structure_Members_Table&lt;br /&gt;
&lt;br /&gt;
=== Example for embedding r.mapcalc (map algebra) ===&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.raster|mapcalc}} accepts a template string followed by keyword&lt;br /&gt;
arguments for the substitutions, e.g. (code snippets):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
grass.mapcalc(&amp;quot;${out} = ${rast1} + ${rast2}&amp;quot;,&lt;br /&gt;
              out = options['output'],&lt;br /&gt;
              rast1 = options['raster1'],&lt;br /&gt;
              rast2 = options['raster2'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Best practice'': first copy all of the options[] into separate variables at the beginning of main(), i.e.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def main():&lt;br /&gt;
    output = options['output']&lt;br /&gt;
    raster1 = options['raster1']&lt;br /&gt;
    raster2 = options['raster2']&lt;br /&gt;
 &lt;br /&gt;
    ...&lt;br /&gt;
 &lt;br /&gt;
    grass.mapcalc(&amp;quot;${out} = ${rast1} + ${rast2}&amp;quot;,&lt;br /&gt;
                  out = output,&lt;br /&gt;
                  rast1 = raster1,&lt;br /&gt;
                  rast2 = raster2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Performing multiple computations using &amp;lt;tt&amp;gt;grass.script.raster.mapcalc()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
expr = &amp;quot;;&amp;quot;.join([&lt;br /&gt;
        &amp;quot;$out.r = r#$first * $frac + (1.0 - $frac) * r#$second&amp;quot;,&lt;br /&gt;
        &amp;quot;$out.g = g#$first * $frac + (1.0 - $frac) * g#$second&amp;quot;,&lt;br /&gt;
        &amp;quot;$out.b = b#$first * $frac + (1.0 - $frac) * b#$second&amp;quot;])&lt;br /&gt;
grass.mapcalc(expr, out=out, first=first, second=second, frac=percent/100.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hint: multi-line strings can be separated by using a semicolon instead of a newline.&lt;br /&gt;
&lt;br /&gt;
=== Looping over file names stored in an ASCII file ===&lt;br /&gt;
&lt;br /&gt;
When looping over file names stored in an ASCII file and getting the error&lt;br /&gt;
&lt;br /&gt;
   WARNING: Illegal filename &amp;lt;map.f1jan.05216.something&lt;br /&gt;
          &amp;gt;. Character &amp;lt;&lt;br /&gt;
          &amp;gt; not allowed.&lt;br /&gt;
&lt;br /&gt;
then the line terminators may be the reason.&lt;br /&gt;
When you iterate over a file, the strings include the line terminators (e.g. '\n' or '\r\n'). Use e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    for line in gl:&lt;br /&gt;
        renamed = line.rstrip().replace('.','_')&lt;br /&gt;
        ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to remove any trailing whitespace (including newlines) from each line.&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing raster category labels ===&lt;br /&gt;
&lt;br /&gt;
How to obtain the text labels&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    # dump cats to file to avoid &amp;quot;too many argument&amp;quot; problem:&lt;br /&gt;
    p = grass.pipe_command('r.category', map = rastertmp, separator = ';', quiet = True)&lt;br /&gt;
    cats = []&lt;br /&gt;
    for line in p.stdout:&lt;br /&gt;
        cats.append(line.rstrip('\r\n').split(';')[0])&lt;br /&gt;
    p.wait()&lt;br /&gt;
&lt;br /&gt;
    number = len(cats)&lt;br /&gt;
    if number &amp;lt; 1:&lt;br /&gt;
        grass.fatal(_(&amp;quot;No categories found in raster map&amp;quot;))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing category numbers ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' How to obtain the number of cells of a certain category?&lt;br /&gt;
&lt;br /&gt;
'''A:''' It is recommended to use {{pyapi|script|script.core|pipe_command}} and parse the output, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       p = grass.pipe_command('r.stats',flags='c',input='map')&lt;br /&gt;
       result = {}&lt;br /&gt;
       for line in p.stdout:&lt;br /&gt;
           val,count = line.strip().split()&lt;br /&gt;
           result[int(val)] = int(count)&lt;br /&gt;
       p.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing the region output of a module ===&lt;br /&gt;
&lt;br /&gt;
Some of the GRASS GIS modules are delivering region information (e.g. {{cmd|r.in.xyz}} which scans a LiDAR file for the extent of the point cloud). The retrieved region settings (using '''-g''' flag for script style output) can be parsed in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
from grass.script import core as gcore&lt;br /&gt;
&lt;br /&gt;
from grass.pygrass.modules.shortcuts import general as g&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
&lt;br /&gt;
# scan a LiDAR xyz point file for its extent&lt;br /&gt;
compregion = gcore.parse_command(&amp;quot;r.in.xyz&amp;quot;, input=&amp;quot;tmp.xyz&amp;quot;, separator=&amp;quot;space&amp;quot;, flags=&amp;quot;sg&amp;quot;, output=&amp;quot;bbox&amp;quot;,&lt;br /&gt;
                                  parse=(gcore.parse_key_val, {'sep': '=', 'vsep': ' '}))&lt;br /&gt;
print(compregion)&lt;br /&gt;
# set computational region from LiDAR extent&lt;br /&gt;
# hint: we turn here the dictionary to a region by unpacking the dictionary:&lt;br /&gt;
g.region(res=&amp;quot;1&amp;quot;, flags=&amp;quot;p&amp;quot;, **compregion)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the two '''*''' above which unpack the dictionary (see also the related [https://docs.python.org/2/tutorial/controlflow.html#keyword-arguments Python manual] page).&lt;br /&gt;
&lt;br /&gt;
=== Example for getting the region's number of rows and columns ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' How to obtain the number of rows and columns of the current region?&lt;br /&gt;
&lt;br /&gt;
'''A:''' It is recommended to use the {{pyapi|script|script.core|region}} function which will create a dictionary with values for extents and resolution, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
#-*- coding:utf-8 -*-&lt;br /&gt;
#&lt;br /&gt;
############################################################################&lt;br /&gt;
#&lt;br /&gt;
# MODULE:       g.region.resolution&lt;br /&gt;
# AUTHOR(S):    based on a post at GRASS-USER mailing list [1]               &lt;br /&gt;
# PURPOSE:	Parses &amp;quot;g.region -g&amp;quot;, prints out number of rows, cols&lt;br /&gt;
# COPYLEFT:     ;-)&lt;br /&gt;
# COMMENT:      ...a lot of comments to be easy-to-read for/by beginners&lt;br /&gt;
#&lt;br /&gt;
#############################################################################&lt;br /&gt;
#&lt;br /&gt;
#%Module&lt;br /&gt;
#% description: Print number of rows, cols of current geographic region&lt;br /&gt;
#% keyword: region&lt;br /&gt;
#%end&lt;br /&gt;
&lt;br /&gt;
# importing required modules&lt;br /&gt;
import sys # the sys module [2]&lt;br /&gt;
from grass.script import core as grass # the core module [3]&lt;br /&gt;
&lt;br /&gt;
# information about imported modules can be obtained using the dir() function&lt;br /&gt;
# e.g.: dir(sys)&lt;br /&gt;
&lt;br /&gt;
# define the &amp;quot;main&amp;quot; function: get number of rows, cols of region&lt;br /&gt;
def main():&lt;br /&gt;
    &lt;br /&gt;
    # #######################################################################&lt;br /&gt;
    # the following commented code works but is kept only for learning purposes&lt;br /&gt;
     &lt;br /&gt;
    ## assigning the output of the command &amp;quot;g.region -g&amp;quot; in a string called &amp;quot;return_rows_x_cols&amp;quot;&lt;br /&gt;
    # return_rows_x_cols = grass.read_command('g.region', flags = 'g')&lt;br /&gt;
    &lt;br /&gt;
    ## parsing arguments of interest (rows, cols) in a dictionary named &amp;quot;rows_x_cols&amp;quot;&lt;br /&gt;
    # rows_x_cols = grass.parse_key_val(return_rows_x_cols)&lt;br /&gt;
    &lt;br /&gt;
    ## selectively print rows, cols from the dictionary &amp;quot;rows_x_cols&amp;quot;&lt;br /&gt;
    # print 'rows=%d \ncols=%d' % (int(rows_x_cols['rows']), int(rows_x_cols['cols']))&lt;br /&gt;
    &lt;br /&gt;
    # #######################################################################&lt;br /&gt;
    &lt;br /&gt;
    # faster/ easier way: use of the &amp;quot;grass.region()&amp;quot; function&lt;br /&gt;
    gregion = grass.region()&lt;br /&gt;
    rows = gregion['rows']&lt;br /&gt;
    cols = gregion['cols']&lt;br /&gt;
    &lt;br /&gt;
    # print rows, cols properly formatted &lt;br /&gt;
    print 'rows=%d \ncols=%d' % (rows, cols)&lt;br /&gt;
&lt;br /&gt;
    # average resolution (in case of non-square pixels)&lt;br /&gt;
    avg_res=(gregion['nsres'] + gregion['ewres']) / 2.0&lt;br /&gt;
&lt;br /&gt;
# this &amp;quot;if&amp;quot; condition instructs execution of code contained in this script, *only* if the script is being executed directly &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;: # this allows the script to be used as a module in other scripts or as a standalone script&lt;br /&gt;
    options, flags = grass.parser() #&lt;br /&gt;
    sys.exit(main()) #&lt;br /&gt;
&lt;br /&gt;
# Links&lt;br /&gt;
# [1] http://n2.nabble.com/Getting-rows-cols-of-a-region-in-a-script-tp2787474p2787509.html&lt;br /&gt;
# [2] http://www.python.org/doc/2.5.2/lib/module-sys.html&lt;br /&gt;
# [3] https://grass.osgeo.org/grass78/manuals/libpython&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Managing mapsets ===&lt;br /&gt;
&lt;br /&gt;
To check if a certain mapset exists in the active location, use {{pyapi|script|script.core|mapsets}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.mapsets(False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
... returns a list of mapsets in the current location.&lt;br /&gt;
&lt;br /&gt;
=== r.mapcalc example ===&lt;br /&gt;
&lt;br /&gt;
Example of Python script, which is processed by {{cmd|g.parser}}:&lt;br /&gt;
&lt;br /&gt;
The shell script line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  r.mapcalc &amp;quot;MASK = if(($cloudResampName &amp;lt; 0.01000),1,null())&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would be written like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       ...&lt;br /&gt;
&lt;br /&gt;
       grass.mapcalc(&amp;quot;MASK=if(($cloudResampName &amp;lt; 0.01000),1,null())&amp;quot;,&lt;br /&gt;
                     cloudResampName = cloudResampName)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first argument to the mapcalc function is a template (see the Python library documentation for [http://docs.python.org/library/string.html string.Template]). Any keyword arguments (other than &amp;lt;tt&amp;gt;quiet&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;verbose&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;overwrite&amp;lt;/tt&amp;gt;) specify substitutions.&lt;br /&gt;
&lt;br /&gt;
=== r.mapcalc example: defining a moving window ===&lt;br /&gt;
&lt;br /&gt;
Moving window of 4 cell in every 8 direction and do a boolean comparison. Boolean value (e.g. the result of a comparison) is an integer, with 1 for true, 0 for false.&lt;br /&gt;
Then do a r.mapcalc calculation with the moving window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
           &lt;br /&gt;
       # define a moving window of 4 cell in every 8 direction&lt;br /&gt;
       #&lt;br /&gt;
       # map[4,4]                                    map[4,0]                                    map[4,-4]		&lt;br /&gt;
       # 	    map[3,3]                         map[3,0]                         map[3,-3]			&lt;br /&gt;
       # 		       map[2,2]              map[2,0]              map[2,-2]				&lt;br /&gt;
       #                                  map[1,1]   map[1,0]   map[1,-1]	 				&lt;br /&gt;
       # map[0,4]   map[0,3]   map[0,2]   map[0,1]       x      map[0,-1]  map[0,-2]  map[0,-3]  map[0,-4]&lt;br /&gt;
       #                                  map[-1,1]  map[-1,0]  map[-1,-1]					&lt;br /&gt;
       #                       map[-2,2]             map[-2,0]             map[-2,-2]				&lt;br /&gt;
       #            map[-3,3]                        map[-3,0]                        map[-3,-3]			&lt;br /&gt;
       # map[-4,4]                                   map[-4,0]                                   map[-4,-4]&lt;br /&gt;
       &lt;br /&gt;
       # define the offet duplets&lt;br /&gt;
       &lt;br /&gt;
       offsets = [d&lt;br /&gt;
           for j in xrange(1,4+1)&lt;br /&gt;
           for i in [j,-j]&lt;br /&gt;
           for d in [(i,0),(0,i),(i,i),(i,-i)]]&lt;br /&gt;
       	&lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;offsets&lt;br /&gt;
       # [(1, 0), (0, 1), (1, 1), (1, -1), (-1, 0), (0, -1), (-1, -1), (-1, 1), (2, 0), (0, 2), (2, 2), (2, -2), (-2, 0), (0, -2), \&lt;br /&gt;
       # (-2, -2), (-2, 2), (3, 0), (0, 3), (3, 3), (3, -3), (-3, 0), (0, -3), (-3, -3), (-3, 3), (4, 0), (0, 4), (4, 4), (4, -4), \&lt;br /&gt;
       # (-4, 0), (0, -4), (-4, -4), (-4, 4)]&lt;br /&gt;
       &lt;br /&gt;
       # define the calculation term&lt;br /&gt;
       &lt;br /&gt;
       terms = [&amp;quot;(myelevnc[%d,%d] &amp;lt; myelevnc)&amp;quot; % d&lt;br /&gt;
                for d in offsets]&lt;br /&gt;
       &lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;terms&lt;br /&gt;
       # ['(myelevnc[1,0] &amp;lt; myelevnc)', '(myelevnc[0,1] &amp;lt; myelevnc)', '(myelevnc[1,1] &amp;lt; myelevnc)', '(myelevnc[1,-1] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-1,0] &amp;lt; myelevnc)', '(myelevnc[0,-1] &amp;lt; myelevnc)', '(myelevnc[-1,-1] &amp;lt; myelevnc)', '(myelevnc[-1,1] &amp;lt; myelevnc)',\&lt;br /&gt;
       # '(myelevnc[2,0] &amp;lt; myelevnc)', '(myelevnc[0,2] &amp;lt; myelevnc)', '(myelevnc[2,2] &amp;lt; myelevnc)', '(myelevnc[2,-2] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-2,0] &amp;lt; myelevnc)', '(myelevnc[0,-2] &amp;lt; myelevnc)', '(myelevnc[-2,-2] &amp;lt; myelevnc)', '(myelevnc[-2,2] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[3,0] &amp;lt; myelevnc)', '(myelevnc[0,3] &amp;lt; myelevnc)', '(myelevnc[3,3] &amp;lt; myelevnc)', '(myelevnc[3,-3] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-3,0] &amp;lt; myelevnc)', '(myelevnc[0,-3] &amp;lt; myelevnc)', '(myelevnc[-3,-3] &amp;lt; myelevnc)', '(myelevnc[-3,3] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[4,0] &amp;lt; myelevnc)', '(myelevnc[0,4] &amp;lt; myelevnc)', '(myelevnc[4,4] &amp;lt; myelevnc)', '(myelevnc[4,-4] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-4,0] &amp;lt; myelevnc)', '(myelevnc[0,-4] &amp;lt; myelevnc)', '(myelevnc[-4,-4] &amp;lt; myelevnc)', '(myelevnc[-4,4] &amp;lt; myelevnc)']&lt;br /&gt;
       &lt;br /&gt;
       # define the calculation expression&lt;br /&gt;
       &lt;br /&gt;
       expr = &amp;quot;elevation_percentile4 = (100.0 / 48.0) * (%s)&amp;quot; % &amp;quot; + &amp;quot;.join(terms)&lt;br /&gt;
       &lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;expr&lt;br /&gt;
       #  elevation_percentile4 = (100.0 / 48.0) * ((myelevnc[1,0] &amp;lt; myelevnc) + (myelevnc[0,1] &amp;lt; myelevnc) + (myelevnc[1,1] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[1,-1] &amp;lt; myelevnc) + (myelevnc[-1,0] &amp;lt; myelevnc) + (myelevnc[0,-1] &amp;lt; myelevnc) + (myelevnc[-1,-1] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-1,1] &amp;lt; myelevnc) + (myelevnc[2,0] &amp;lt; myelevnc) + (myelevnc[0,2] &amp;lt; myelevnc) + (myelevnc[2,2] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[2,-2] &amp;lt; myelevnc) + (myelevnc[-2,0] &amp;lt; myelevnc) + (myelevnc[0,-2] &amp;lt; myelevnc) + (myelevnc[-2,-2] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-2,2] &amp;lt; myelevnc) + (myelevnc[3,0] &amp;lt; myelevnc) + (myelevnc[0,3] &amp;lt; myelevnc) + (myelevnc[3,3] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[3,-3] &amp;lt; myelevnc) + (myelevnc[-3,0] &amp;lt; myelevnc) + (myelevnc[0,-3] &amp;lt; myelevnc) + (myelevnc[-3,-3] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-3,3] &amp;lt; myelevnc) + (myelevnc[4,0] &amp;lt; myelevnc) + (myelevnc[0,4] &amp;lt; myelevnc) + (myelevnc[4,4] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[4,-4] &amp;lt; myelevnc) + (myelevnc[-4,0] &amp;lt; myelevnc) + (myelevnc[0,-4] &amp;lt; myelevnc) + (myelevnc[-4,-4] &amp;lt; myelevnc)\&lt;br /&gt;
       #  + (myelevnc[-4,4] &amp;lt; myelevnc))&lt;br /&gt;
       &lt;br /&gt;
       # do the r.mapcalc calculation with the moving window&lt;br /&gt;
       &lt;br /&gt;
       grass.mapcalc( expr )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using output from GRASS modules in the script ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you need to use the output of a module for the next step. There are dedicated functions to obtain the result of, for example, a statistical analysis.&lt;br /&gt;
&lt;br /&gt;
Example: get the range of a raster map and use it in {{cmd|r.mapcalc}}. Here you can use {{pyapi|script|script.raster|raster_info}}, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       max = grass.raster_info(inmap)['max']&lt;br /&gt;
       grass.mapcalc(&amp;quot;$outmap = $inmap / $max&amp;quot;,&lt;br /&gt;
                     inmap = inmap, outmap = outmap, max = max)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using output from r.what ===&lt;br /&gt;
&lt;br /&gt;
''Q: How does one return attribute values from a call to the 'r.what' module running in a python script?''&lt;br /&gt;
&lt;br /&gt;
A: If you use &amp;lt;tt&amp;gt;grass.script.raster_what()&amp;lt;/tt&amp;gt;, it returns a list of dictionaries.&lt;br /&gt;
&lt;br /&gt;
PyGRASS which requires you to add &amp;lt;tt&amp;gt;stdout_=PIPE&amp;lt;/tt&amp;gt;, then you can get the output as a string from &amp;lt;tt&amp;gt;module.outputs.stdout&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Or using directly the C API through python with (North Carolina dataset example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.vector import VectorTopo&lt;br /&gt;
from grass.pygrass.raster import RasterRow&lt;br /&gt;
from grass.pygrass.gis.region import Region&lt;br /&gt;
&lt;br /&gt;
with RasterRow('elevation', mode='r') as rast:&lt;br /&gt;
    with VectorTopo('hospitals', mode='r') as hospitals:&lt;br /&gt;
        region = Region()&lt;br /&gt;
        for hosp in hospitals:&lt;br /&gt;
            value = rast.get_value(hosp, region)&lt;br /&gt;
            if value is not None:&lt;br /&gt;
                print(hosp.cat, value)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoiding a syntax error for r.rescale ===&lt;br /&gt;
&lt;br /&gt;
''Q: How to avoid a syntax error for r.rescale related to &amp;quot;from=&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
A: &amp;quot;from&amp;quot; is a reserved word, use from_ instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
grass.run_command('r.rescale', input=mis1, output=mis1_8bit, from_='0,2048', to='0,255')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interface to copying maps (g.copy) ===&lt;br /&gt;
&lt;br /&gt;
Copy a raster map (for vector, replace &amp;quot;rast&amp;quot; with &amp;quot;vect&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('g.copy', rast = (input, output))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To generalize it, &amp;quot;datatype&amp;quot; is the form of grass data to copy (eg, rast, vect, etc)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('g.copy', **{datatype: (input, output)})&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interface to listing maps (g.list) ===&lt;br /&gt;
&lt;br /&gt;
You may use the functions in [https://grass.osgeo.org/grass-stable/manuals/libpython/script.html?highlight=list_grouped#script.core.list_grouped script.core.list_grouped()]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# list all&lt;br /&gt;
list_grouped('raster')['PERMANENT']&lt;br /&gt;
[..., 'lakes', ..., 'slope', ...&lt;br /&gt;
&lt;br /&gt;
# list with pattern&lt;br /&gt;
list_grouped('vect', pattern='*roads*')['PERMANENT']&lt;br /&gt;
['railroads', 'roadsmajor']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For temporal data, see likewise [https://grass.osgeo.org/grass-stable/manuals/libpython/temporal.html?highlight=list_grouped#temporal.gui_support.tlist_grouped temporal.gui_support.tlist_grouped()]&lt;br /&gt;
&lt;br /&gt;
See also [[Python/pygrass#Sample_PyGRASS_scripts|Sample PyGRASS scripts]] for an alternative solution.&lt;br /&gt;
&lt;br /&gt;
=== i.group with patterns as name for input ===&lt;br /&gt;
&lt;br /&gt;
Imagery groups can be populated like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.gis import Mapset&lt;br /&gt;
&lt;br /&gt;
run_command(&amp;quot;i.group&amp;quot;, group=&amp;quot;mygroup&amp;quot;, input=mset.glist(&amp;quot;raster&amp;quot;, pattern=&amp;quot;mypattern_*&amp;quot;))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Percentage output for progress of computation ===&lt;br /&gt;
&lt;br /&gt;
A) Within a Python script, the {{pyapi|script|script.core|percent}} module method wraps the &amp;lt;tt&amp;gt;g.message -p&amp;lt;/tt&amp;gt; command.&lt;br /&gt;
&lt;br /&gt;
B) If you call a GRASS command within the Python code, you have to parse the output by setting &amp;lt;tt&amp;gt;GRASS_MESSAGE_FORMAT=gui&amp;lt;/tt&amp;gt; in the environment when running the command and read from the command's stderr; e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       env = os.environ.copy()&lt;br /&gt;
       env['GRASS_MESSAGE_FORMAT'] = 'gui'&lt;br /&gt;
       p = grass.start_command(..., stderr = grass.PIPE, env = env)&lt;br /&gt;
       # read from p.stderr&lt;br /&gt;
       p.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need to capture both stdout and stderr, you need to use threads, select, or non-blocking I/O to consume data from both streams as it is generated in order to avoid deadlock.&lt;br /&gt;
&lt;br /&gt;
ALTERNATIVE:&lt;br /&gt;
&lt;br /&gt;
Redirect both stdout and stderr to the same pipe (and hope that the normal output doesn't include anything which will be mistaken for progress/error/etc messages):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       p = grass.start_command(..., stdout = grass.PIPE, stderr = grass.STDOUT, env = env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NULL data management ===&lt;br /&gt;
&lt;br /&gt;
How to analyse if there are only NULL cells in a map:&lt;br /&gt;
&lt;br /&gt;
If a map contains only null cells, its minimum and maximum will be &amp;quot;NULL&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
       $ r.mapcalc 'foo = null()'&lt;br /&gt;
       $ r.info -r foo&lt;br /&gt;
       min=NULL&lt;br /&gt;
       max=NULL&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using the Python API, The 'min' and 'max' values in the result of the {{pyapi|script|script.raster|raster_info}} function will be &amp;lt;tt&amp;gt;None&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Counting cells ===&lt;br /&gt;
&lt;br /&gt;
Counting cells is far more expensive than simply determining whether&lt;br /&gt;
there are any non-null cells. Counting cells requires reading the&lt;br /&gt;
entire map, while the {{cmd|r.info}} approach only needs to read the metadata&lt;br /&gt;
files.&lt;br /&gt;
&lt;br /&gt;
If you do need to count cells, {{cmd|r.stats}} is likely to be more efficient than {{cmd|r.univar}}.&lt;br /&gt;
&lt;br /&gt;
A count loop:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       while grass.raster_info(inmap)['max'] is not None:&lt;br /&gt;
           ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Display: overlayed map display with labels ===&lt;br /&gt;
&lt;br /&gt;
Example: display a vector map and overlay its labels on top of the map.&lt;br /&gt;
&lt;br /&gt;
If the environment contains the setting GRASS_PNG_READ=TRUE, d.* commands should overlay their output on an existing image (otherwise the first command creates the file map.png but the second command overwrites the file with only the labels). So the following should work:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('d.vect', map='my_shape')&lt;br /&gt;
       env = os.environ.copy()&lt;br /&gt;
       env['GRASS_PNG_READ'] = 'TRUE'&lt;br /&gt;
       grass.run_command('d.labels', labels='my_shape_labels', env = env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Path to GISDBASE ===&lt;br /&gt;
In order to a avoid hardcoded paths to GRASS mapset files like the SQLite DB file, you can get the GISDBASE variable from the environment:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       import os.path&lt;br /&gt;
&lt;br /&gt;
       env = grass.gisenv()&lt;br /&gt;
&lt;br /&gt;
       gisdbase = env['GISDBASE']&lt;br /&gt;
       location = env['LOCATION_NAME']&lt;br /&gt;
       mapset = env['MAPSET']&lt;br /&gt;
&lt;br /&gt;
       path = os.path.join(gisdbase, location, mapset, 'sqlite.db')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parse the GRASS GIS version or revision or path to library ===&lt;br /&gt;
&lt;br /&gt;
In order to a avoid hardcoded versions or to scan the SVN revision of the GRASS GIS version used, you can query the {{cmd|helptext|startup script}}:&lt;br /&gt;
&lt;br /&gt;
'''Variant 1 (pure Python solution) - svn_revision:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
cmd = subprocess.Popen('grass78 --config svn_revision', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
revision = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(revision)&lt;br /&gt;
# the result is for example: '72327'.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Variant 2 (GRASS GIS-Python solution) - svn_revision:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
cmd = grass.Popen('grass78 --config svn_revision', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
revision = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(revision)&lt;br /&gt;
# the result is for example: '72327'.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Path to GRASS GIS library (GRASS GIS-Python solution):'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
cmd = grass.Popen('grass78 --config path', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
version = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(version)&lt;br /&gt;
# the result is for example: '/usr/local/grass-7.6.svn'&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a new location ===&lt;br /&gt;
&lt;br /&gt;
Use {{pyapi|script|script.core|create_location}} to create a new location.&lt;br /&gt;
&lt;br /&gt;
=== Use Python reserved keyword ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' ''r.resamp.bspline'' uses 'lambda' as a command line parameter name, but when you try to use it with {{pyapi|script|script.core|run_command}} or {{pyapi|script|script.core|start_command}} you get an error as lambda is a python reserved keyword. How to work around that?&lt;br /&gt;
&lt;br /&gt;
'''A:''' Append an underscore to the name, i.e.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('r.resamp.bspline', lambda_ = ...)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this follows Python [http://legacy.python.org/dev/peps/pep-0008/#descriptive-naming-styles PEP8] style guide. In GRASS GIS version 6, you have to prepend the underscore.&lt;br /&gt;
&lt;br /&gt;
=== Controlling the PNG display driver ===&lt;br /&gt;
&lt;br /&gt;
Code fragment to control the {{cmd|pngdriver}} in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
def main():&lt;br /&gt;
       os.environ['GRASS_PNGFILE'] = filename&lt;br /&gt;
       os.environ['GRASS_WIDTH'] = str(width)&lt;br /&gt;
       os.environ['GRASS_HEIGHT'] = str(height)&lt;br /&gt;
       grass.run_command('d.his', i='elevation_shade', h='elevation')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sophisticated cleanup procedure ===&lt;br /&gt;
&lt;br /&gt;
Scripts which create several temporary files need a more sophisticated cleanup procedure which deletes all the tmp maps which have been created. This procedure should also work if the script stops (e.g due to an error).&lt;br /&gt;
&lt;br /&gt;
Solution: Define a list of map names which starts out empty and has names appended to it as the names are generated. Code fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import atexit, sys&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       tmp_rast = []&lt;br /&gt;
&lt;br /&gt;
       def cleanup():&lt;br /&gt;
           for rast in tmp_rast:&lt;br /&gt;
               grass.run_command(&amp;quot;g.remove&amp;quot;,&lt;br /&gt;
                                 flags = 'f',&lt;br /&gt;
                                 type = 'raster',&lt;br /&gt;
                                 name = rast,&lt;br /&gt;
                                 quiet = True)&lt;br /&gt;
&lt;br /&gt;
       def main():&lt;br /&gt;
           ...&lt;br /&gt;
           while ...:&lt;br /&gt;
               next_rast = ...&lt;br /&gt;
               tmp_rast.append(next_rast)&lt;br /&gt;
               ...&lt;br /&gt;
&lt;br /&gt;
       if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
           options, flags = grass.parser()&lt;br /&gt;
           atexit.register(cleanup)&lt;br /&gt;
           sys.exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using temporary region for computations ===&lt;br /&gt;
&lt;br /&gt;
There are two possible ways how to define temporary region for raster-based computations within your scripts. First method uses environmental variable WIND_OVERRIDE, the second GRASS_REGION, see {{cmd|variables|desc=GRASS variables}} for more info. The key point is to recover the current region when the script is finished or terminated.&lt;br /&gt;
&lt;br /&gt;
* ''First method'' (WIND_OVERRIDE) is implemented as {{pyapi|script|script.core|use_temp_region}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
# store the current region settings and installs an atexit&lt;br /&gt;
# handler to recover the current region on script termination&lt;br /&gt;
grass.use_temp_region()&lt;br /&gt;
&lt;br /&gt;
grass.run_command('g.region', region='detail')&lt;br /&gt;
&lt;br /&gt;
grass.mapcalc('map = 1', overwrite=True)&lt;br /&gt;
&lt;br /&gt;
# after making operations using the temporary region,&lt;br /&gt;
# to unset the temporary WIND_OVERRIDE file and remove any &lt;br /&gt;
# region named by it, it is possible to use del_temp_region&lt;br /&gt;
grass.del_temp_region()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* ''Second method'' (GRASS_REGION) doesn't store current region settings to any temporary region, it just defines GRASS_REGION which forces GIS Library to use this settings for raster-based computations instead of the settings stored in WIND file (ie. current region). See {{pyapi|script|script.core|region_env}}.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
# copy environment and define GRASS_REGION environmental variable&lt;br /&gt;
# same as `g.region region=detail`&lt;br /&gt;
env = os.environ.copy()&lt;br /&gt;
env['GRASS_REGION'] = grass.region_env(region='detail')&lt;br /&gt;
 &lt;br /&gt;
grass.mapcalc('map = 1', overwrite=True, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using predefined constants ===&lt;br /&gt;
&lt;br /&gt;
Some constants are wrapped from C to Python through ctypes.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
from grass.lib.gis import GRASS_EPSILON&lt;br /&gt;
GRASS_EPSILON&lt;br /&gt;
1e-15&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting a list of wrapped C functions and constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import pprint&lt;br /&gt;
import grass.lib.gis as grass_gis&lt;br /&gt;
&lt;br /&gt;
# simple list&lt;br /&gt;
dir(grass_gis)&lt;br /&gt;
&lt;br /&gt;
# pretty printing&lt;br /&gt;
pprint.pprint(dir(grass_gis))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direct Access from wxGUI ==&lt;br /&gt;
&lt;br /&gt;
[[wxGUI]] Layer Manager in GRASS GIS comes with &amp;quot;Python shell&amp;quot; which enables users to type and execute python commands directly in wxGUI environment.&lt;br /&gt;
&lt;br /&gt;
[[Image:wxgui-pyshell.png|center|400px|Embedded interactive Python Shell in wxGUI Layer Manager]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[GRASS GIS Jupyter notebooks]]&lt;br /&gt;
* [[Working with GRASS without starting it explicitly‎]]&lt;br /&gt;
* Many more tutorials under [[:Category:Python]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_Python_Scripting_Library&amp;diff=26754</id>
		<title>GRASS Python Scripting Library</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_Python_Scripting_Library&amp;diff=26754"/>
		<updated>2022-11-23T20:38:59Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: /* Interfacing with NumPy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Python}}&lt;br /&gt;
Python API documentation:&lt;br /&gt;
&lt;br /&gt;
* [https://grass.osgeo.org/grass78/manuals/libpython/ Python API for GRASS GIS 7] and [http://grass.osgeo.org/grass78/manuals/libpython/script_intro.html Python Scripting Library]&lt;br /&gt;
* (old: [https://grass.osgeo.org/programming6/pythonlib.html for GRASS GIS 6]: core.py, db.py, raster.py, vector.py, setup.py, array.py task.py)&lt;br /&gt;
&lt;br /&gt;
The GRASS Python Scripting Library can be imported by statement&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The other packages such as PyGRASS can be imported in a similar way.&lt;br /&gt;
&lt;br /&gt;
The code in {{src|lib/python/|lib/python}} provides &amp;lt;tt&amp;gt;grass.script&amp;lt;/tt&amp;gt; and other packages in order to support GRASS scripts written in Python. The {{src|scripts}} directory of GRASS GIS 7 contains a series of examples actually provided to the end users (while the script in GRASS GIS 6 are shell scripts).&lt;br /&gt;
&lt;br /&gt;
For more general info, see also [[GRASS and Python]] and see also [[Converting Bash scripts to Python]] if you have some Bash scripts you want to rewrite to Python.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Calling a GRASS module in Python ===&lt;br /&gt;
&lt;br /&gt;
Imagine, you wanted to execute this command in Python:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  r.profile -g input=mymap output=newfile profile=12244.256,-295112.597,12128.012,-295293.77&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All arguments except the first (which is a flag) are keyword arguments, i.e. &amp;lt;tt&amp;gt;arg = val&amp;lt;/tt&amp;gt;. For the flag, use &amp;lt;tt&amp;gt;flags = 'g'&amp;lt;/tt&amp;gt; (note that &amp;quot;-g&amp;quot; would be the negative of a Python variable named &amp;quot;g&amp;quot;!). So:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('r.profile',&lt;br /&gt;
               input = input_map,&lt;br /&gt;
               output = output_file,&lt;br /&gt;
               profile = [12244.256,-295112.597,12128.012,-295293.77]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
or:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
               profile = [(12244.256,-295112.597),(12128.012,-295293.77)]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i.e. you need to provide the keyword, and the argument must be a valid Python expression. Function &amp;lt;code&amp;gt;run_command()&amp;lt;/code&amp;gt; etc accept lists and tuples.&lt;br /&gt;
&lt;br /&gt;
'''What is the proper way to include keyword-arguments tuples?'''&lt;br /&gt;
&lt;br /&gt;
For example, &amp;quot;g.list -f type=rast,vect&amp;quot; translates into:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;g.list&amp;quot;, flags=&amp;quot;f&amp;quot;, type=&amp;quot;rast,vect&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
or:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;g.list&amp;quot;, flags=&amp;quot;f&amp;quot;, type=[&amp;quot;rast&amp;quot;,&amp;quot;vect&amp;quot;])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The various *_command() functions accept arbitrary keyword arguments. Any keywords which don't have a specific meaning to either the *_command() function or the Popen constructor are treated as arguments to the GRASS module.&lt;br /&gt;
&lt;br /&gt;
'''What is the proper way to use multiple flags?'''&lt;br /&gt;
&lt;br /&gt;
How can I call a module with multiple flags set (e.g., -a and -b) in GRASS-Python?&lt;br /&gt;
&lt;br /&gt;
  flags = &amp;quot;ab&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;r.info&amp;quot;, flags=&amp;quot;eg&amp;quot;, map=[&amp;quot;elevation&amp;quot;])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Differences between ''run_command()'' and ''read_command()'':'''&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|run_command}} executes the command and waits for it to terminate; it doesn't redirect any of the standard streams.&lt;br /&gt;
* {{pyapi|script|script.core|read_command}} executes the command with stdout redirected to a pipe, and reads everything written to it. Once the command terminates, it returns the data written to stdout as a string.&lt;br /&gt;
&lt;br /&gt;
'''How to retrieve error messages from ''read_command()'':'''&lt;br /&gt;
&lt;br /&gt;
None of the existing *_command functions redirect stderr. You can do so with e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
def read2_command(*args, **kwargs):&lt;br /&gt;
   kwargs['stdout'] = grass.PIPE&lt;br /&gt;
   kwargs['stderr'] = grass.PIPE&lt;br /&gt;
   ps = grass.start_command(*args, **kwargs)&lt;br /&gt;
   return ps.communicate()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This behaves like &amp;lt;tt&amp;gt;read_command()&amp;lt;/tt&amp;gt; except that it returns a tuple of (stdout, stderr) rather than just stdout.&lt;br /&gt;
&lt;br /&gt;
== Uses for read, feed and pipe, start and exec commands ==&lt;br /&gt;
&lt;br /&gt;
All of the &amp;lt;tt&amp;gt;*_command&amp;lt;/tt&amp;gt; functions use {{pyapi|script|script.core|make_command}} to construct a command&lt;br /&gt;
line for a program which uses the {{cmd|g.parser|desc=GRASS parser}}. Most of them then pass&lt;br /&gt;
that command line to &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; via {{pyapi|script|script.core|start_command}}, except&lt;br /&gt;
for {{pyapi|script|script.core|exec_command}} which uses &amp;lt;tt&amp;gt;os.execvpe()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[To be precise, they use &amp;lt;tt&amp;gt;grass.Popen()&amp;lt;/tt&amp;gt;, which just calls&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; with 'shell=True' on Windows and 'shell=False'&lt;br /&gt;
otherwise. On Windows, you need to use 'shell=True' to be able to&lt;br /&gt;
execute scripts (including batch files); 'shell=False' only works with&lt;br /&gt;
binary executables.]&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.core|start_command}} separates the arguments into those which&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; understands and the rest. The rest are passed to&lt;br /&gt;
&amp;lt;tt&amp;gt;make_command()&amp;lt;/tt&amp;gt; to construct a command line which is passed as the&lt;br /&gt;
&amp;quot;args&amp;quot; parameter to &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, {{pyapi|script|script.core|start_command}} is a GRASS-oriented interface to&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt;. It should be suitable for any situation where you&lt;br /&gt;
would use &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; to execute a normal GRASS command (one&lt;br /&gt;
which uses the GRASS parser, which is almost all of them; the main&lt;br /&gt;
exception is {{cmd|r.mapcalc}} in 6.x).&lt;br /&gt;
&lt;br /&gt;
Most of the others are convenience wrappers around &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt;, for common use cases.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|run_command}} calls the wait() method on the process, so it doesn't return until the command has finished, and returns the command's exit code. Similar to &amp;lt;tt&amp;gt;system()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|pipe_command}} calls &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; with 'stdout=PIPE' and returns the process object. You can use the process' .stdout member to read the command's stdout. Similar to popen(..., &amp;quot;r&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|feed_command}} calls &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; with stdin=PIPE and returns the process object. You can use the process' .stdin member to write to the command's stdout. Similar to popen(..., &amp;quot;w&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|read_command}} calls &amp;lt;tt&amp;gt;pipe_command()&amp;lt;/tt&amp;gt;, reads the data from the command's stdout, and returns it as a string. Similar to `backticks` in the shell.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|write_command}} calls &amp;lt;tt&amp;gt;feed_command()&amp;lt;/tt&amp;gt;, sends the string specified by the &amp;quot;stdin&amp;quot; argument to the command's stdin, waits for the command to finish and returns its exit code. Similar to &amp;quot;echo ... | command&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|parse_command}} calls &amp;lt;tt&amp;gt;read_command()&amp;lt;/tt&amp;gt; and parses its output as key-value pairs. Useful for obtaining information from {{cmd|g.region}}, {{cmd|g.proj}}, {{cmd|r.info}}, etc.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|exec_command}} doesn't use &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; but &amp;lt;tt&amp;gt;os.execvpe()&amp;lt;/tt&amp;gt;. This causes the specified command to replace the current program (i.e. the Python script), so &amp;lt;tt&amp;gt;exec_command()&amp;lt;/tt&amp;gt; never returns. Similar to bash's &amp;quot;exec&amp;quot; command. This can be useful if the script is a &amp;quot;wrapper&amp;quot; around a single command, where you construct the command line and execute the command as the final step. Notes: exec_command() is rarely appropriate. You probably want run_command() instead. On Windows, exec_command() will probably require the &amp;quot;.exe&amp;quot; suffix.&lt;br /&gt;
&lt;br /&gt;
If you have any other questions, you might want to look at the code ({{src|lib/python/script/core.py}}). Most of these functions are only a few lines long.&lt;br /&gt;
&lt;br /&gt;
=== Hints for parse_command() ===&lt;br /&gt;
&lt;br /&gt;
To turn this command&lt;br /&gt;
        g.rename raster=old_name,new_name&lt;br /&gt;
into a g.parse_command() call, you need to consider that it is a function call with three arguments:&lt;br /&gt;
# &amp;quot;g.rename&amp;quot;&lt;br /&gt;
# raster=old_name&lt;br /&gt;
# new_name&lt;br /&gt;
&lt;br /&gt;
The second argument is a keyword argument, the first and third are&lt;br /&gt;
positional (non-keyword) arguments. Python doesn't allow positional&lt;br /&gt;
arguments to follow keyword arguments; positional arguments come&lt;br /&gt;
first, keyword arguments last.&lt;br /&gt;
&lt;br /&gt;
Given the context, it's safe to assume that you want to pass a pair of&lt;br /&gt;
map names as the value to the rast= option. This requires explicit&lt;br /&gt;
parentheses so that the comma is treated as forming a tuple rather&lt;br /&gt;
than as an argument separator:&lt;br /&gt;
&lt;br /&gt;
        g.parse_command(&amp;quot;g.rename&amp;quot;, raster=(old_name,new_name))&lt;br /&gt;
&lt;br /&gt;
The parentheses in a tuple value can only be omitted if it doesn't&lt;br /&gt;
result in the comma being ambiguous (as is the case in a function&lt;br /&gt;
call).&lt;br /&gt;
&lt;br /&gt;
== Interfacing ==&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy ===&lt;br /&gt;
&lt;br /&gt;
The {{pyapi|script|script.array|array}} module defines a &amp;lt;code&amp;gt;class array&amp;lt;/code&amp;gt; which is a subclass of [http://docs.scipy.org/doc/numpy/reference/generated/numpy.memmap.html numpy.memmap] that reads/writes the underlying file via {{cmd|r.out.bin}}/{{cmd|r.in.bin}}. Metadata can be read with {{pyapi|script|script.raster|raster_info}}:&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
import grass.script.array as garray&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    map = &amp;quot;elevation.dem&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # read map&lt;br /&gt;
    a = garray.array(map)&lt;br /&gt;
&lt;br /&gt;
    # get raster map info&lt;br /&gt;
    print(grass.raster_info(map)['datatype'])&lt;br /&gt;
    i = grass.raster_info(map)&lt;br /&gt;
    &lt;br /&gt;
    # get computational region info&lt;br /&gt;
    c = grass.region()&lt;br /&gt;
    print(&amp;quot;rows: %d&amp;quot; % c['rows'])&lt;br /&gt;
    print(&amp;quot;cols: %d&amp;quot; % c['cols'])&lt;br /&gt;
&lt;br /&gt;
    # new array for result&lt;br /&gt;
    b = garray.array()&lt;br /&gt;
    # calculate new map from input map and store as GRASS raster map&lt;br /&gt;
    b[...] = (a / 50).astype(int) * 50&lt;br /&gt;
    b.write(&amp;quot;elev.50m&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The size of the array is taken from the current region ([[computational region]]).&lt;br /&gt;
&lt;br /&gt;
The main drawback of using numpy is that you're limited by available&lt;br /&gt;
memory. Using a subclass of &amp;lt;code&amp;gt;numpy.memmap&amp;lt;/code&amp;gt; lets you use files which may&lt;br /&gt;
be much larger, but processing the entire array in one go is likely to&lt;br /&gt;
produce in-memory results of a similar size.&lt;br /&gt;
&lt;br /&gt;
'''NULL (no data) management:'''&lt;br /&gt;
&lt;br /&gt;
For integer maps, the NULL value is -2^31 = -2147483648. For floating-point maps, the NULL value is NaN. Note that the null= parameter for read() and write() specifies the value in the numpy array which is mapped to/from null values in the GRASS raster map.&lt;br /&gt;
&lt;br /&gt;
If you're using floating-point numpy arrays, then use (Note: This assumes that atof() and sscanf(&amp;quot;%lf&amp;quot;) recognise &amp;quot;nan&amp;quot;; this is the case on Linux, but doesn't appear to work on Windows)&lt;br /&gt;
 null=numpy.nan&lt;br /&gt;
&lt;br /&gt;
For integer arrays, using&lt;br /&gt;
 null=-2147483648&lt;br /&gt;
will ensure that valid values don't collide with NYLLs.&lt;br /&gt;
&lt;br /&gt;
'''MASK support:'''&lt;br /&gt;
&lt;br /&gt;
Reading and writing use r.out.bin and r.in.bin respectively. r.out.bin respects the MASK.&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy and SciPy  ===&lt;br /&gt;
&lt;br /&gt;
[http://docs.scipy.org/doc/scipy/reference/index.html SciPy] offers simple access to complex calculations. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from scipy import stats&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
import grass.script.array as garray&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    map = &amp;quot;elevation.dem&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    x = garray.array()&lt;br /&gt;
    x.read(map)&lt;br /&gt;
&lt;br /&gt;
    # Descriptive Statistics:&lt;br /&gt;
    print(&amp;quot;max, min, mean, var:&amp;quot;)&lt;br /&gt;
    print(x.max(), x.min(), x.mean(), x.var())&lt;br /&gt;
    print(&amp;quot;Skewness test: z-score and 2-sided p-value:&amp;quot;)&lt;br /&gt;
    print(stats.skewtest(stats.skew(x)))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy, SciPy and Matlab ===&lt;br /&gt;
&lt;br /&gt;
One may also use the SciPy - Matlab interface:&lt;br /&gt;
    &lt;br /&gt;
    r.out.mat input=elevation output=elev.mat&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    ### PY ###&lt;br /&gt;
    import scipy.io as sio&lt;br /&gt;
    # load data&lt;br /&gt;
    elev = sio.loadmat('elev.mat')&lt;br /&gt;
    # retrive the actual array. the data set contains also the spatial reference&lt;br /&gt;
    elev.get('map_data')&lt;br /&gt;
    data = elev.get('map_data')&lt;br /&gt;
    # a first simple plot&lt;br /&gt;
    import pylab&lt;br /&gt;
    pylab.plot(data)&lt;br /&gt;
    pylab.show()&lt;br /&gt;
    # the contour plot&lt;br /&gt;
    pylab.contour(data)&lt;br /&gt;
    # obviously data needs to ne reversed&lt;br /&gt;
    import numpy as np&lt;br /&gt;
    data_rev = data[::-1]&lt;br /&gt;
    pylab.contour(data_rev)&lt;br /&gt;
    # =&amp;gt; this is a quick plot. basemap mapping may provide a nicer map!&lt;br /&gt;
    #######&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Usage Examples ==&lt;br /&gt;
&lt;br /&gt;
=== Display example ===&lt;br /&gt;
Example of Python script, which is processed by {{cmd|g.parser}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
#&lt;br /&gt;
############################################################################&lt;br /&gt;
#&lt;br /&gt;
# MODULE:      d.shadedmap&lt;br /&gt;
# AUTHOR(S):   Unknown; updated to GRASS 5.7 by Michael Barton&lt;br /&gt;
#              Converted to Python by Glynn Clements&lt;br /&gt;
# PURPOSE:     Uses d.his to drape a color raster over a shaded relief map&lt;br /&gt;
# COPYRIGHT:   (C) 2004,2008,2009 by the GRASS Development Team&lt;br /&gt;
#&lt;br /&gt;
#              This program is free software under the GNU General Public&lt;br /&gt;
#              License (&amp;gt;=v2). Read the file COPYING that comes with GRASS&lt;br /&gt;
#              for details.&lt;br /&gt;
#&lt;br /&gt;
#############################################################################&lt;br /&gt;
&lt;br /&gt;
#%Module&lt;br /&gt;
#% description: Drapes a color raster over a shaded relief map using d.his&lt;br /&gt;
#% keyword: display&lt;br /&gt;
#% keyword: raster&lt;br /&gt;
#%End&lt;br /&gt;
#%option&lt;br /&gt;
#% key: reliefmap&lt;br /&gt;
#% type: string&lt;br /&gt;
#% gisprompt: old,cell,raster&lt;br /&gt;
#% description: Name of shaded relief or aspect map&lt;br /&gt;
#% required : yes&lt;br /&gt;
#%end&lt;br /&gt;
#%option&lt;br /&gt;
#% key: drapemap&lt;br /&gt;
#% type: string&lt;br /&gt;
#% gisprompt: old,cell,raster&lt;br /&gt;
#% description: Name of raster to drape over relief map&lt;br /&gt;
#% required : yes&lt;br /&gt;
#%end&lt;br /&gt;
#%option&lt;br /&gt;
#% key: brighten&lt;br /&gt;
#% type: integer&lt;br /&gt;
#% description: Percent to brighten&lt;br /&gt;
#% options: -99-99&lt;br /&gt;
#% answer: 0&lt;br /&gt;
#%end&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    drape_map = options['drapemap']&lt;br /&gt;
    relief_map = options['reliefmap']&lt;br /&gt;
    brighten = options['brighten']&lt;br /&gt;
    ret = grass.run_command(&amp;quot;d.his&amp;quot;, h_map = drape_map,  i_map = relief_map, brighten = brighten)&lt;br /&gt;
    sys.exit(ret)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    options, flags = grass.parser()&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parsing the options and flags  ===&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.core|parser}} is an interface to {{cmd|g.parser}}, and allows to parse the ''options'' and ''flags'' passed to your script on the command line. It is to be called at the top-level:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    options, flags = grass.parser()&lt;br /&gt;
    main()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Global variables &amp;quot;options&amp;quot; and &amp;quot;flags&amp;quot; are Python dictionaries containing the options/flags values, keyed by lower-case option/flag names. The values in &amp;quot;options&amp;quot; are strings, those in &amp;quot;flags&amp;quot; are Python booleans. All those variables have to be previously declared in the header of your script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; options, flags = grass.parser()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; options&lt;br /&gt;
{'input': 'my_map', 'output': 'map_out', 'option1': '21.472', 'option2': ''}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; flags&lt;br /&gt;
{'c': True, 'm': False}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Accessing the --quiet and --verbose flags:'''&lt;br /&gt;
&lt;br /&gt;
See {{pyapi|script|script.core|verbosity}} for the 5 verbosity levels:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
&lt;br /&gt;
# to hide non-error messages from subprocesses&lt;br /&gt;
if grass.verbosity() &amp;lt;= 2:&lt;br /&gt;
    outdev = open(os.devnull, 'w')&lt;br /&gt;
else:&lt;br /&gt;
    outdev = sys.stdout&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Passing several floats to a single option ===&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
python my.module.py input=input output=output myoption=0.1,0.2,0.5&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The values in the &amp;quot;options&amp;quot; dictionary returned from the parser()&lt;br /&gt;
function are always strings. You can parse the string with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        myoption = map(float, options['myoption'].split(','))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The option definition in the script should have:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        #% type: double&lt;br /&gt;
        #% multiple: yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This allows g.parser to validate the option syntax, so you can rely&lt;br /&gt;
upon the string being in the correct format. If the values have a&lt;br /&gt;
fixed range, you can use e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        #% options: 0.0-1.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to have the parser check that the values fall within the range.&lt;br /&gt;
&lt;br /&gt;
For more information on option definitions, see:&lt;br /&gt;
&lt;br /&gt;
https://grass.osgeo.org/programming7/gislib.html#Complete_Structure_Members_Table&lt;br /&gt;
&lt;br /&gt;
=== Example for embedding r.mapcalc (map algebra) ===&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.raster|mapcalc}} accepts a template string followed by keyword&lt;br /&gt;
arguments for the substitutions, e.g. (code snippets):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
grass.mapcalc(&amp;quot;${out} = ${rast1} + ${rast2}&amp;quot;,&lt;br /&gt;
              out = options['output'],&lt;br /&gt;
              rast1 = options['raster1'],&lt;br /&gt;
              rast2 = options['raster2'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Best practice'': first copy all of the options[] into separate variables at the beginning of main(), i.e.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def main():&lt;br /&gt;
    output = options['output']&lt;br /&gt;
    raster1 = options['raster1']&lt;br /&gt;
    raster2 = options['raster2']&lt;br /&gt;
 &lt;br /&gt;
    ...&lt;br /&gt;
 &lt;br /&gt;
    grass.mapcalc(&amp;quot;${out} = ${rast1} + ${rast2}&amp;quot;,&lt;br /&gt;
                  out = output,&lt;br /&gt;
                  rast1 = raster1,&lt;br /&gt;
                  rast2 = raster2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Performing multiple computations using &amp;lt;tt&amp;gt;grass.script.raster.mapcalc()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
expr = &amp;quot;;&amp;quot;.join([&lt;br /&gt;
        &amp;quot;$out.r = r#$first * $frac + (1.0 - $frac) * r#$second&amp;quot;,&lt;br /&gt;
        &amp;quot;$out.g = g#$first * $frac + (1.0 - $frac) * g#$second&amp;quot;,&lt;br /&gt;
        &amp;quot;$out.b = b#$first * $frac + (1.0 - $frac) * b#$second&amp;quot;])&lt;br /&gt;
grass.mapcalc(expr, out=out, first=first, second=second, frac=percent/100.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hint: multi-line strings can be separated by using a semicolon instead of a newline.&lt;br /&gt;
&lt;br /&gt;
=== Looping over file names stored in an ASCII file ===&lt;br /&gt;
&lt;br /&gt;
When looping over file names stored in an ASCII file and getting the error&lt;br /&gt;
&lt;br /&gt;
   WARNING: Illegal filename &amp;lt;map.f1jan.05216.something&lt;br /&gt;
          &amp;gt;. Character &amp;lt;&lt;br /&gt;
          &amp;gt; not allowed.&lt;br /&gt;
&lt;br /&gt;
then the line terminators may be the reason.&lt;br /&gt;
When you iterate over a file, the strings include the line terminators (e.g. '\n' or '\r\n'). Use e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    for line in gl:&lt;br /&gt;
        renamed = line.rstrip().replace('.','_')&lt;br /&gt;
        ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to remove any trailing whitespace (including newlines) from each line.&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing raster category labels ===&lt;br /&gt;
&lt;br /&gt;
How to obtain the text labels&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    # dump cats to file to avoid &amp;quot;too many argument&amp;quot; problem:&lt;br /&gt;
    p = grass.pipe_command('r.category', map = rastertmp, separator = ';', quiet = True)&lt;br /&gt;
    cats = []&lt;br /&gt;
    for line in p.stdout:&lt;br /&gt;
        cats.append(line.rstrip('\r\n').split(';')[0])&lt;br /&gt;
    p.wait()&lt;br /&gt;
&lt;br /&gt;
    number = len(cats)&lt;br /&gt;
    if number &amp;lt; 1:&lt;br /&gt;
        grass.fatal(_(&amp;quot;No categories found in raster map&amp;quot;))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing category numbers ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' How to obtain the number of cells of a certain category?&lt;br /&gt;
&lt;br /&gt;
'''A:''' It is recommended to use {{pyapi|script|script.core|pipe_command}} and parse the output, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       p = grass.pipe_command('r.stats',flags='c',input='map')&lt;br /&gt;
       result = {}&lt;br /&gt;
       for line in p.stdout:&lt;br /&gt;
           val,count = line.strip().split()&lt;br /&gt;
           result[int(val)] = int(count)&lt;br /&gt;
       p.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing the region output of a module ===&lt;br /&gt;
&lt;br /&gt;
Some of the GRASS GIS modules are delivering region information (e.g. {{cmd|r.in.xyz}} which scans a LiDAR file for the extent of the point cloud). The retrieved region settings (using '''-g''' flag for script style output) can be parsed in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
from grass.script import core as gcore&lt;br /&gt;
&lt;br /&gt;
from grass.pygrass.modules.shortcuts import general as g&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
&lt;br /&gt;
# scan a LiDAR xyz point file for its extent&lt;br /&gt;
compregion = gcore.parse_command(&amp;quot;r.in.xyz&amp;quot;, input=&amp;quot;tmp.xyz&amp;quot;, separator=&amp;quot;space&amp;quot;, flags=&amp;quot;sg&amp;quot;, output=&amp;quot;bbox&amp;quot;,&lt;br /&gt;
                                  parse=(gcore.parse_key_val, {'sep': '=', 'vsep': ' '}))&lt;br /&gt;
print(compregion)&lt;br /&gt;
# set computational region from LiDAR extent&lt;br /&gt;
# hint: we turn here the dictionary to a region by unpacking the dictionary:&lt;br /&gt;
g.region(res=&amp;quot;1&amp;quot;, flags=&amp;quot;p&amp;quot;, **compregion)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the two '''*''' above which unpack the dictionary (see also the related [https://docs.python.org/2/tutorial/controlflow.html#keyword-arguments Python manual] page).&lt;br /&gt;
&lt;br /&gt;
=== Example for getting the region's number of rows and columns ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' How to obtain the number of rows and columns of the current region?&lt;br /&gt;
&lt;br /&gt;
'''A:''' It is recommended to use the {{pyapi|script|script.core|region}} function which will create a dictionary with values for extents and resolution, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
#-*- coding:utf-8 -*-&lt;br /&gt;
#&lt;br /&gt;
############################################################################&lt;br /&gt;
#&lt;br /&gt;
# MODULE:       g.region.resolution&lt;br /&gt;
# AUTHOR(S):    based on a post at GRASS-USER mailing list [1]               &lt;br /&gt;
# PURPOSE:	Parses &amp;quot;g.region -g&amp;quot;, prints out number of rows, cols&lt;br /&gt;
# COPYLEFT:     ;-)&lt;br /&gt;
# COMMENT:      ...a lot of comments to be easy-to-read for/by beginners&lt;br /&gt;
#&lt;br /&gt;
#############################################################################&lt;br /&gt;
#&lt;br /&gt;
#%Module&lt;br /&gt;
#% description: Print number of rows, cols of current geographic region&lt;br /&gt;
#% keyword: region&lt;br /&gt;
#%end&lt;br /&gt;
&lt;br /&gt;
# importing required modules&lt;br /&gt;
import sys # the sys module [2]&lt;br /&gt;
from grass.script import core as grass # the core module [3]&lt;br /&gt;
&lt;br /&gt;
# information about imported modules can be obtained using the dir() function&lt;br /&gt;
# e.g.: dir(sys)&lt;br /&gt;
&lt;br /&gt;
# define the &amp;quot;main&amp;quot; function: get number of rows, cols of region&lt;br /&gt;
def main():&lt;br /&gt;
    &lt;br /&gt;
    # #######################################################################&lt;br /&gt;
    # the following commented code works but is kept only for learning purposes&lt;br /&gt;
     &lt;br /&gt;
    ## assigning the output of the command &amp;quot;g.region -g&amp;quot; in a string called &amp;quot;return_rows_x_cols&amp;quot;&lt;br /&gt;
    # return_rows_x_cols = grass.read_command('g.region', flags = 'g')&lt;br /&gt;
    &lt;br /&gt;
    ## parsing arguments of interest (rows, cols) in a dictionary named &amp;quot;rows_x_cols&amp;quot;&lt;br /&gt;
    # rows_x_cols = grass.parse_key_val(return_rows_x_cols)&lt;br /&gt;
    &lt;br /&gt;
    ## selectively print rows, cols from the dictionary &amp;quot;rows_x_cols&amp;quot;&lt;br /&gt;
    # print 'rows=%d \ncols=%d' % (int(rows_x_cols['rows']), int(rows_x_cols['cols']))&lt;br /&gt;
    &lt;br /&gt;
    # #######################################################################&lt;br /&gt;
    &lt;br /&gt;
    # faster/ easier way: use of the &amp;quot;grass.region()&amp;quot; function&lt;br /&gt;
    gregion = grass.region()&lt;br /&gt;
    rows = gregion['rows']&lt;br /&gt;
    cols = gregion['cols']&lt;br /&gt;
    &lt;br /&gt;
    # print rows, cols properly formatted &lt;br /&gt;
    print 'rows=%d \ncols=%d' % (rows, cols)&lt;br /&gt;
&lt;br /&gt;
    # average resolution (in case of non-square pixels)&lt;br /&gt;
    avg_res=(gregion['nsres'] + gregion['ewres']) / 2.0&lt;br /&gt;
&lt;br /&gt;
# this &amp;quot;if&amp;quot; condition instructs execution of code contained in this script, *only* if the script is being executed directly &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;: # this allows the script to be used as a module in other scripts or as a standalone script&lt;br /&gt;
    options, flags = grass.parser() #&lt;br /&gt;
    sys.exit(main()) #&lt;br /&gt;
&lt;br /&gt;
# Links&lt;br /&gt;
# [1] http://n2.nabble.com/Getting-rows-cols-of-a-region-in-a-script-tp2787474p2787509.html&lt;br /&gt;
# [2] http://www.python.org/doc/2.5.2/lib/module-sys.html&lt;br /&gt;
# [3] https://grass.osgeo.org/grass78/manuals/libpython&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Managing mapsets ===&lt;br /&gt;
&lt;br /&gt;
To check if a certain mapset exists in the active location, use {{pyapi|script|script.core|mapsets}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.mapsets(False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
... returns a list of mapsets in the current location.&lt;br /&gt;
&lt;br /&gt;
=== r.mapcalc example ===&lt;br /&gt;
&lt;br /&gt;
Example of Python script, which is processed by {{cmd|g.parser}}:&lt;br /&gt;
&lt;br /&gt;
The shell script line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  r.mapcalc &amp;quot;MASK = if(($cloudResampName &amp;lt; 0.01000),1,null())&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would be written like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       ...&lt;br /&gt;
&lt;br /&gt;
       grass.mapcalc(&amp;quot;MASK=if(($cloudResampName &amp;lt; 0.01000),1,null())&amp;quot;,&lt;br /&gt;
                     cloudResampName = cloudResampName)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first argument to the mapcalc function is a template (see the Python library documentation for [http://docs.python.org/library/string.html string.Template]). Any keyword arguments (other than &amp;lt;tt&amp;gt;quiet&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;verbose&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;overwrite&amp;lt;/tt&amp;gt;) specify substitutions.&lt;br /&gt;
&lt;br /&gt;
=== r.mapcalc example: defining a moving window ===&lt;br /&gt;
&lt;br /&gt;
Moving window of 4 cell in every 8 direction and do a boolean comparison. Boolean value (e.g. the result of a comparison) is an integer, with 1 for true, 0 for false.&lt;br /&gt;
Then do a r.mapcalc calculation with the moving window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
           &lt;br /&gt;
       # define a moving window of 4 cell in every 8 direction&lt;br /&gt;
       #&lt;br /&gt;
       # map[4,4]                                    map[4,0]                                    map[4,-4]		&lt;br /&gt;
       # 	    map[3,3]                         map[3,0]                         map[3,-3]			&lt;br /&gt;
       # 		       map[2,2]              map[2,0]              map[2,-2]				&lt;br /&gt;
       #                                  map[1,1]   map[1,0]   map[1,-1]	 				&lt;br /&gt;
       # map[0,4]   map[0,3]   map[0,2]   map[0,1]       x      map[0,-1]  map[0,-2]  map[0,-3]  map[0,-4]&lt;br /&gt;
       #                                  map[-1,1]  map[-1,0]  map[-1,-1]					&lt;br /&gt;
       #                       map[-2,2]             map[-2,0]             map[-2,-2]				&lt;br /&gt;
       #            map[-3,3]                        map[-3,0]                        map[-3,-3]			&lt;br /&gt;
       # map[-4,4]                                   map[-4,0]                                   map[-4,-4]&lt;br /&gt;
       &lt;br /&gt;
       # define the offet duplets&lt;br /&gt;
       &lt;br /&gt;
       offsets = [d&lt;br /&gt;
           for j in xrange(1,4+1)&lt;br /&gt;
           for i in [j,-j]&lt;br /&gt;
           for d in [(i,0),(0,i),(i,i),(i,-i)]]&lt;br /&gt;
       	&lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;offsets&lt;br /&gt;
       # [(1, 0), (0, 1), (1, 1), (1, -1), (-1, 0), (0, -1), (-1, -1), (-1, 1), (2, 0), (0, 2), (2, 2), (2, -2), (-2, 0), (0, -2), \&lt;br /&gt;
       # (-2, -2), (-2, 2), (3, 0), (0, 3), (3, 3), (3, -3), (-3, 0), (0, -3), (-3, -3), (-3, 3), (4, 0), (0, 4), (4, 4), (4, -4), \&lt;br /&gt;
       # (-4, 0), (0, -4), (-4, -4), (-4, 4)]&lt;br /&gt;
       &lt;br /&gt;
       # define the calculation term&lt;br /&gt;
       &lt;br /&gt;
       terms = [&amp;quot;(myelevnc[%d,%d] &amp;lt; myelevnc)&amp;quot; % d&lt;br /&gt;
                for d in offsets]&lt;br /&gt;
       &lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;terms&lt;br /&gt;
       # ['(myelevnc[1,0] &amp;lt; myelevnc)', '(myelevnc[0,1] &amp;lt; myelevnc)', '(myelevnc[1,1] &amp;lt; myelevnc)', '(myelevnc[1,-1] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-1,0] &amp;lt; myelevnc)', '(myelevnc[0,-1] &amp;lt; myelevnc)', '(myelevnc[-1,-1] &amp;lt; myelevnc)', '(myelevnc[-1,1] &amp;lt; myelevnc)',\&lt;br /&gt;
       # '(myelevnc[2,0] &amp;lt; myelevnc)', '(myelevnc[0,2] &amp;lt; myelevnc)', '(myelevnc[2,2] &amp;lt; myelevnc)', '(myelevnc[2,-2] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-2,0] &amp;lt; myelevnc)', '(myelevnc[0,-2] &amp;lt; myelevnc)', '(myelevnc[-2,-2] &amp;lt; myelevnc)', '(myelevnc[-2,2] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[3,0] &amp;lt; myelevnc)', '(myelevnc[0,3] &amp;lt; myelevnc)', '(myelevnc[3,3] &amp;lt; myelevnc)', '(myelevnc[3,-3] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-3,0] &amp;lt; myelevnc)', '(myelevnc[0,-3] &amp;lt; myelevnc)', '(myelevnc[-3,-3] &amp;lt; myelevnc)', '(myelevnc[-3,3] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[4,0] &amp;lt; myelevnc)', '(myelevnc[0,4] &amp;lt; myelevnc)', '(myelevnc[4,4] &amp;lt; myelevnc)', '(myelevnc[4,-4] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-4,0] &amp;lt; myelevnc)', '(myelevnc[0,-4] &amp;lt; myelevnc)', '(myelevnc[-4,-4] &amp;lt; myelevnc)', '(myelevnc[-4,4] &amp;lt; myelevnc)']&lt;br /&gt;
       &lt;br /&gt;
       # define the calculation expression&lt;br /&gt;
       &lt;br /&gt;
       expr = &amp;quot;elevation_percentile4 = (100.0 / 48.0) * (%s)&amp;quot; % &amp;quot; + &amp;quot;.join(terms)&lt;br /&gt;
       &lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;expr&lt;br /&gt;
       #  elevation_percentile4 = (100.0 / 48.0) * ((myelevnc[1,0] &amp;lt; myelevnc) + (myelevnc[0,1] &amp;lt; myelevnc) + (myelevnc[1,1] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[1,-1] &amp;lt; myelevnc) + (myelevnc[-1,0] &amp;lt; myelevnc) + (myelevnc[0,-1] &amp;lt; myelevnc) + (myelevnc[-1,-1] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-1,1] &amp;lt; myelevnc) + (myelevnc[2,0] &amp;lt; myelevnc) + (myelevnc[0,2] &amp;lt; myelevnc) + (myelevnc[2,2] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[2,-2] &amp;lt; myelevnc) + (myelevnc[-2,0] &amp;lt; myelevnc) + (myelevnc[0,-2] &amp;lt; myelevnc) + (myelevnc[-2,-2] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-2,2] &amp;lt; myelevnc) + (myelevnc[3,0] &amp;lt; myelevnc) + (myelevnc[0,3] &amp;lt; myelevnc) + (myelevnc[3,3] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[3,-3] &amp;lt; myelevnc) + (myelevnc[-3,0] &amp;lt; myelevnc) + (myelevnc[0,-3] &amp;lt; myelevnc) + (myelevnc[-3,-3] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-3,3] &amp;lt; myelevnc) + (myelevnc[4,0] &amp;lt; myelevnc) + (myelevnc[0,4] &amp;lt; myelevnc) + (myelevnc[4,4] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[4,-4] &amp;lt; myelevnc) + (myelevnc[-4,0] &amp;lt; myelevnc) + (myelevnc[0,-4] &amp;lt; myelevnc) + (myelevnc[-4,-4] &amp;lt; myelevnc)\&lt;br /&gt;
       #  + (myelevnc[-4,4] &amp;lt; myelevnc))&lt;br /&gt;
       &lt;br /&gt;
       # do the r.mapcalc calculation with the moving window&lt;br /&gt;
       &lt;br /&gt;
       grass.mapcalc( expr )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using output from GRASS modules in the script ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you need to use the output of a module for the next step. There are dedicated functions to obtain the result of, for example, a statistical analysis.&lt;br /&gt;
&lt;br /&gt;
Example: get the range of a raster map and use it in {{cmd|r.mapcalc}}. Here you can use {{pyapi|script|script.raster|raster_info}}, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       max = grass.raster_info(inmap)['max']&lt;br /&gt;
       grass.mapcalc(&amp;quot;$outmap = $inmap / $max&amp;quot;,&lt;br /&gt;
                     inmap = inmap, outmap = outmap, max = max)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using output from r.what ===&lt;br /&gt;
&lt;br /&gt;
''Q: How does one return attribute values from a call to the 'r.what' module running in a python script?''&lt;br /&gt;
&lt;br /&gt;
A: If you use &amp;lt;tt&amp;gt;grass.script.raster_what()&amp;lt;/tt&amp;gt;, it returns a list of dictionaries.&lt;br /&gt;
&lt;br /&gt;
PyGRASS which requires you to add &amp;lt;tt&amp;gt;stdout_=PIPE&amp;lt;/tt&amp;gt;, then you can get the output as a string from &amp;lt;tt&amp;gt;module.outputs.stdout&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Or using directly the C API through python with (North Carolina dataset example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.vector import VectorTopo&lt;br /&gt;
from grass.pygrass.raster import RasterRow&lt;br /&gt;
from grass.pygrass.gis.region import Region&lt;br /&gt;
&lt;br /&gt;
with RasterRow('elevation', mode='r') as rast:&lt;br /&gt;
    with VectorTopo('hospitals', mode='r') as hospitals:&lt;br /&gt;
        region = Region()&lt;br /&gt;
        for hosp in hospitals:&lt;br /&gt;
            value = rast.get_value(hosp, region)&lt;br /&gt;
            if value is not None:&lt;br /&gt;
                print(hosp.cat, value)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoiding a syntax error for r.rescale ===&lt;br /&gt;
&lt;br /&gt;
''Q: How to avoid a syntax error for r.rescale related to &amp;quot;from=&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
A: &amp;quot;from&amp;quot; is a reserved word, use from_ instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
grass.run_command('r.rescale', input=mis1, output=mis1_8bit, from_='0,2048', to='0,255')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interface to copying maps (g.copy) ===&lt;br /&gt;
&lt;br /&gt;
Copy a raster map (for vector, replace &amp;quot;rast&amp;quot; with &amp;quot;vect&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('g.copy', rast = (input, output))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To generalize it, &amp;quot;datatype&amp;quot; is the form of grass data to copy (eg, rast, vect, etc)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('g.copy', **{datatype: (input, output)})&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interface to listing maps (g.list) ===&lt;br /&gt;
&lt;br /&gt;
You may use the functions in [https://grass.osgeo.org/grass-stable/manuals/libpython/script.html?highlight=list_grouped#script.core.list_grouped script.core.list_grouped()]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# list all&lt;br /&gt;
list_grouped('raster')['PERMANENT']&lt;br /&gt;
[..., 'lakes', ..., 'slope', ...&lt;br /&gt;
&lt;br /&gt;
# list with pattern&lt;br /&gt;
list_grouped('vect', pattern='*roads*')['PERMANENT']&lt;br /&gt;
['railroads', 'roadsmajor']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For temporal data, see likewise [https://grass.osgeo.org/grass-stable/manuals/libpython/temporal.html?highlight=list_grouped#temporal.gui_support.tlist_grouped temporal.gui_support.tlist_grouped()]&lt;br /&gt;
&lt;br /&gt;
See also [[Python/pygrass#Sample_PyGRASS_scripts|Sample PyGRASS scripts]] for an alternative solution.&lt;br /&gt;
&lt;br /&gt;
=== i.group with patterns as name for input ===&lt;br /&gt;
&lt;br /&gt;
Imagery groups can be populated like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.gis import Mapset&lt;br /&gt;
&lt;br /&gt;
run_command(&amp;quot;i.group&amp;quot;, group=&amp;quot;mygroup&amp;quot;, input=mset.glist(&amp;quot;raster&amp;quot;, pattern=&amp;quot;mypattern_*&amp;quot;))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Percentage output for progress of computation ===&lt;br /&gt;
&lt;br /&gt;
A) Within a Python script, the {{pyapi|script|script.core|percent}} module method wraps the &amp;lt;tt&amp;gt;g.message -p&amp;lt;/tt&amp;gt; command.&lt;br /&gt;
&lt;br /&gt;
B) If you call a GRASS command within the Python code, you have to parse the output by setting &amp;lt;tt&amp;gt;GRASS_MESSAGE_FORMAT=gui&amp;lt;/tt&amp;gt; in the environment when running the command and read from the command's stderr; e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       env = os.environ.copy()&lt;br /&gt;
       env['GRASS_MESSAGE_FORMAT'] = 'gui'&lt;br /&gt;
       p = grass.start_command(..., stderr = grass.PIPE, env = env)&lt;br /&gt;
       # read from p.stderr&lt;br /&gt;
       p.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need to capture both stdout and stderr, you need to use threads, select, or non-blocking I/O to consume data from both streams as it is generated in order to avoid deadlock.&lt;br /&gt;
&lt;br /&gt;
ALTERNATIVE:&lt;br /&gt;
&lt;br /&gt;
Redirect both stdout and stderr to the same pipe (and hope that the normal output doesn't include anything which will be mistaken for progress/error/etc messages):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       p = grass.start_command(..., stdout = grass.PIPE, stderr = grass.STDOUT, env = env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NULL data management ===&lt;br /&gt;
&lt;br /&gt;
How to analyse if there are only NULL cells in a map:&lt;br /&gt;
&lt;br /&gt;
If a map contains only null cells, its minimum and maximum will be &amp;quot;NULL&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
       $ r.mapcalc 'foo = null()'&lt;br /&gt;
       $ r.info -r foo&lt;br /&gt;
       min=NULL&lt;br /&gt;
       max=NULL&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using the Python API, The 'min' and 'max' values in the result of the {{pyapi|script|script.raster|raster_info}} function will be &amp;lt;tt&amp;gt;None&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Counting cells ===&lt;br /&gt;
&lt;br /&gt;
Counting cells is far more expensive than simply determining whether&lt;br /&gt;
there are any non-null cells. Counting cells requires reading the&lt;br /&gt;
entire map, while the {{cmd|r.info}} approach only needs to read the metadata&lt;br /&gt;
files.&lt;br /&gt;
&lt;br /&gt;
If you do need to count cells, {{cmd|r.stats}} is likely to be more efficient than {{cmd|r.univar}}.&lt;br /&gt;
&lt;br /&gt;
A count loop:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       while grass.raster_info(inmap)['max'] is not None:&lt;br /&gt;
           ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Display: overlayed map display with labels ===&lt;br /&gt;
&lt;br /&gt;
Example: display a vector map and overlay its labels on top of the map.&lt;br /&gt;
&lt;br /&gt;
If the environment contains the setting GRASS_PNG_READ=TRUE, d.* commands should overlay their output on an existing image (otherwise the first command creates the file map.png but the second command overwrites the file with only the labels). So the following should work:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('d.vect', map='my_shape')&lt;br /&gt;
       env = os.environ.copy()&lt;br /&gt;
       env['GRASS_PNG_READ'] = 'TRUE'&lt;br /&gt;
       grass.run_command('d.labels', labels='my_shape_labels', env = env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Path to GISDBASE ===&lt;br /&gt;
In order to a avoid hardcoded paths to GRASS mapset files like the SQLite DB file, you can get the GISDBASE variable from the environment:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       import os.path&lt;br /&gt;
&lt;br /&gt;
       env = grass.gisenv()&lt;br /&gt;
&lt;br /&gt;
       gisdbase = env['GISDBASE']&lt;br /&gt;
       location = env['LOCATION_NAME']&lt;br /&gt;
       mapset = env['MAPSET']&lt;br /&gt;
&lt;br /&gt;
       path = os.path.join(gisdbase, location, mapset, 'sqlite.db')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parse the GRASS GIS version or revision or path to library ===&lt;br /&gt;
&lt;br /&gt;
In order to a avoid hardcoded versions or to scan the SVN revision of the GRASS GIS version used, you can query the {{cmd|helptext|startup script}}:&lt;br /&gt;
&lt;br /&gt;
'''Variant 1 (pure Python solution) - svn_revision:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
cmd = subprocess.Popen('grass78 --config svn_revision', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
revision = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(revision)&lt;br /&gt;
# the result is for example: '72327'.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Variant 2 (GRASS GIS-Python solution) - svn_revision:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
cmd = grass.Popen('grass78 --config svn_revision', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
revision = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(revision)&lt;br /&gt;
# the result is for example: '72327'.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Path to GRASS GIS library (GRASS GIS-Python solution):'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
cmd = grass.Popen('grass78 --config path', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
version = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(version)&lt;br /&gt;
# the result is for example: '/usr/local/grass-7.6.svn'&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a new location ===&lt;br /&gt;
&lt;br /&gt;
Use {{pyapi|script|script.core|create_location}} to create a new location.&lt;br /&gt;
&lt;br /&gt;
=== Use Python reserved keyword ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' ''r.resamp.bspline'' uses 'lambda' as a command line parameter name, but when you try to use it with {{pyapi|script|script.core|run_command}} or {{pyapi|script|script.core|start_command}} you get an error as lambda is a python reserved keyword. How to work around that?&lt;br /&gt;
&lt;br /&gt;
'''A:''' Append an underscore to the name, i.e.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('r.resamp.bspline', lambda_ = ...)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this follows Python [http://legacy.python.org/dev/peps/pep-0008/#descriptive-naming-styles PEP8] style guide. In GRASS GIS version 6, you have to prepend the underscore.&lt;br /&gt;
&lt;br /&gt;
=== Controlling the PNG display driver ===&lt;br /&gt;
&lt;br /&gt;
Code fragment to control the {{cmd|pngdriver}} in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
def main():&lt;br /&gt;
       os.environ['GRASS_PNGFILE'] = filename&lt;br /&gt;
       os.environ['GRASS_WIDTH'] = str(width)&lt;br /&gt;
       os.environ['GRASS_HEIGHT'] = str(height)&lt;br /&gt;
       grass.run_command('d.his', i='elevation_shade', h='elevation')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sophisticated cleanup procedure ===&lt;br /&gt;
&lt;br /&gt;
Scripts which create several temporary files need a more sophisticated cleanup procedure which deletes all the tmp maps which have been created. This procedure should also work if the script stops (e.g due to an error).&lt;br /&gt;
&lt;br /&gt;
Solution: Define a list of map names which starts out empty and has names appended to it as the names are generated. Code fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import atexit, sys&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       tmp_rast = []&lt;br /&gt;
&lt;br /&gt;
       def cleanup():&lt;br /&gt;
           for rast in tmp_rast:&lt;br /&gt;
               grass.run_command(&amp;quot;g.remove&amp;quot;,&lt;br /&gt;
                                 flags = 'f',&lt;br /&gt;
                                 type = 'raster',&lt;br /&gt;
                                 name = rast,&lt;br /&gt;
                                 quiet = True)&lt;br /&gt;
&lt;br /&gt;
       def main():&lt;br /&gt;
           ...&lt;br /&gt;
           while ...:&lt;br /&gt;
               next_rast = ...&lt;br /&gt;
               tmp_rast.append(next_rast)&lt;br /&gt;
               ...&lt;br /&gt;
&lt;br /&gt;
       if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
           options, flags = grass.parser()&lt;br /&gt;
           atexit.register(cleanup)&lt;br /&gt;
           sys.exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using temporary region for computations ===&lt;br /&gt;
&lt;br /&gt;
There are two possible ways how to define temporary region for raster-based computations within your scripts. First method uses environmental variable WIND_OVERRIDE, the second GRASS_REGION, see {{cmd|variables|desc=GRASS variables}} for more info. The key point is to recover the current region when the script is finished or terminated.&lt;br /&gt;
&lt;br /&gt;
* ''First method'' (WIND_OVERRIDE) is implemented as {{pyapi|script|script.core|use_temp_region}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
# store the current region settings and installs an atexit&lt;br /&gt;
# handler to recover the current region on script termination&lt;br /&gt;
grass.use_temp_region()&lt;br /&gt;
&lt;br /&gt;
grass.run_command('g.region', region='detail')&lt;br /&gt;
&lt;br /&gt;
grass.mapcalc('map = 1', overwrite=True)&lt;br /&gt;
&lt;br /&gt;
# after making operations using the temporary region,&lt;br /&gt;
# to unset the temporary WIND_OVERRIDE file and remove any &lt;br /&gt;
# region named by it, it is possible to use del_temp_region&lt;br /&gt;
grass.del_temp_region()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* ''Second method'' (GRASS_REGION) doesn't store current region settings to any temporary region, it just defines GRASS_REGION which forces GIS Library to use this settings for raster-based computations instead of the settings stored in WIND file (ie. current region). See {{pyapi|script|script.core|region_env}}.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
# copy environment and define GRASS_REGION environmental variable&lt;br /&gt;
# same as `g.region region=detail`&lt;br /&gt;
env = os.environ.copy()&lt;br /&gt;
env['GRASS_REGION'] = grass.region_env(region='detail')&lt;br /&gt;
 &lt;br /&gt;
grass.mapcalc('map = 1', overwrite=True, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using predefined constants ===&lt;br /&gt;
&lt;br /&gt;
Some constants are wrapped from C to Python through ctypes.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
from grass.lib.gis import GRASS_EPSILON&lt;br /&gt;
GRASS_EPSILON&lt;br /&gt;
1e-15&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting a list of wrapped C functions and constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import pprint&lt;br /&gt;
import grass.lib.gis as grass_gis&lt;br /&gt;
&lt;br /&gt;
# simple list&lt;br /&gt;
dir(grass_gis)&lt;br /&gt;
&lt;br /&gt;
# pretty printing&lt;br /&gt;
pprint.pprint(dir(grass_gis))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direct Access from wxGUI ==&lt;br /&gt;
&lt;br /&gt;
[[wxGUI]] Layer Manager in GRASS GIS comes with &amp;quot;Python shell&amp;quot; which enables users to type and execute python commands directly in wxGUI environment.&lt;br /&gt;
&lt;br /&gt;
[[Image:wxgui-pyshell.png|center|400px|Embedded interactive Python Shell in wxGUI Layer Manager]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[GRASS GIS Jupyter notebooks]]&lt;br /&gt;
* [[Working with GRASS without starting it explicitly‎]]&lt;br /&gt;
* Many more tutorials under [[:Category:Python]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=User:Baharmon&amp;diff=26753</id>
		<title>User:Baharmon</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=User:Baharmon&amp;diff=26753"/>
		<updated>2022-11-22T03:59:55Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: Blanked the page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_Python_Scripting_Library&amp;diff=26635</id>
		<title>GRASS Python Scripting Library</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_Python_Scripting_Library&amp;diff=26635"/>
		<updated>2022-03-31T01:09:31Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: Updated print statements to Python 3 in the Interfacing section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Python}}&lt;br /&gt;
Python API documentation:&lt;br /&gt;
&lt;br /&gt;
* [https://grass.osgeo.org/grass78/manuals/libpython/ Python API for GRASS GIS 7] and [http://grass.osgeo.org/grass78/manuals/libpython/script_intro.html Python Scripting Library]&lt;br /&gt;
* (old: [https://grass.osgeo.org/programming6/pythonlib.html for GRASS GIS 6]: core.py, db.py, raster.py, vector.py, setup.py, array.py task.py)&lt;br /&gt;
&lt;br /&gt;
The GRASS Python Scripting Library can be imported by statement&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The other packages such as PyGRASS can be imported in a similar way.&lt;br /&gt;
&lt;br /&gt;
The code in {{src|lib/python/|lib/python}} provides &amp;lt;tt&amp;gt;grass.script&amp;lt;/tt&amp;gt; and other packages in order to support GRASS scripts written in Python. The {{src|scripts}} directory of GRASS GIS 7 contains a series of examples actually provided to the end users (while the script in GRASS GIS 6 are shell scripts).&lt;br /&gt;
&lt;br /&gt;
For more general info, see also [[GRASS and Python]] and see also [[Converting Bash scripts to Python]] if you have some Bash scripts you want to rewrite to Python.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Calling a GRASS module in Python ===&lt;br /&gt;
&lt;br /&gt;
Imagine, you wanted to execute this command in Python:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  r.profile -g input=mymap output=newfile profile=12244.256,-295112.597,12128.012,-295293.77&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All arguments except the first (which is a flag) are keyword arguments, i.e. &amp;lt;tt&amp;gt;arg = val&amp;lt;/tt&amp;gt;. For the flag, use &amp;lt;tt&amp;gt;flags = 'g'&amp;lt;/tt&amp;gt; (note that &amp;quot;-g&amp;quot; would be the negative of a Python variable named &amp;quot;g&amp;quot;!). So:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('r.profile',&lt;br /&gt;
               input = input_map,&lt;br /&gt;
               output = output_file,&lt;br /&gt;
               profile = [12244.256,-295112.597,12128.012,-295293.77]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
or:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
               profile = [(12244.256,-295112.597),(12128.012,-295293.77)]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
i.e. you need to provide the keyword, and the argument must be a valid Python expression. Function &amp;lt;code&amp;gt;run_command()&amp;lt;/code&amp;gt; etc accept lists and tuples.&lt;br /&gt;
&lt;br /&gt;
'''What is the proper way to include keyword-arguments tuples?'''&lt;br /&gt;
&lt;br /&gt;
For example, &amp;quot;g.list -f type=rast,vect&amp;quot; translates into:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;g.list&amp;quot;, flags=&amp;quot;f&amp;quot;, type=&amp;quot;rast,vect&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
or:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;g.list&amp;quot;, flags=&amp;quot;f&amp;quot;, type=[&amp;quot;rast&amp;quot;,&amp;quot;vect&amp;quot;])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The various *_command() functions accept arbitrary keyword arguments. Any keywords which don't have a specific meaning to either the *_command() function or the Popen constructor are treated as arguments to the GRASS module.&lt;br /&gt;
&lt;br /&gt;
'''What is the proper way to use multiple flags?'''&lt;br /&gt;
&lt;br /&gt;
How can I call a module with multiple flags set (e.g., -a and -b) in GRASS-Python?&lt;br /&gt;
&lt;br /&gt;
  flags = &amp;quot;ab&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       grass.run_command(&amp;quot;r.info&amp;quot;, flags=&amp;quot;eg&amp;quot;, map=[&amp;quot;elevation&amp;quot;])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Differences between ''run_command()'' and ''read_command()'':'''&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|run_command}} executes the command and waits for it to terminate; it doesn't redirect any of the standard streams.&lt;br /&gt;
* {{pyapi|script|script.core|read_command}} executes the command with stdout redirected to a pipe, and reads everything written to it. Once the command terminates, it returns the data written to stdout as a string.&lt;br /&gt;
&lt;br /&gt;
'''How to retrieve error messages from ''read_command()'':'''&lt;br /&gt;
&lt;br /&gt;
None of the existing *_command functions redirect stderr. You can do so with e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
def read2_command(*args, **kwargs):&lt;br /&gt;
   kwargs['stdout'] = grass.PIPE&lt;br /&gt;
   kwargs['stderr'] = grass.PIPE&lt;br /&gt;
   ps = grass.start_command(*args, **kwargs)&lt;br /&gt;
   return ps.communicate()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This behaves like &amp;lt;tt&amp;gt;read_command()&amp;lt;/tt&amp;gt; except that it returns a tuple of (stdout, stderr) rather than just stdout.&lt;br /&gt;
&lt;br /&gt;
== Uses for read, feed and pipe, start and exec commands ==&lt;br /&gt;
&lt;br /&gt;
All of the &amp;lt;tt&amp;gt;*_command&amp;lt;/tt&amp;gt; functions use {{pyapi|script|script.core|make_command}} to construct a command&lt;br /&gt;
line for a program which uses the {{cmd|g.parser|desc=GRASS parser}}. Most of them then pass&lt;br /&gt;
that command line to &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; via {{pyapi|script|script.core|start_command}}, except&lt;br /&gt;
for {{pyapi|script|script.core|exec_command}} which uses &amp;lt;tt&amp;gt;os.execvpe()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[To be precise, they use &amp;lt;tt&amp;gt;grass.Popen()&amp;lt;/tt&amp;gt;, which just calls&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; with 'shell=True' on Windows and 'shell=False'&lt;br /&gt;
otherwise. On Windows, you need to use 'shell=True' to be able to&lt;br /&gt;
execute scripts (including batch files); 'shell=False' only works with&lt;br /&gt;
binary executables.]&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.core|start_command}} separates the arguments into those which&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; understands and the rest. The rest are passed to&lt;br /&gt;
&amp;lt;tt&amp;gt;make_command()&amp;lt;/tt&amp;gt; to construct a command line which is passed as the&lt;br /&gt;
&amp;quot;args&amp;quot; parameter to &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, {{pyapi|script|script.core|start_command}} is a GRASS-oriented interface to&lt;br /&gt;
&amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt;. It should be suitable for any situation where you&lt;br /&gt;
would use &amp;lt;tt&amp;gt;subprocess.Popen()&amp;lt;/tt&amp;gt; to execute a normal GRASS command (one&lt;br /&gt;
which uses the GRASS parser, which is almost all of them; the main&lt;br /&gt;
exception is {{cmd|r.mapcalc}} in 6.x).&lt;br /&gt;
&lt;br /&gt;
Most of the others are convenience wrappers around &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt;, for common use cases.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|run_command}} calls the wait() method on the process, so it doesn't return until the command has finished, and returns the command's exit code. Similar to &amp;lt;tt&amp;gt;system()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|pipe_command}} calls &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; with 'stdout=PIPE' and returns the process object. You can use the process' .stdout member to read the command's stdout. Similar to popen(..., &amp;quot;r&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|feed_command}} calls &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; with stdin=PIPE and returns the process object. You can use the process' .stdin member to write to the command's stdout. Similar to popen(..., &amp;quot;w&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|read_command}} calls &amp;lt;tt&amp;gt;pipe_command()&amp;lt;/tt&amp;gt;, reads the data from the command's stdout, and returns it as a string. Similar to `backticks` in the shell.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|write_command}} calls &amp;lt;tt&amp;gt;feed_command()&amp;lt;/tt&amp;gt;, sends the string specified by the &amp;quot;stdin&amp;quot; argument to the command's stdin, waits for the command to finish and returns its exit code. Similar to &amp;quot;echo ... | command&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|parse_command}} calls &amp;lt;tt&amp;gt;read_command()&amp;lt;/tt&amp;gt; and parses its output as key-value pairs. Useful for obtaining information from {{cmd|g.region}}, {{cmd|g.proj}}, {{cmd|r.info}}, etc.&lt;br /&gt;
&lt;br /&gt;
* {{pyapi|script|script.core|exec_command}} doesn't use &amp;lt;tt&amp;gt;start_command()&amp;lt;/tt&amp;gt; but &amp;lt;tt&amp;gt;os.execvpe()&amp;lt;/tt&amp;gt;. This causes the specified command to replace the current program (i.e. the Python script), so &amp;lt;tt&amp;gt;exec_command()&amp;lt;/tt&amp;gt; never returns. Similar to bash's &amp;quot;exec&amp;quot; command. This can be useful if the script is a &amp;quot;wrapper&amp;quot; around a single command, where you construct the command line and execute the command as the final step. Notes: exec_command() is rarely appropriate. You probably want run_command() instead. On Windows, exec_command() will probably require the &amp;quot;.exe&amp;quot; suffix.&lt;br /&gt;
&lt;br /&gt;
If you have any other questions, you might want to look at the code ({{src|lib/python/script/core.py}}). Most of these functions are only a few lines long.&lt;br /&gt;
&lt;br /&gt;
=== Hints for parse_command() ===&lt;br /&gt;
&lt;br /&gt;
To turn this command&lt;br /&gt;
        g.rename raster=old_name,new_name&lt;br /&gt;
into a g.parse_command() call, you need to consider that it is a function call with three arguments:&lt;br /&gt;
# &amp;quot;g.rename&amp;quot;&lt;br /&gt;
# raster=old_name&lt;br /&gt;
# new_name&lt;br /&gt;
&lt;br /&gt;
The second argument is a keyword argument, the first and third are&lt;br /&gt;
positional (non-keyword) arguments. Python doesn't allow positional&lt;br /&gt;
arguments to follow keyword arguments; positional arguments come&lt;br /&gt;
first, keyword arguments last.&lt;br /&gt;
&lt;br /&gt;
Given the context, it's safe to assume that you want to pass a pair of&lt;br /&gt;
map names as the value to the rast= option. This requires explicit&lt;br /&gt;
parentheses so that the comma is treated as forming a tuple rather&lt;br /&gt;
than as an argument separator:&lt;br /&gt;
&lt;br /&gt;
        g.parse_command(&amp;quot;g.rename&amp;quot;, raster=(old_name,new_name))&lt;br /&gt;
&lt;br /&gt;
The parentheses in a tuple value can only be omitted if it doesn't&lt;br /&gt;
result in the comma being ambiguous (as is the case in a function&lt;br /&gt;
call).&lt;br /&gt;
&lt;br /&gt;
== Interfacing ==&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy ===&lt;br /&gt;
&lt;br /&gt;
The {{pyapi|script|script.array|array}} module defines a &amp;lt;code&amp;gt;class array&amp;lt;/code&amp;gt; which is a subclass of [http://docs.scipy.org/doc/numpy/reference/generated/numpy.memmap.html numpy.memmap] with &amp;lt;code&amp;gt;.read()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;.write()&amp;lt;/code&amp;gt; methods to read/write the underlying file via {{cmd|r.out.bin}}/{{cmd|r.in.bin}}. Metadata can be read with {{pyapi|script|script.raster|raster_info}}:&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
import grass.script.array as garray&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    map = &amp;quot;elevation.dem&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # read map&lt;br /&gt;
    a = garray.array()&lt;br /&gt;
    a.read(map)&lt;br /&gt;
&lt;br /&gt;
    # get raster map info&lt;br /&gt;
    print(grass.raster_info(map)['datatype'])&lt;br /&gt;
    i = grass.raster_info(map)&lt;br /&gt;
    &lt;br /&gt;
    # get computational region info&lt;br /&gt;
    c = grass.region()&lt;br /&gt;
    print(&amp;quot;rows: %d&amp;quot; % c['rows'])&lt;br /&gt;
    print(&amp;quot;cols: %d&amp;quot; % c['cols'])&lt;br /&gt;
&lt;br /&gt;
    # new array for result&lt;br /&gt;
    b = garray.array()&lt;br /&gt;
    # calculate new map from input map and store as GRASS raster map&lt;br /&gt;
    b[...] = (a / 50).astype(int) * 50&lt;br /&gt;
    b.write(&amp;quot;elev.50m&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The size of the array is taken from the current region ([[computational region]]).&lt;br /&gt;
&lt;br /&gt;
The main drawback of using numpy is that you're limited by available&lt;br /&gt;
memory. Using a subclass of &amp;lt;code&amp;gt;numpy.memmap&amp;lt;/code&amp;gt; lets you use files which may&lt;br /&gt;
be much larger, but processing the entire array in one go is likely to&lt;br /&gt;
produce in-memory results of a similar size.&lt;br /&gt;
&lt;br /&gt;
'''NULL (no data) management:'''&lt;br /&gt;
&lt;br /&gt;
For integer maps, the NULL value is -2^31 = -2147483648. For floating-point maps, the NULL value is NaN. Note that the null= parameter for read() and write() specifies the value in the numpy array which is mapped to/from null values in the GRASS raster map.&lt;br /&gt;
&lt;br /&gt;
If you're using floating-point numpy arrays, then use (Note: This assumes that atof() and sscanf(&amp;quot;%lf&amp;quot;) recognise &amp;quot;nan&amp;quot;; this is the case on Linux, but doesn't appear to work on Windows)&lt;br /&gt;
 null=numpy.nan&lt;br /&gt;
&lt;br /&gt;
For integer arrays, using&lt;br /&gt;
 null=-2147483648&lt;br /&gt;
will ensure that valid values don't collide with NYLLs.&lt;br /&gt;
&lt;br /&gt;
'''MASK support:'''&lt;br /&gt;
&lt;br /&gt;
The function grass.script.array.read() and ...write() use r.out.bin and r.in.bin respectively. r.out.bin respects the MASK.&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy and SciPy  ===&lt;br /&gt;
&lt;br /&gt;
[http://docs.scipy.org/doc/scipy/reference/index.html SciPy] offers simple access to complex calculations. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from scipy import stats&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
import grass.script.array as garray&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    map = &amp;quot;elevation.dem&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    x = garray.array()&lt;br /&gt;
    x.read(map)&lt;br /&gt;
&lt;br /&gt;
    # Descriptive Statistics:&lt;br /&gt;
    print(&amp;quot;max, min, mean, var:&amp;quot;)&lt;br /&gt;
    print(x.max(), x.min(), x.mean(), x.var())&lt;br /&gt;
    print(&amp;quot;Skewness test: z-score and 2-sided p-value:&amp;quot;)&lt;br /&gt;
    print(stats.skewtest(stats.skew(x)))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interfacing with NumPy, SciPy and Matlab ===&lt;br /&gt;
&lt;br /&gt;
One may also use the SciPy - Matlab interface:&lt;br /&gt;
    &lt;br /&gt;
    r.out.mat input=elevation output=elev.mat&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    ### PY ###&lt;br /&gt;
    import scipy.io as sio&lt;br /&gt;
    # load data&lt;br /&gt;
    elev = sio.loadmat('elev.mat')&lt;br /&gt;
    # retrive the actual array. the data set contains also the spatial reference&lt;br /&gt;
    elev.get('map_data')&lt;br /&gt;
    data = elev.get('map_data')&lt;br /&gt;
    # a first simple plot&lt;br /&gt;
    import pylab&lt;br /&gt;
    pylab.plot(data)&lt;br /&gt;
    pylab.show()&lt;br /&gt;
    # the contour plot&lt;br /&gt;
    pylab.contour(data)&lt;br /&gt;
    # obviously data needs to ne reversed&lt;br /&gt;
    import numpy as np&lt;br /&gt;
    data_rev = data[::-1]&lt;br /&gt;
    pylab.contour(data_rev)&lt;br /&gt;
    # =&amp;gt; this is a quick plot. basemap mapping may provide a nicer map!&lt;br /&gt;
    #######&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Usage Examples ==&lt;br /&gt;
&lt;br /&gt;
=== Display example ===&lt;br /&gt;
Example of Python script, which is processed by {{cmd|g.parser}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
#&lt;br /&gt;
############################################################################&lt;br /&gt;
#&lt;br /&gt;
# MODULE:      d.shadedmap&lt;br /&gt;
# AUTHOR(S):   Unknown; updated to GRASS 5.7 by Michael Barton&lt;br /&gt;
#              Converted to Python by Glynn Clements&lt;br /&gt;
# PURPOSE:     Uses d.his to drape a color raster over a shaded relief map&lt;br /&gt;
# COPYRIGHT:   (C) 2004,2008,2009 by the GRASS Development Team&lt;br /&gt;
#&lt;br /&gt;
#              This program is free software under the GNU General Public&lt;br /&gt;
#              License (&amp;gt;=v2). Read the file COPYING that comes with GRASS&lt;br /&gt;
#              for details.&lt;br /&gt;
#&lt;br /&gt;
#############################################################################&lt;br /&gt;
&lt;br /&gt;
#%Module&lt;br /&gt;
#% description: Drapes a color raster over a shaded relief map using d.his&lt;br /&gt;
#% keyword: display&lt;br /&gt;
#% keyword: raster&lt;br /&gt;
#%End&lt;br /&gt;
#%option&lt;br /&gt;
#% key: reliefmap&lt;br /&gt;
#% type: string&lt;br /&gt;
#% gisprompt: old,cell,raster&lt;br /&gt;
#% description: Name of shaded relief or aspect map&lt;br /&gt;
#% required : yes&lt;br /&gt;
#%end&lt;br /&gt;
#%option&lt;br /&gt;
#% key: drapemap&lt;br /&gt;
#% type: string&lt;br /&gt;
#% gisprompt: old,cell,raster&lt;br /&gt;
#% description: Name of raster to drape over relief map&lt;br /&gt;
#% required : yes&lt;br /&gt;
#%end&lt;br /&gt;
#%option&lt;br /&gt;
#% key: brighten&lt;br /&gt;
#% type: integer&lt;br /&gt;
#% description: Percent to brighten&lt;br /&gt;
#% options: -99-99&lt;br /&gt;
#% answer: 0&lt;br /&gt;
#%end&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    drape_map = options['drapemap']&lt;br /&gt;
    relief_map = options['reliefmap']&lt;br /&gt;
    brighten = options['brighten']&lt;br /&gt;
    ret = grass.run_command(&amp;quot;d.his&amp;quot;, h_map = drape_map,  i_map = relief_map, brighten = brighten)&lt;br /&gt;
    sys.exit(ret)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    options, flags = grass.parser()&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parsing the options and flags  ===&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.core|parser}} is an interface to {{cmd|g.parser}}, and allows to parse the ''options'' and ''flags'' passed to your script on the command line. It is to be called at the top-level:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    options, flags = grass.parser()&lt;br /&gt;
    main()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Global variables &amp;quot;options&amp;quot; and &amp;quot;flags&amp;quot; are Python dictionaries containing the options/flags values, keyed by lower-case option/flag names. The values in &amp;quot;options&amp;quot; are strings, those in &amp;quot;flags&amp;quot; are Python booleans. All those variables have to be previously declared in the header of your script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; options, flags = grass.parser()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; options&lt;br /&gt;
{'input': 'my_map', 'output': 'map_out', 'option1': '21.472', 'option2': ''}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; flags&lt;br /&gt;
{'c': True, 'm': False}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Accessing the --quiet and --verbose flags:'''&lt;br /&gt;
&lt;br /&gt;
See {{pyapi|script|script.core|verbosity}} for the 5 verbosity levels:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
&lt;br /&gt;
# to hide non-error messages from subprocesses&lt;br /&gt;
if grass.verbosity() &amp;lt;= 2:&lt;br /&gt;
    outdev = open(os.devnull, 'w')&lt;br /&gt;
else:&lt;br /&gt;
    outdev = sys.stdout&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Passing several floats to a single option ===&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
python my.module.py input=input output=output myoption=0.1,0.2,0.5&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The values in the &amp;quot;options&amp;quot; dictionary returned from the parser()&lt;br /&gt;
function are always strings. You can parse the string with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        myoption = map(float, options['myoption'].split(','))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The option definition in the script should have:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        #% type: double&lt;br /&gt;
        #% multiple: yes&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This allows g.parser to validate the option syntax, so you can rely&lt;br /&gt;
upon the string being in the correct format. If the values have a&lt;br /&gt;
fixed range, you can use e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
        #% options: 0.0-1.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to have the parser check that the values fall within the range.&lt;br /&gt;
&lt;br /&gt;
For more information on option definitions, see:&lt;br /&gt;
&lt;br /&gt;
https://grass.osgeo.org/programming7/gislib.html#Complete_Structure_Members_Table&lt;br /&gt;
&lt;br /&gt;
=== Example for embedding r.mapcalc (map algebra) ===&lt;br /&gt;
&lt;br /&gt;
{{pyapi|script|script.raster|mapcalc}} accepts a template string followed by keyword&lt;br /&gt;
arguments for the substitutions, e.g. (code snippets):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
grass.mapcalc(&amp;quot;${out} = ${rast1} + ${rast2}&amp;quot;,&lt;br /&gt;
              out = options['output'],&lt;br /&gt;
              rast1 = options['raster1'],&lt;br /&gt;
              rast2 = options['raster2'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Best practice'': first copy all of the options[] into separate variables at the beginning of main(), i.e.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def main():&lt;br /&gt;
    output = options['output']&lt;br /&gt;
    raster1 = options['raster1']&lt;br /&gt;
    raster2 = options['raster2']&lt;br /&gt;
 &lt;br /&gt;
    ...&lt;br /&gt;
 &lt;br /&gt;
    grass.mapcalc(&amp;quot;${out} = ${rast1} + ${rast2}&amp;quot;,&lt;br /&gt;
                  out = output,&lt;br /&gt;
                  rast1 = raster1,&lt;br /&gt;
                  rast2 = raster2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Performing multiple computations using &amp;lt;tt&amp;gt;grass.script.raster.mapcalc()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
expr = &amp;quot;;&amp;quot;.join([&lt;br /&gt;
        &amp;quot;$out.r = r#$first * $frac + (1.0 - $frac) * r#$second&amp;quot;,&lt;br /&gt;
        &amp;quot;$out.g = g#$first * $frac + (1.0 - $frac) * g#$second&amp;quot;,&lt;br /&gt;
        &amp;quot;$out.b = b#$first * $frac + (1.0 - $frac) * b#$second&amp;quot;])&lt;br /&gt;
grass.mapcalc(expr, out=out, first=first, second=second, frac=percent/100.0)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hint: multi-line strings can be separated by using a semicolon instead of a newline.&lt;br /&gt;
&lt;br /&gt;
=== Looping over file names stored in an ASCII file ===&lt;br /&gt;
&lt;br /&gt;
When looping over file names stored in an ASCII file and getting the error&lt;br /&gt;
&lt;br /&gt;
   WARNING: Illegal filename &amp;lt;map.f1jan.05216.something&lt;br /&gt;
          &amp;gt;. Character &amp;lt;&lt;br /&gt;
          &amp;gt; not allowed.&lt;br /&gt;
&lt;br /&gt;
then the line terminators may be the reason.&lt;br /&gt;
When you iterate over a file, the strings include the line terminators (e.g. '\n' or '\r\n'). Use e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    for line in gl:&lt;br /&gt;
        renamed = line.rstrip().replace('.','_')&lt;br /&gt;
        ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to remove any trailing whitespace (including newlines) from each line.&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing raster category labels ===&lt;br /&gt;
&lt;br /&gt;
How to obtain the text labels&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
    # dump cats to file to avoid &amp;quot;too many argument&amp;quot; problem:&lt;br /&gt;
    p = grass.pipe_command('r.category', map = rastertmp, separator = ';', quiet = True)&lt;br /&gt;
    cats = []&lt;br /&gt;
    for line in p.stdout:&lt;br /&gt;
        cats.append(line.rstrip('\r\n').split(';')[0])&lt;br /&gt;
    p.wait()&lt;br /&gt;
&lt;br /&gt;
    number = len(cats)&lt;br /&gt;
    if number &amp;lt; 1:&lt;br /&gt;
        grass.fatal(_(&amp;quot;No categories found in raster map&amp;quot;))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing category numbers ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' How to obtain the number of cells of a certain category?&lt;br /&gt;
&lt;br /&gt;
'''A:''' It is recommended to use {{pyapi|script|script.core|pipe_command}} and parse the output, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       p = grass.pipe_command('r.stats',flags='c',input='map')&lt;br /&gt;
       result = {}&lt;br /&gt;
       for line in p.stdout:&lt;br /&gt;
           val,count = line.strip().split()&lt;br /&gt;
           result[int(val)] = int(count)&lt;br /&gt;
       p.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example for parsing the region output of a module ===&lt;br /&gt;
&lt;br /&gt;
Some of the GRASS GIS modules are delivering region information (e.g. {{cmd|r.in.xyz}} which scans a LiDAR file for the extent of the point cloud). The retrieved region settings (using '''-g''' flag for script style output) can be parsed in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
from grass.script import core as gcore&lt;br /&gt;
&lt;br /&gt;
from grass.pygrass.modules.shortcuts import general as g&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
&lt;br /&gt;
# scan a LiDAR xyz point file for its extent&lt;br /&gt;
compregion = gcore.parse_command(&amp;quot;r.in.xyz&amp;quot;, input=&amp;quot;tmp.xyz&amp;quot;, separator=&amp;quot;space&amp;quot;, flags=&amp;quot;sg&amp;quot;, output=&amp;quot;bbox&amp;quot;,&lt;br /&gt;
                                  parse=(gcore.parse_key_val, {'sep': '=', 'vsep': ' '}))&lt;br /&gt;
print(compregion)&lt;br /&gt;
# set computational region from LiDAR extent&lt;br /&gt;
# hint: we turn here the dictionary to a region by unpacking the dictionary:&lt;br /&gt;
g.region(res=&amp;quot;1&amp;quot;, flags=&amp;quot;p&amp;quot;, **compregion)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the two '''*''' above which unpack the dictionary (see also the related [https://docs.python.org/2/tutorial/controlflow.html#keyword-arguments Python manual] page).&lt;br /&gt;
&lt;br /&gt;
=== Example for getting the region's number of rows and columns ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' How to obtain the number of rows and columns of the current region?&lt;br /&gt;
&lt;br /&gt;
'''A:''' It is recommended to use the {{pyapi|script|script.core|region}} function which will create a dictionary with values for extents and resolution, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
#-*- coding:utf-8 -*-&lt;br /&gt;
#&lt;br /&gt;
############################################################################&lt;br /&gt;
#&lt;br /&gt;
# MODULE:       g.region.resolution&lt;br /&gt;
# AUTHOR(S):    based on a post at GRASS-USER mailing list [1]               &lt;br /&gt;
# PURPOSE:	Parses &amp;quot;g.region -g&amp;quot;, prints out number of rows, cols&lt;br /&gt;
# COPYLEFT:     ;-)&lt;br /&gt;
# COMMENT:      ...a lot of comments to be easy-to-read for/by beginners&lt;br /&gt;
#&lt;br /&gt;
#############################################################################&lt;br /&gt;
#&lt;br /&gt;
#%Module&lt;br /&gt;
#% description: Print number of rows, cols of current geographic region&lt;br /&gt;
#% keyword: region&lt;br /&gt;
#%end&lt;br /&gt;
&lt;br /&gt;
# importing required modules&lt;br /&gt;
import sys # the sys module [2]&lt;br /&gt;
from grass.script import core as grass # the core module [3]&lt;br /&gt;
&lt;br /&gt;
# information about imported modules can be obtained using the dir() function&lt;br /&gt;
# e.g.: dir(sys)&lt;br /&gt;
&lt;br /&gt;
# define the &amp;quot;main&amp;quot; function: get number of rows, cols of region&lt;br /&gt;
def main():&lt;br /&gt;
    &lt;br /&gt;
    # #######################################################################&lt;br /&gt;
    # the following commented code works but is kept only for learning purposes&lt;br /&gt;
     &lt;br /&gt;
    ## assigning the output of the command &amp;quot;g.region -g&amp;quot; in a string called &amp;quot;return_rows_x_cols&amp;quot;&lt;br /&gt;
    # return_rows_x_cols = grass.read_command('g.region', flags = 'g')&lt;br /&gt;
    &lt;br /&gt;
    ## parsing arguments of interest (rows, cols) in a dictionary named &amp;quot;rows_x_cols&amp;quot;&lt;br /&gt;
    # rows_x_cols = grass.parse_key_val(return_rows_x_cols)&lt;br /&gt;
    &lt;br /&gt;
    ## selectively print rows, cols from the dictionary &amp;quot;rows_x_cols&amp;quot;&lt;br /&gt;
    # print 'rows=%d \ncols=%d' % (int(rows_x_cols['rows']), int(rows_x_cols['cols']))&lt;br /&gt;
    &lt;br /&gt;
    # #######################################################################&lt;br /&gt;
    &lt;br /&gt;
    # faster/ easier way: use of the &amp;quot;grass.region()&amp;quot; function&lt;br /&gt;
    gregion = grass.region()&lt;br /&gt;
    rows = gregion['rows']&lt;br /&gt;
    cols = gregion['cols']&lt;br /&gt;
    &lt;br /&gt;
    # print rows, cols properly formatted &lt;br /&gt;
    print 'rows=%d \ncols=%d' % (rows, cols)&lt;br /&gt;
&lt;br /&gt;
    # average resolution (in case of non-square pixels)&lt;br /&gt;
    avg_res=(gregion['nsres'] + gregion['ewres']) / 2.0&lt;br /&gt;
&lt;br /&gt;
# this &amp;quot;if&amp;quot; condition instructs execution of code contained in this script, *only* if the script is being executed directly &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;: # this allows the script to be used as a module in other scripts or as a standalone script&lt;br /&gt;
    options, flags = grass.parser() #&lt;br /&gt;
    sys.exit(main()) #&lt;br /&gt;
&lt;br /&gt;
# Links&lt;br /&gt;
# [1] http://n2.nabble.com/Getting-rows-cols-of-a-region-in-a-script-tp2787474p2787509.html&lt;br /&gt;
# [2] http://www.python.org/doc/2.5.2/lib/module-sys.html&lt;br /&gt;
# [3] https://grass.osgeo.org/grass78/manuals/libpython&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Managing mapsets ===&lt;br /&gt;
&lt;br /&gt;
To check if a certain mapset exists in the active location, use {{pyapi|script|script.core|mapsets}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.mapsets(False)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
... returns a list of mapsets in the current location.&lt;br /&gt;
&lt;br /&gt;
=== r.mapcalc example ===&lt;br /&gt;
&lt;br /&gt;
Example of Python script, which is processed by {{cmd|g.parser}}:&lt;br /&gt;
&lt;br /&gt;
The shell script line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  r.mapcalc &amp;quot;MASK = if(($cloudResampName &amp;lt; 0.01000),1,null())&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would be written like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       ...&lt;br /&gt;
&lt;br /&gt;
       grass.mapcalc(&amp;quot;MASK=if(($cloudResampName &amp;lt; 0.01000),1,null())&amp;quot;,&lt;br /&gt;
                     cloudResampName = cloudResampName)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first argument to the mapcalc function is a template (see the Python library documentation for [http://docs.python.org/library/string.html string.Template]). Any keyword arguments (other than &amp;lt;tt&amp;gt;quiet&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;verbose&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;overwrite&amp;lt;/tt&amp;gt;) specify substitutions.&lt;br /&gt;
&lt;br /&gt;
=== r.mapcalc example: defining a moving window ===&lt;br /&gt;
&lt;br /&gt;
Moving window of 4 cell in every 8 direction and do a boolean comparison. Boolean value (e.g. the result of a comparison) is an integer, with 1 for true, 0 for false.&lt;br /&gt;
Then do a r.mapcalc calculation with the moving window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
           &lt;br /&gt;
       # define a moving window of 4 cell in every 8 direction&lt;br /&gt;
       #&lt;br /&gt;
       # map[4,4]                                    map[4,0]                                    map[4,-4]		&lt;br /&gt;
       # 	    map[3,3]                         map[3,0]                         map[3,-3]			&lt;br /&gt;
       # 		       map[2,2]              map[2,0]              map[2,-2]				&lt;br /&gt;
       #                                  map[1,1]   map[1,0]   map[1,-1]	 				&lt;br /&gt;
       # map[0,4]   map[0,3]   map[0,2]   map[0,1]       x      map[0,-1]  map[0,-2]  map[0,-3]  map[0,-4]&lt;br /&gt;
       #                                  map[-1,1]  map[-1,0]  map[-1,-1]					&lt;br /&gt;
       #                       map[-2,2]             map[-2,0]             map[-2,-2]				&lt;br /&gt;
       #            map[-3,3]                        map[-3,0]                        map[-3,-3]			&lt;br /&gt;
       # map[-4,4]                                   map[-4,0]                                   map[-4,-4]&lt;br /&gt;
       &lt;br /&gt;
       # define the offet duplets&lt;br /&gt;
       &lt;br /&gt;
       offsets = [d&lt;br /&gt;
           for j in xrange(1,4+1)&lt;br /&gt;
           for i in [j,-j]&lt;br /&gt;
           for d in [(i,0),(0,i),(i,i),(i,-i)]]&lt;br /&gt;
       	&lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;offsets&lt;br /&gt;
       # [(1, 0), (0, 1), (1, 1), (1, -1), (-1, 0), (0, -1), (-1, -1), (-1, 1), (2, 0), (0, 2), (2, 2), (2, -2), (-2, 0), (0, -2), \&lt;br /&gt;
       # (-2, -2), (-2, 2), (3, 0), (0, 3), (3, 3), (3, -3), (-3, 0), (0, -3), (-3, -3), (-3, 3), (4, 0), (0, 4), (4, 4), (4, -4), \&lt;br /&gt;
       # (-4, 0), (0, -4), (-4, -4), (-4, 4)]&lt;br /&gt;
       &lt;br /&gt;
       # define the calculation term&lt;br /&gt;
       &lt;br /&gt;
       terms = [&amp;quot;(myelevnc[%d,%d] &amp;lt; myelevnc)&amp;quot; % d&lt;br /&gt;
                for d in offsets]&lt;br /&gt;
       &lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;terms&lt;br /&gt;
       # ['(myelevnc[1,0] &amp;lt; myelevnc)', '(myelevnc[0,1] &amp;lt; myelevnc)', '(myelevnc[1,1] &amp;lt; myelevnc)', '(myelevnc[1,-1] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-1,0] &amp;lt; myelevnc)', '(myelevnc[0,-1] &amp;lt; myelevnc)', '(myelevnc[-1,-1] &amp;lt; myelevnc)', '(myelevnc[-1,1] &amp;lt; myelevnc)',\&lt;br /&gt;
       # '(myelevnc[2,0] &amp;lt; myelevnc)', '(myelevnc[0,2] &amp;lt; myelevnc)', '(myelevnc[2,2] &amp;lt; myelevnc)', '(myelevnc[2,-2] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-2,0] &amp;lt; myelevnc)', '(myelevnc[0,-2] &amp;lt; myelevnc)', '(myelevnc[-2,-2] &amp;lt; myelevnc)', '(myelevnc[-2,2] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[3,0] &amp;lt; myelevnc)', '(myelevnc[0,3] &amp;lt; myelevnc)', '(myelevnc[3,3] &amp;lt; myelevnc)', '(myelevnc[3,-3] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-3,0] &amp;lt; myelevnc)', '(myelevnc[0,-3] &amp;lt; myelevnc)', '(myelevnc[-3,-3] &amp;lt; myelevnc)', '(myelevnc[-3,3] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[4,0] &amp;lt; myelevnc)', '(myelevnc[0,4] &amp;lt; myelevnc)', '(myelevnc[4,4] &amp;lt; myelevnc)', '(myelevnc[4,-4] &amp;lt; myelevnc)', \&lt;br /&gt;
       # '(myelevnc[-4,0] &amp;lt; myelevnc)', '(myelevnc[0,-4] &amp;lt; myelevnc)', '(myelevnc[-4,-4] &amp;lt; myelevnc)', '(myelevnc[-4,4] &amp;lt; myelevnc)']&lt;br /&gt;
       &lt;br /&gt;
       # define the calculation expression&lt;br /&gt;
       &lt;br /&gt;
       expr = &amp;quot;elevation_percentile4 = (100.0 / 48.0) * (%s)&amp;quot; % &amp;quot; + &amp;quot;.join(terms)&lt;br /&gt;
       &lt;br /&gt;
       # &amp;gt;&amp;gt;&amp;gt;expr&lt;br /&gt;
       #  elevation_percentile4 = (100.0 / 48.0) * ((myelevnc[1,0] &amp;lt; myelevnc) + (myelevnc[0,1] &amp;lt; myelevnc) + (myelevnc[1,1] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[1,-1] &amp;lt; myelevnc) + (myelevnc[-1,0] &amp;lt; myelevnc) + (myelevnc[0,-1] &amp;lt; myelevnc) + (myelevnc[-1,-1] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-1,1] &amp;lt; myelevnc) + (myelevnc[2,0] &amp;lt; myelevnc) + (myelevnc[0,2] &amp;lt; myelevnc) + (myelevnc[2,2] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[2,-2] &amp;lt; myelevnc) + (myelevnc[-2,0] &amp;lt; myelevnc) + (myelevnc[0,-2] &amp;lt; myelevnc) + (myelevnc[-2,-2] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-2,2] &amp;lt; myelevnc) + (myelevnc[3,0] &amp;lt; myelevnc) + (myelevnc[0,3] &amp;lt; myelevnc) + (myelevnc[3,3] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[3,-3] &amp;lt; myelevnc) + (myelevnc[-3,0] &amp;lt; myelevnc) + (myelevnc[0,-3] &amp;lt; myelevnc) + (myelevnc[-3,-3] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[-3,3] &amp;lt; myelevnc) + (myelevnc[4,0] &amp;lt; myelevnc) + (myelevnc[0,4] &amp;lt; myelevnc) + (myelevnc[4,4] &amp;lt; myelevnc) + \&lt;br /&gt;
       # (myelevnc[4,-4] &amp;lt; myelevnc) + (myelevnc[-4,0] &amp;lt; myelevnc) + (myelevnc[0,-4] &amp;lt; myelevnc) + (myelevnc[-4,-4] &amp;lt; myelevnc)\&lt;br /&gt;
       #  + (myelevnc[-4,4] &amp;lt; myelevnc))&lt;br /&gt;
       &lt;br /&gt;
       # do the r.mapcalc calculation with the moving window&lt;br /&gt;
       &lt;br /&gt;
       grass.mapcalc( expr )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using output from GRASS modules in the script ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you need to use the output of a module for the next step. There are dedicated functions to obtain the result of, for example, a statistical analysis.&lt;br /&gt;
&lt;br /&gt;
Example: get the range of a raster map and use it in {{cmd|r.mapcalc}}. Here you can use {{pyapi|script|script.raster|raster_info}}, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       max = grass.raster_info(inmap)['max']&lt;br /&gt;
       grass.mapcalc(&amp;quot;$outmap = $inmap / $max&amp;quot;,&lt;br /&gt;
                     inmap = inmap, outmap = outmap, max = max)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using output from r.what ===&lt;br /&gt;
&lt;br /&gt;
''Q: How does one return attribute values from a call to the 'r.what' module running in a python script?''&lt;br /&gt;
&lt;br /&gt;
A: If you use &amp;lt;tt&amp;gt;grass.script.raster_what()&amp;lt;/tt&amp;gt;, it returns a list of dictionaries.&lt;br /&gt;
&lt;br /&gt;
PyGRASS which requires you to add &amp;lt;tt&amp;gt;stdout_=PIPE&amp;lt;/tt&amp;gt;, then you can get the output as a string from &amp;lt;tt&amp;gt;module.outputs.stdout&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Or using directly the C API through python with (North Carolina dataset example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.vector import VectorTopo&lt;br /&gt;
from grass.pygrass.raster import RasterRow&lt;br /&gt;
from grass.pygrass.gis.region import Region&lt;br /&gt;
&lt;br /&gt;
with RasterRow('elevation', mode='r') as rast:&lt;br /&gt;
    with VectorTopo('hospitals', mode='r') as hospitals:&lt;br /&gt;
        region = Region()&lt;br /&gt;
        for hosp in hospitals:&lt;br /&gt;
            value = rast.get_value(hosp, region)&lt;br /&gt;
            if value is not None:&lt;br /&gt;
                print(hosp.cat, value)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoiding a syntax error for r.rescale ===&lt;br /&gt;
&lt;br /&gt;
''Q: How to avoid a syntax error for r.rescale related to &amp;quot;from=&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
A: &amp;quot;from&amp;quot; is a reserved word, use from_ instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
grass.run_command('r.rescale', input=mis1, output=mis1_8bit, from_='0,2048', to='0,255')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interface to copying maps (g.copy) ===&lt;br /&gt;
&lt;br /&gt;
Copy a raster map (for vector, replace &amp;quot;rast&amp;quot; with &amp;quot;vect&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('g.copy', rast = (input, output))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To generalize it, &amp;quot;datatype&amp;quot; is the form of grass data to copy (eg, rast, vect, etc)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('g.copy', **{datatype: (input, output)})&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interface to listing maps (g.list) ===&lt;br /&gt;
&lt;br /&gt;
You may use the functions in [https://grass.osgeo.org/grass-stable/manuals/libpython/script.html?highlight=list_grouped#script.core.list_grouped script.core.list_grouped()]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# list all&lt;br /&gt;
list_grouped('raster')['PERMANENT']&lt;br /&gt;
[..., 'lakes', ..., 'slope', ...&lt;br /&gt;
&lt;br /&gt;
# list with pattern&lt;br /&gt;
list_grouped('vect', pattern='*roads*')['PERMANENT']&lt;br /&gt;
['railroads', 'roadsmajor']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For temporal data, see likewise [https://grass.osgeo.org/grass-stable/manuals/libpython/temporal.html?highlight=list_grouped#temporal.gui_support.tlist_grouped temporal.gui_support.tlist_grouped()]&lt;br /&gt;
&lt;br /&gt;
See also [[Python/pygrass#Sample_PyGRASS_scripts|Sample PyGRASS scripts]] for an alternative solution.&lt;br /&gt;
&lt;br /&gt;
=== i.group with patterns as name for input ===&lt;br /&gt;
&lt;br /&gt;
Imagery groups can be populated like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.gis import Mapset&lt;br /&gt;
&lt;br /&gt;
run_command(&amp;quot;i.group&amp;quot;, group=&amp;quot;mygroup&amp;quot;, input=mset.glist(&amp;quot;raster&amp;quot;, pattern=&amp;quot;mypattern_*&amp;quot;))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Percentage output for progress of computation ===&lt;br /&gt;
&lt;br /&gt;
A) Within a Python script, the {{pyapi|script|script.core|percent}} module method wraps the &amp;lt;tt&amp;gt;g.message -p&amp;lt;/tt&amp;gt; command.&lt;br /&gt;
&lt;br /&gt;
B) If you call a GRASS command within the Python code, you have to parse the output by setting &amp;lt;tt&amp;gt;GRASS_MESSAGE_FORMAT=gui&amp;lt;/tt&amp;gt; in the environment when running the command and read from the command's stderr; e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       env = os.environ.copy()&lt;br /&gt;
       env['GRASS_MESSAGE_FORMAT'] = 'gui'&lt;br /&gt;
       p = grass.start_command(..., stderr = grass.PIPE, env = env)&lt;br /&gt;
       # read from p.stderr&lt;br /&gt;
       p.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need to capture both stdout and stderr, you need to use threads, select, or non-blocking I/O to consume data from both streams as it is generated in order to avoid deadlock.&lt;br /&gt;
&lt;br /&gt;
ALTERNATIVE:&lt;br /&gt;
&lt;br /&gt;
Redirect both stdout and stderr to the same pipe (and hope that the normal output doesn't include anything which will be mistaken for progress/error/etc messages):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       p = grass.start_command(..., stdout = grass.PIPE, stderr = grass.STDOUT, env = env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NULL data management ===&lt;br /&gt;
&lt;br /&gt;
How to analyse if there are only NULL cells in a map:&lt;br /&gt;
&lt;br /&gt;
If a map contains only null cells, its minimum and maximum will be &amp;quot;NULL&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
       $ r.mapcalc 'foo = null()'&lt;br /&gt;
       $ r.info -r foo&lt;br /&gt;
       min=NULL&lt;br /&gt;
       max=NULL&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using the Python API, The 'min' and 'max' values in the result of the {{pyapi|script|script.raster|raster_info}} function will be &amp;lt;tt&amp;gt;None&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Counting cells ===&lt;br /&gt;
&lt;br /&gt;
Counting cells is far more expensive than simply determining whether&lt;br /&gt;
there are any non-null cells. Counting cells requires reading the&lt;br /&gt;
entire map, while the {{cmd|r.info}} approach only needs to read the metadata&lt;br /&gt;
files.&lt;br /&gt;
&lt;br /&gt;
If you do need to count cells, {{cmd|r.stats}} is likely to be more efficient than {{cmd|r.univar}}.&lt;br /&gt;
&lt;br /&gt;
A count loop:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       while grass.raster_info(inmap)['max'] is not None:&lt;br /&gt;
           ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Display: overlayed map display with labels ===&lt;br /&gt;
&lt;br /&gt;
Example: display a vector map and overlay its labels on top of the map.&lt;br /&gt;
&lt;br /&gt;
If the environment contains the setting GRASS_PNG_READ=TRUE, d.* commands should overlay their output on an existing image (otherwise the first command creates the file map.png but the second command overwrites the file with only the labels). So the following should work:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('d.vect', map='my_shape')&lt;br /&gt;
       env = os.environ.copy()&lt;br /&gt;
       env['GRASS_PNG_READ'] = 'TRUE'&lt;br /&gt;
       grass.run_command('d.labels', labels='my_shape_labels', env = env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Path to GISDBASE ===&lt;br /&gt;
In order to a avoid hardcoded paths to GRASS mapset files like the SQLite DB file, you can get the GISDBASE variable from the environment:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
       import os.path&lt;br /&gt;
&lt;br /&gt;
       env = grass.gisenv()&lt;br /&gt;
&lt;br /&gt;
       gisdbase = env['GISDBASE']&lt;br /&gt;
       location = env['LOCATION_NAME']&lt;br /&gt;
       mapset = env['MAPSET']&lt;br /&gt;
&lt;br /&gt;
       path = os.path.join(gisdbase, location, mapset, 'sqlite.db')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parse the GRASS GIS version or revision or path to library ===&lt;br /&gt;
&lt;br /&gt;
In order to a avoid hardcoded versions or to scan the SVN revision of the GRASS GIS version used, you can query the {{cmd|helptext|startup script}}:&lt;br /&gt;
&lt;br /&gt;
'''Variant 1 (pure Python solution) - svn_revision:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
cmd = subprocess.Popen('grass78 --config svn_revision', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
revision = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(revision)&lt;br /&gt;
# the result is for example: '72327'.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Variant 2 (GRASS GIS-Python solution) - svn_revision:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
cmd = grass.Popen('grass78 --config svn_revision', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
revision = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(revision)&lt;br /&gt;
# the result is for example: '72327'.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Path to GRASS GIS library (GRASS GIS-Python solution):'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import subprocess&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
cmd = grass.Popen('grass78 --config path', shell=True, stdout=subprocess.PIPE)&lt;br /&gt;
version = cmd.communicate()[0].rstrip()&lt;br /&gt;
print(version)&lt;br /&gt;
# the result is for example: '/usr/local/grass-7.6.svn'&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Creating a new location ===&lt;br /&gt;
&lt;br /&gt;
Use {{pyapi|script|script.core|create_location}} to create a new location.&lt;br /&gt;
&lt;br /&gt;
=== Use Python reserved keyword ===&lt;br /&gt;
&lt;br /&gt;
'''Q:''' ''r.resamp.bspline'' uses 'lambda' as a command line parameter name, but when you try to use it with {{pyapi|script|script.core|run_command}} or {{pyapi|script|script.core|start_command}} you get an error as lambda is a python reserved keyword. How to work around that?&lt;br /&gt;
&lt;br /&gt;
'''A:''' Append an underscore to the name, i.e.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       grass.run_command('r.resamp.bspline', lambda_ = ...)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this follows Python [http://legacy.python.org/dev/peps/pep-0008/#descriptive-naming-styles PEP8] style guide. In GRASS GIS version 6, you have to prepend the underscore.&lt;br /&gt;
&lt;br /&gt;
=== Controlling the PNG display driver ===&lt;br /&gt;
&lt;br /&gt;
Code fragment to control the {{cmd|pngdriver}} in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
from grass.script import core as grass&lt;br /&gt;
def main():&lt;br /&gt;
       os.environ['GRASS_PNGFILE'] = filename&lt;br /&gt;
       os.environ['GRASS_WIDTH'] = str(width)&lt;br /&gt;
       os.environ['GRASS_HEIGHT'] = str(height)&lt;br /&gt;
       grass.run_command('d.his', i='elevation_shade', h='elevation')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sophisticated cleanup procedure ===&lt;br /&gt;
&lt;br /&gt;
Scripts which create several temporary files need a more sophisticated cleanup procedure which deletes all the tmp maps which have been created. This procedure should also work if the script stops (e.g due to an error).&lt;br /&gt;
&lt;br /&gt;
Solution: Define a list of map names which starts out empty and has names appended to it as the names are generated. Code fragment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
       import atexit, sys&lt;br /&gt;
       import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
       tmp_rast = []&lt;br /&gt;
&lt;br /&gt;
       def cleanup():&lt;br /&gt;
           for rast in tmp_rast:&lt;br /&gt;
               grass.run_command(&amp;quot;g.remove&amp;quot;,&lt;br /&gt;
                                 flags = 'f',&lt;br /&gt;
                                 type = 'raster',&lt;br /&gt;
                                 name = rast,&lt;br /&gt;
                                 quiet = True)&lt;br /&gt;
&lt;br /&gt;
       def main():&lt;br /&gt;
           ...&lt;br /&gt;
           while ...:&lt;br /&gt;
               next_rast = ...&lt;br /&gt;
               tmp_rast.append(next_rast)&lt;br /&gt;
               ...&lt;br /&gt;
&lt;br /&gt;
       if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
           options, flags = grass.parser()&lt;br /&gt;
           atexit.register(cleanup)&lt;br /&gt;
           sys.exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using temporary region for computations ===&lt;br /&gt;
&lt;br /&gt;
There are two possible ways how to define temporary region for raster-based computations within your scripts. First method uses environmental variable WIND_OVERRIDE, the second GRASS_REGION, see {{cmd|variables|desc=GRASS variables}} for more info. The key point is to recover the current region when the script is finished or terminated.&lt;br /&gt;
&lt;br /&gt;
* ''First method'' (WIND_OVERRIDE) is implemented as {{pyapi|script|script.core|use_temp_region}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
# store the current region settings and installs an atexit&lt;br /&gt;
# handler to recover the current region on script termination&lt;br /&gt;
grass.use_temp_region()&lt;br /&gt;
&lt;br /&gt;
grass.run_command('g.region', region='detail')&lt;br /&gt;
&lt;br /&gt;
grass.mapcalc('map = 1', overwrite=True)&lt;br /&gt;
&lt;br /&gt;
# after making operations using the temporary region,&lt;br /&gt;
# to unset the temporary WIND_OVERRIDE file and remove any &lt;br /&gt;
# region named by it, it is possible to use del_temp_region&lt;br /&gt;
grass.del_temp_region()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* ''Second method'' (GRASS_REGION) doesn't store current region settings to any temporary region, it just defines GRASS_REGION which forces GIS Library to use this settings for raster-based computations instead of the settings stored in WIND file (ie. current region). See {{pyapi|script|script.core|region_env}}.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
import grass.script as grass&lt;br /&gt;
&lt;br /&gt;
# copy environment and define GRASS_REGION environmental variable&lt;br /&gt;
# same as `g.region region=detail`&lt;br /&gt;
env = os.environ.copy()&lt;br /&gt;
env['GRASS_REGION'] = grass.region_env(region='detail')&lt;br /&gt;
 &lt;br /&gt;
grass.mapcalc('map = 1', overwrite=True, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using predefined constants ===&lt;br /&gt;
&lt;br /&gt;
Some constants are wrapped from C to Python through ctypes.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
from grass.lib.gis import GRASS_EPSILON&lt;br /&gt;
GRASS_EPSILON&lt;br /&gt;
1e-15&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting a list of wrapped C functions and constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
import pprint&lt;br /&gt;
import grass.lib.gis as grass_gis&lt;br /&gt;
&lt;br /&gt;
# simple list&lt;br /&gt;
dir(grass_gis)&lt;br /&gt;
&lt;br /&gt;
# pretty printing&lt;br /&gt;
pprint.pprint(dir(grass_gis))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direct Access from wxGUI ==&lt;br /&gt;
&lt;br /&gt;
[[wxGUI]] Layer Manager in GRASS GIS comes with &amp;quot;Python shell&amp;quot; which enables users to type and execute python commands directly in wxGUI environment.&lt;br /&gt;
&lt;br /&gt;
[[Image:wxgui-pyshell.png|center|400px|Embedded interactive Python Shell in wxGUI Layer Manager]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[GRASS GIS Jupyter notebooks]]&lt;br /&gt;
* [[Working with GRASS without starting it explicitly‎]]&lt;br /&gt;
* Many more tutorials under [[:Category:Python]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_GIS_Raleigh_meetups_2016&amp;diff=23591</id>
		<title>GRASS GIS Raleigh meetups 2016</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_GIS_Raleigh_meetups_2016&amp;diff=23591"/>
		<updated>2016-09-23T15:23:29Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: Added participants&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A group of people contributing or interested in contributing to GRASS GIS met [[Christmas GRASS GIS potential contributors meeting in Raleigh|at the end of 2015 in Raleigh]], NC and decided to meet regularly in the following year. This is a page to organize meetings and to record what was done or discussed during the meetings.&lt;br /&gt;
&lt;br /&gt;
Contact person: [[User:Wenzeslaus|Vaclav Petras]] (Vashek, wenzeslaus gmail com)&lt;br /&gt;
&lt;br /&gt;
== October 1 ==&lt;br /&gt;
&lt;br /&gt;
* date: October 1 (Saturday)&lt;br /&gt;
* time: 1:30pm - 6:00pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see below)&lt;br /&gt;
* room: will be specified later, likely 4411 (note that the elevator from the 1st floor will take you just to the 2nd floor, use the yellow stairs for simplicity if you can)&lt;br /&gt;
* participants:&lt;br /&gt;
** Brendan Harmon&lt;br /&gt;
&lt;br /&gt;
== August 20 ==&lt;br /&gt;
&lt;br /&gt;
* date: August 20 (Saturday)&lt;br /&gt;
* time: 1:30pm - 6:00pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see below)&lt;br /&gt;
* room: 4502 The Fishbowl (note that the elevator from the 1st floor will take you just to the 2nd floor, use the yellow stairs for simplicity if you can)&lt;br /&gt;
* participants:&lt;br /&gt;
** ''add your name here''&lt;br /&gt;
* suggested topics (plus any you come up with):&lt;br /&gt;
** getting started with developing custom modules for GRASS GIS&lt;br /&gt;
** testing releases 7.2.0 (scheduled for September 1) and 7.0.5 (scheduled for August 21), see [https://trac.osgeo.org/grass/roadmap Roadmap at Trac]&lt;br /&gt;
** testing results of 4 GSoC projects (GSoC finishes August 15), see [https://trac.osgeo.org/grass/wiki/GSoC#a2016 GSoC 2016 Projects at Trac] (Cartography, New image segmentation algorithms, Web interface, Qt interface)&lt;br /&gt;
** fix tests, code or report an issue: [http://fatra.cnr.ncsu.edu/grassgistests/reports_for_date-2016-06-30-14-51/report_for_nc_basic_spm_grass7_nc/raster/r.mapcalc/test_row_above_below_bug/index.html r.mapcalc/test_row_above_below_bug], [http://fatra.cnr.ncsu.edu/grassgistests/reports_for_date-2016-05-24-07-00/report_for_nc_basic_spm_grass7_nc/raster/r.mapcalc/test_r3_mapcalc/index.html r.mapcalc/test_r3_mapcalc], [http://fatra.cnr.ncsu.edu/grassgistests/reports_for_date-2016-06-30-14-51/report_for_nc_basic_spm_grass7_nc/lib/python/pygrass/raster/test_history/index.html pygrass/raster/test_history], [http://fatra.cnr.ncsu.edu/grassgistests/reports_for_date-2016-06-30-14-51/report_for_nc_basic_spm_grass7_nc/lib/python/pygrass/vector/test_doctests/index.html pygrass/vector/test_doctests]&lt;br /&gt;
** ...&lt;br /&gt;
&lt;br /&gt;
== July 9 ==&lt;br /&gt;
&lt;br /&gt;
* date: July 9 (Saturday)&lt;br /&gt;
* time: 1:00pm - 6:00pm (feel free to come and leave anytime, library closes at 6:00pm)&lt;br /&gt;
* place: Hunt library (see below)&lt;br /&gt;
* room: 4502 The Fishbowl (note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras ([https://trac.osgeo.org/grass/timeline?from=July+9%2C+2016&amp;amp;daysback=1&amp;amp;authors=wenzeslaus&amp;amp;milestone=on&amp;amp;ticket=on&amp;amp;changeset=on&amp;amp;wiki=on&amp;amp;sfp_email=&amp;amp;sfph_mail=&amp;amp;update=Update changes at Trac])&lt;br /&gt;
** Anna Petrasova ([https://trac.osgeo.org/grass/timeline?from=July+9%2C+2016&amp;amp;daysback=1&amp;amp;authors=annakrat&amp;amp;milestone=on&amp;amp;ticket=on&amp;amp;changeset=on&amp;amp;wiki=on&amp;amp;sfp_email=&amp;amp;sfph_mail=&amp;amp;update=Update changes at Trac])&lt;br /&gt;
* topics:&lt;br /&gt;
** backports for 7.2 release&lt;br /&gt;
** cartography in GRASS GIS: testing&lt;br /&gt;
** new features and refactoring of overlays (legend, text, ...) in Map Display in wGUI&lt;br /&gt;
** unicode support for Python scripts&lt;br /&gt;
&lt;br /&gt;
== June 4 ==&lt;br /&gt;
&lt;br /&gt;
[[File:Hunt_library_spaces.jpg|thumbnail|right|Spaces in the Hunt library, almost empty during the summer and the Fishbowl empty after the meetup]]&lt;br /&gt;
&lt;br /&gt;
* date: June 4 (Saturday)&lt;br /&gt;
* time: 1:30pm - 6:00pm (feel free to come and leave anytime, library closes at 6:00pm)&lt;br /&gt;
* place: Hunt library (see below)&lt;br /&gt;
* room: 4502 The Fishbowl (note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
*** documentation improvements (content, style, consistency), color table modules in addons, .... ([https://trac.osgeo.org/grass/timeline?from=June+4%2C+2016&amp;amp;daysback=1&amp;amp;authors=wenzeslaus&amp;amp;milestone=on&amp;amp;ticket=on&amp;amp;changeset=on&amp;amp;wiki=on&amp;amp;sfp_email=&amp;amp;sfph_mail=&amp;amp;update=Update list of all changesets at Trac])&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
*** fixed {{trac|3010}} (PyGRASS vector attributes issue), ... ([https://trac.osgeo.org/grass/timeline?from=June+4%2C+2016&amp;amp;daysback=1&amp;amp;authors=annakrat&amp;amp;milestone=on&amp;amp;ticket=on&amp;amp;changeset=on&amp;amp;wiki=on&amp;amp;sfp_email=&amp;amp;sfph_mail=&amp;amp;update=Update list of all changesets at Trac])&lt;br /&gt;
** and 2 others&lt;br /&gt;
* other topics:&lt;br /&gt;
** contributing to GRASS GIS (commit rights, addons versus core)&lt;br /&gt;
** GRASS GIS compilation, updating older source code&lt;br /&gt;
** writing GRASS GIS module in C&lt;br /&gt;
&lt;br /&gt;
== May 6-7 ==&lt;br /&gt;
&lt;br /&gt;
[[File:Red_hat_raleigh.jpg|thumbnail|right|Red Hat Tower in Downtown Raleigh]]&lt;br /&gt;
&lt;br /&gt;
* For April and May we are meeting for two days at [https://2016.foss4g-na.org/ FOSS4G NA] Code Sprint and Unconference.&lt;br /&gt;
* date: May 6 (Friday) - May 7 (Saturday)&lt;br /&gt;
* time: starts at 10:00am on Friday, ends at 5:00pm on Saturday&lt;br /&gt;
* place: Red Hat Inc. - 100 East Davie Street, Raleigh, NC 27601&lt;br /&gt;
* participants:&lt;br /&gt;
** Brendan Harmon&lt;br /&gt;
** Vaclav Petras (Vashek)&lt;br /&gt;
*** Simple Python Editor, GSoC 2016, ... ([https://trac.osgeo.org/grass/timeline?from=May+8%2C+2016&amp;amp;daysback=3&amp;amp;authors=wenzeslaus&amp;amp;milestone=on&amp;amp;ticket=on&amp;amp;changeset=on&amp;amp;wiki=on&amp;amp;sfp_email=&amp;amp;sfph_mail=&amp;amp;update=Update list of all changes at Trac])&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
*** Data Catalog, GSoC 2016, d.polar, ... ([https://trac.osgeo.org/grass/timeline?from=May+8%2C+2016&amp;amp;daysback=3&amp;amp;authors=annakrat&amp;amp;milestone=on&amp;amp;ticket=on&amp;amp;changeset=on&amp;amp;wiki=on&amp;amp;sfp_email=&amp;amp;sfph_mail=&amp;amp;update=Update list of all changes at Trac])&lt;br /&gt;
** and 2 others&lt;br /&gt;
&lt;br /&gt;
== March 19 ==&lt;br /&gt;
&lt;br /&gt;
[[File:Grass_meetup_2016_03_19.jpg|thumbnail|right|In the Fishbowl on March 19]]&lt;br /&gt;
&lt;br /&gt;
* date: March 19 (Saturday)&lt;br /&gt;
* time: 1:30pm - 5:30pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see below)&lt;br /&gt;
* room: 4502 The Fishbowl (note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
** Brendan Harmon&lt;br /&gt;
** Doug Newcomb&lt;br /&gt;
** Makiko Shukunobe&lt;br /&gt;
** and 3 others&lt;br /&gt;
* topics:&lt;br /&gt;
** fix {{cmd|r.in.lidar}} and large rasters ({{rev|68083}})&lt;br /&gt;
** turning a Python script into a GRASS addon module&lt;br /&gt;
** planning next two meetings in relation to [https://2016.foss4g-na.org/ FOSS4G NA 2016] which is in Raleigh on May 2-5. and related possible code sprint (May 6-7)&lt;br /&gt;
** discussing needed graphic improvements of GRASS manual pages (index, graphical index, module man page)&lt;br /&gt;
** and several other things&lt;br /&gt;
** [[Introduction to GRASS GIS with terrain analysis examples]] wiki page&lt;br /&gt;
&lt;br /&gt;
== February 20 ==&lt;br /&gt;
&lt;br /&gt;
[[File:Grass gis raleigh meetup feb20 2016.png|thumbnail|right|In the Fishbowl on February 20]]&lt;br /&gt;
&lt;br /&gt;
* date: February 20 (Saturday)&lt;br /&gt;
* time: 1:30pm - 5:30pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see below)&lt;br /&gt;
* room: 4502 The Fishbowl (note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
** Makiko Shukunobe&lt;br /&gt;
** and 2 others&lt;br /&gt;
* topics: [https://grass.osgeo.org/grass64/manuals/addons/r.wind.sun.py.html r.wind.sun] port to version 7 as possible beginners topic ([https://trac.osgeo.org/grass/browser/grass-addons/grass6/raster/r.wind.sun/r.wind.sun.py?rev=67404 source code]), {{Cmd|v.overlay}} interface and possible v.clip, [https://trac.osgeo.org/grass/ticket/2663 submitting code through a ticket], GRASS GIS in QGIS, GRASS Story video ([http://dx.doi.org/10.5446/12963 HD], [https://www.youtube.com/watch?v=U3Hf0qI4JLc YouTube], [https://grass.osgeo.org/uploads/grass/history_docs/grass_movie_CERL_1987.mov MOV]), [https://2016.foss4g-na.org FOSS4G NA]&lt;br /&gt;
&lt;br /&gt;
== January 30 ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Room3208 jan30.jpg|thumb|400px|The room 3208 on January 30 with GRASS GIS logo on whiteboard to make the room easy to find]]&lt;br /&gt;
&lt;br /&gt;
* date: January 30 (moved from January 23 because of the weather)&lt;br /&gt;
* time: 1:00pm - 6:30pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see [[#Location|below]])&lt;br /&gt;
* room: 3208 (Large Group Study Room; close to the Game Lab and the wide yellow stairs; note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* food: your own supplies, [http://dining.ncsu.edu/locations/restaurants-cafes/hunt-library/ Common Grounds Café] at Hunt (closes at 5pm), [http://dining.ncsu.edu/locations/restaurants-cafes/on-the-oval/ On The Oval] (closes at 8pm)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
** Doug Newcomb&lt;br /&gt;
** Brendan Harmon&lt;br /&gt;
** Makiko Shukunobe&lt;br /&gt;
** and 2 others&lt;br /&gt;
* some of the topics:&lt;br /&gt;
** starting with Python API and running scripts in command line on Linux&lt;br /&gt;
** [[Compiling on MacOSX]] (ended up using brew because of problems with separately installed GDAL)&lt;br /&gt;
** debugging missing APPDATA on MS Windows, improved in {{rev|67709}}&lt;br /&gt;
** automated testing with Python and generating artificial data, e.g. &amp;lt;tt&amp;gt;r.mapcalc &amp;quot;plane = row()&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;r.mapcalc &amp;quot;surface = sin(2)&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
** discussing some GRASS concepts and more&lt;br /&gt;
&lt;br /&gt;
== Location ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Hunt 2015 2.jpg|thumb|400px|The Hunt Library]]&lt;br /&gt;
&lt;br /&gt;
* Raleigh, North Carolina, USA&lt;br /&gt;
* Centennial Campus of North Carolina State University&lt;br /&gt;
* [https://www.lib.ncsu.edu/huntlibrary James B. Hunt Jr. Library], 1070 Partners Way, Raleigh, NC 27606 ([http://www.openstreetmap.org/way/177166351 map])&lt;br /&gt;
** [https://www.lib.ncsu.edu/huntlibrary/explorespaces Floor plan].&lt;br /&gt;
*** The building is vertically split into two sections (library and another partially private space) and that the floor with the main desk and access to Oval is 2nd floor.&lt;br /&gt;
*** The elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can.&lt;br /&gt;
** Info about [https://www.lib.ncsu.edu/spaces/fishbowl Fishbowl]&lt;br /&gt;
** Info about [https://www.lib.ncsu.edu/spaces/group-study-rooms-large Group Study Rooms - Large]&lt;br /&gt;
* free parking on Saturdays: Oval West Parking Deck, Partners Way ([https://www.openstreetmap.org/way/164125158 map])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- https://www.lib.ncsu.edu/spaces/fishbowl --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Code Sprint]]&lt;br /&gt;
[[Category: 2016]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_GIS_ISPRS_Prague_meetup_2016&amp;diff=23233</id>
		<title>GRASS GIS ISPRS Prague meetup 2016</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_GIS_ISPRS_Prague_meetup_2016&amp;diff=23233"/>
		<updated>2016-07-08T17:23:12Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: /* People */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;People contributing or interested in contributing to GRASS GIS are welcome to meet during [http://www.isprs2016-prague.com/ ISPRS Congress] held in Prague 12-19th July 2016, Czech Republic.&lt;br /&gt;
&lt;br /&gt;
Details will be published later or during the congress.&lt;br /&gt;
&lt;br /&gt;
Contact person: [[User:Landa|Martin Landa]] (landa.martin gmail com) &lt;br /&gt;
&lt;br /&gt;
== Meetings ==&lt;br /&gt;
&lt;br /&gt;
We are doing more than one meeting to discuss everything from GSoC to general visions.&lt;br /&gt;
&lt;br /&gt;
=== Tuesday July 12 ===&lt;br /&gt;
&lt;br /&gt;
When: evening&lt;br /&gt;
&lt;br /&gt;
Where:&lt;br /&gt;
&lt;br /&gt;
Topics: &lt;br /&gt;
* GSoC&lt;br /&gt;
** vector legend implementation&lt;br /&gt;
&lt;br /&gt;
== People ==&lt;br /&gt;
&lt;br /&gt;
Are you going to ISPRS Congress, or you are just in Prague and willing to meet? Please put your name to the table bellow.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;   border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;4&amp;quot; rules=&amp;quot;all&amp;quot; style=&amp;quot;margin:1em 1em 1em 0; border:solid 1px #AAAAAA; border-collapse:collapse; background-color:#edf9c7; font-size:95%; empty-cells:show;&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! No&lt;br /&gt;
! Participant&lt;br /&gt;
! Arrival&lt;br /&gt;
! Departure&lt;br /&gt;
! Country&lt;br /&gt;
! ISPRS participation&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Martin Landa&lt;br /&gt;
| 12/7&lt;br /&gt;
| 19/7&lt;br /&gt;
| CZ&lt;br /&gt;
| yes&lt;br /&gt;
| Contact person&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Helena Mitasova&lt;br /&gt;
| 15/7&lt;br /&gt;
| 19/7&lt;br /&gt;
| US&lt;br /&gt;
| yes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Vaclav Petras&lt;br /&gt;
| 12/7&lt;br /&gt;
| 19/7&lt;br /&gt;
| US&lt;br /&gt;
| yes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Anna Petrasova&lt;br /&gt;
| 12/7&lt;br /&gt;
| 19/7&lt;br /&gt;
| US&lt;br /&gt;
| yes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Yasuharu Yamada&lt;br /&gt;
| 16/7&lt;br /&gt;
| 18/7&lt;br /&gt;
| JP&lt;br /&gt;
| yes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Adam Laza&lt;br /&gt;
| 12/7&lt;br /&gt;
| 19/7&lt;br /&gt;
| CZ&lt;br /&gt;
| no&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Ondrej Pesek&lt;br /&gt;
| 12/7&lt;br /&gt;
| 19/7&lt;br /&gt;
| CZ&lt;br /&gt;
| no&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Stepan Turek&lt;br /&gt;
| 12/7&lt;br /&gt;
| 15/7 or 19/7&lt;br /&gt;
| CZ&lt;br /&gt;
| no&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Zofie Cimburova&lt;br /&gt;
| 14/7&lt;br /&gt;
| 18/7 or 19/7&lt;br /&gt;
| CZ&lt;br /&gt;
| no&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Brendan Harmon&lt;br /&gt;
| 12/7&lt;br /&gt;
| 19/7&lt;br /&gt;
| US&lt;br /&gt;
| yes&lt;br /&gt;
|&lt;br /&gt;
|-}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Code Sprint]]&lt;br /&gt;
[[Category: 2016]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Using_GRASS_GIS_through_Python_and_tangible_interfaces_(workshop_at_FOSS4G_NA_2016)&amp;diff=23077</id>
		<title>Using GRASS GIS through Python and tangible interfaces (workshop at FOSS4G NA 2016)</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Using_GRASS_GIS_through_Python_and_tangible_interfaces_(workshop_at_FOSS4G_NA_2016)&amp;diff=23077"/>
		<updated>2016-05-02T13:09:06Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: /* Tangible Landscape */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:FOSS4G NA 2016.png|center|none]]&lt;br /&gt;
&lt;br /&gt;
This is material for FOSS4G NA 2016 workshop Using GRASS GIS through Python and tangible interfaces held in Raleigh May 2, 2016 - 09:00 to 13:00. &lt;br /&gt;
&lt;br /&gt;
Learn about scripting, graphical and tangible (!) interfaces for GRASS GIS, the powerful desktop GIS and geoprocessing backend. We will start with the Python interface and finish with [https://geospatial.ncsu.edu/osgeorel/tangible-landscape.html Tangible Landscape], a new tangible interface for GRASS GIS.&lt;br /&gt;
Python is the primary scripting language for GRASS GIS. We will demonstrate how to use Python to automate your geoprocessing workflows with GRASS GIS modules and develop custom algorithms using a Pythonic interface to access low level GRASS GIS library functions. We will also review several tips and tricks for parallelization.&lt;br /&gt;
[https://geospatial.ncsu.edu/osgeorel/tangible-landscape.html Tangible Landscape] is an example of how the GRASS GIS Python API can be used to build new, cutting edge tools and advanced applications. Tangible Landscape is a collaborative 3D sketching tool which couples a 3D scanner, a projector and a physical 3D model with GRASS GIS. The workshop will be a truly hands-on experience – you will play with Tangible Landscape, using your hands to shape a sand model and drive geospatial processes.&lt;br /&gt;
&lt;br /&gt;
'''Software''': [https://grass.osgeo.org GRASS GIS 7]&lt;br /&gt;
&lt;br /&gt;
'''Data''': Download [https://grass.osgeo.org/sampledata/north_carolina/nc_spm_08_grass7.zip complete North Carolina sample dataset].&lt;br /&gt;
&lt;br /&gt;
= GRASS GIS introduction =&lt;br /&gt;
You need to create a GRASS database we will use for the tutorial. Please download the [https://grass.osgeo.org/sampledata/north_carolina/nc_spm_08_grass7.zip dataset] for the workshop, noting where the files are located on your local directory. &lt;br /&gt;
Now, create (unless you already have it) a directory named &amp;lt;tt&amp;gt;grassdata&amp;lt;/tt&amp;gt; (GRASS database) in your home folder (or Documents), unzip the downloaded data into this directory. You should now have a Location &amp;lt;tt&amp;gt;nc_spm_08_grass7&amp;lt;/tt&amp;gt; in grassdata. Start GRASS GIS in Mapset &amp;lt;tt&amp;gt;user1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
GRASS GUI introduction&lt;br /&gt;
* [http://www4.ncsu.edu/~akratoc/GRASS_intro/ Basic screenshot tutorial] how to use GRASS GIS GUI &lt;br /&gt;
* [[Workshop_on_urban_growth_modeling_with_FUTURES#GRASS_GIS_introduction|Introduction from Workshop on urban growth modeling with FUTURES]]&lt;br /&gt;
&lt;br /&gt;
= GRASS GIS Python API =&lt;br /&gt;
&lt;br /&gt;
== Python Scripting library ==&lt;br /&gt;
[[File:GRASS GUI Python shell.png|thumbnail|right|Python shell in GRASS GIS GUI]]&lt;br /&gt;
The GRASS GIS 7 Python Scripting Library provides functions to call GRASS modules within scripts as subprocesses. The most often used functions include:&lt;br /&gt;
* '''[https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.run_command run_command]''': most often used with modules which output raster/vector data where text output is not expected&lt;br /&gt;
* '''[https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.read_command read_command]''': used when we are interested in text output&lt;br /&gt;
* '''[https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.parse_command parse_command]''': used with modules producing text output as key=value pair&lt;br /&gt;
* '''[https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.write_command write_command]''': for modules expecting text input from either standard input or file&lt;br /&gt;
&lt;br /&gt;
Besides, this library provides several wrapper functions for often called modules.&lt;br /&gt;
&lt;br /&gt;
=== Calling GRASS GIS modules ===&lt;br /&gt;
We will use GRASS GUI Python Shell to run the commands. For longer scripts, you can create a text file, save it into your current working directory and run it with &amp;lt;tt&amp;gt;python myscript.py&amp;lt;/tt&amp;gt; from the GUI command console or terminal.&lt;br /&gt;
&lt;br /&gt;
'''Tip''': When copying Python code snippets to GUI Python shell, right click at the position and select '''Paste Plus''' in the context menu. Otherwise multiline code snippets won't work.&lt;br /&gt;
&lt;br /&gt;
We start by importing GRASS GIS Python Scripting Library:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Before running any GRASS raster modules, you need to set the computational region using {{cmd|g.region}}. In this example, we set the computational extent and resolution to the raster layer &amp;lt;tt&amp;gt;elevation&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.run_command('g.region', raster='elevation')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The run_command() function is the most commonly used one. Here, we apply the focal operation average ({{cmd|r.neighbors}}) to smooth the elevation raster layer. Note that the syntax is similar to bash syntax, just the flags are specified in a parameter.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.run_command('r.neighbors', input='elevation', output='elev_smoothed', method='average', flags='c')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If we run the Python commands from GUI Python console, we can use &amp;lt;tt&amp;gt;AddLayer&amp;lt;/tt&amp;gt; to add the newly created layer:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
AddLayer('elev_smoothed')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Calling GRASS GIS modules with textual input or output ===&lt;br /&gt;
Textual output from modules can be captured using the read_command() function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.read_command('g.region', flags='p')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.read_command('r.univar', map='elev_smoothed', flags='g')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Certain modules can produce output in key-value format which is enabled by the '''-g''' flag. The parse_command() function automatically parses this output and returns a dictionary. In this example, we call {{cmd|g.proj}} to display the projection parameters of the actual location.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.parse_command('g.proj', flags='g')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For comparison, below is the same example, but using the read_command() function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.read_command('g.proj', flags='g')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Certain modules require the text input be in a file or provided as standard input. Using the write_command() function we can conveniently pass the string to the module. Here, we are creating a new vector with one point with {{cmd|v.in.ascii}}. Note that ''stdin'' parameter is not used as a module parameter, but its content is passed as standard input to the subprocess.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.write_command('v.in.ascii', input='-', stdin='%s|%s' % (635818, 221342), output='point')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If we run the Python commands from GUI Python console, we can use &amp;lt;tt&amp;gt;AddLayer&amp;lt;/tt&amp;gt; to add the newly created layer:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
AddLayer('point')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Convenient wrapper functions ===&lt;br /&gt;
Some modules have wrapper functions to simplify frequent tasks.&lt;br /&gt;
For example we can obtain the information about a raster layer with [https://grass.osgeo.org/grass70/manuals/libpython/script.html?highlight=mapcalc#script.raster.raster_info raster_info] which is a wrapper of {{cmd|r.info}},&lt;br /&gt;
or a vector layer with [https://grass.osgeo.org/grass70/manuals/libpython/script.html?script.vector.vector_info vector_info].&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.raster_info('elevation')&lt;br /&gt;
gscript.vector_info('point')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Another example is using [https://grass.osgeo.org/grass70/manuals/libpython/script.html?highlight=mapcalc#script.raster.mapcalc r.mapcalc wrapper] for raster algebra:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.mapcalc(&amp;quot;elev_strip = if(elevation &amp;gt; 100 &amp;amp;&amp;amp; elevation &amp;lt; 125, elevation, null())&amp;quot;)&lt;br /&gt;
gscript.read_command('r.univar', map='elev_strip', flags='g')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Function [https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.region region] is a convenient way to retrieve the current region settings (i.e., computational region). It returns a dictionary with values converted to appropriate types (floats and ints). &lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
region = gscript.region()&lt;br /&gt;
print region&lt;br /&gt;
# cell area in map units (in projected Locations)&lt;br /&gt;
region['nsres'] * region['ewres']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We can list data stored in a GRASS GIS location with {{cmd|g.list}} wrappers. With [https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.list_grouped list_grouped], the map layers are grouped by mapsets (in this example, raster layers):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.list_grouped(type=['raster'])&lt;br /&gt;
gscript.list_grouped(type=['raster'], pattern=&amp;quot;landuse*&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here is an example of a different {{cmd|g.list}} wrapper [https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.list_pairs list_pairs] which structures the output as list of pairs (name, mapset). We obtain current mapset with {{cmd|g.gisenv}} wrapper.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
current_mapset = gscript.gisenv()['MAPSET']&lt;br /&gt;
gscript.list_pairs('raster', mapset=current_mapset)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exercise ===&lt;br /&gt;
Export all raster layers from your mapset with a name prefix &amp;quot;elev_*&amp;quot; as GeoTiff (see {{cmd|r.out.gdal}}). Don't forget to set the current region ({{cmd|g.region}}) for each map in order to match the individual exported raster layer extents and resolutions since they may differ from each other.&lt;br /&gt;
&lt;br /&gt;
== PyGRASS ==&lt;br /&gt;
PyGRASS is a library originally developed during the Google Summer of Code 2012. PyGRASS library adds two main functionalities:&lt;br /&gt;
* Python interface through the ctypes binding of the C API of GRASS, to read and write natively GRASS GIS 7 data structures,&lt;br /&gt;
* GRASS GIS module interface using objects to check the parameters and execute the respective modules.&lt;br /&gt;
For further discussion about the implementation ideas and performance are presented in the article:&lt;br /&gt;
''[http://www.mdpi.com/2220-9964/2/1/201 Zambelli, P.; Gebbert, S.; Ciolli, M. Pygrass: An Object Oriented Python Application Programming Interface (API) for Geographic Resources Analysis Support System (GRASS) Geographic Information System (GIS). ISPRS Int. J. Geo-Inf. 2013, 2, 201-219.]''&lt;br /&gt;
&lt;br /&gt;
Standard scripting with GRASS modules in Python may sometime seem discouraging especially when you have to do conceptually simple things like: iterate over vector features or raster rows/columns.&lt;br /&gt;
Using the C API (most of GRASS GIS is written in C), all this is much more simple since you can directly work on GRASS GIS data and do just what you need to do.&lt;br /&gt;
However, you perhaps want to stick to Python. Here, the PyGRASS library introduced several objects that allow to interact directly with the data using the underlying C API of GRASS GIS.&lt;br /&gt;
&lt;br /&gt;
=== Working with vector data (see [https://grass.osgeo.org/grass70/manuals/libpython/pygrass_vector.html manual page]) ===&lt;br /&gt;
Create a new vector map. Import the necessary classes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.vector import VectorTopo&lt;br /&gt;
from grass.pygrass.vector.geometry import Point&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create an instance of a vector map:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
my_points = VectorTopo('my_points')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Open the map in write mode:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
my_points.open(mode='w')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create some vector geometry features, like two points:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
point1 = Point(635818.8, 221342.4)&lt;br /&gt;
point2 = Point(633627.7, 227050.2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the above two points to the new vector map:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
my_points.write(point1)&lt;br /&gt;
my_points.write(point2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally close the vector map:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
my_points.close()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Display the newly created vector (from GUI Python Shell):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
AddLayer('my_points')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now do the same thing using the context manager syntax and set also the attribute table:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Define the columns of the new vector map&lt;br /&gt;
cols = [(u'cat',       'INTEGER PRIMARY KEY'),&lt;br /&gt;
        (u'name',      'TEXT')]&lt;br /&gt;
&lt;br /&gt;
with VectorTopo('my_points', mode='w', tab_cols=cols, overwrite=True) as my_points:&lt;br /&gt;
    # save the point and the attribute&lt;br /&gt;
    my_points.write(point1, ('pub', ))&lt;br /&gt;
    my_points.write(point2, ('restaurant', ))&lt;br /&gt;
    # save the changes to the database&lt;br /&gt;
    my_points.table.conn.commit()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Note: we don't need to close the vector map because it is already closed by the context manager.&lt;br /&gt;
&lt;br /&gt;
Go to Layer Manager, right click on 'my_points' and ''Show attribute data''.&lt;br /&gt;
&lt;br /&gt;
Read an existing vector map:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
with VectorTopo('my_points', mode='r') as points:&lt;br /&gt;
    for point in points:&lt;br /&gt;
        print(point, point.attrs['name'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Working with raster data (see [https://grass.osgeo.org/grass70/manuals/libpython/pygrass_raster.html manual page]) ===&lt;br /&gt;
Create a new raster map and derive it's new values from &amp;lt;tt&amp;gt;elevation&amp;lt;/tt&amp;gt; raster. Import the necessary classes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.raster import RasterRow&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Open the existing raster in read mode and print first 5 values of the first row (indices from S to N):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
elev = RasterRow('elevation')&lt;br /&gt;
print elev.exist()&lt;br /&gt;
print elev.mapset&lt;br /&gt;
elev.open('r')&lt;br /&gt;
print elev[0][:5]&lt;br /&gt;
elev.close()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a new raster and write value 1 for cells with elevation &amp;lt; 120 and 0 otherwise:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
new = RasterRow('new')&lt;br /&gt;
new.open('w', overwrite=True)&lt;br /&gt;
for row in elev:&lt;br /&gt;
    new.put_row(row &amp;lt; 120)&lt;br /&gt;
new.close()&lt;br /&gt;
print new.exist()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Query old and new raster maps:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.vector import geometry&lt;br /&gt;
&lt;br /&gt;
new.open('r')&lt;br /&gt;
elev.open('r')&lt;br /&gt;
poi1 = geometry.Point(632942, 225757)&lt;br /&gt;
poi2 = geometry.Point(641780, 217455)&lt;br /&gt;
print elev.get_value(poi1), new.get_value(poi1)&lt;br /&gt;
print elev.get_value(poi2), new.get_value(poi2)&lt;br /&gt;
new.close()&lt;br /&gt;
elev.close()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more examples of using PyGRASS, please look at [https://github.com/wenzeslaus/python-grass-addon How to write a Python GRASS GIS 7 addon] workshop from FOSS4G-Europe 2015 and additional tutorials can be found [[Python/pygrass|on a PyGRASS wiki page]].&lt;br /&gt;
&lt;br /&gt;
= Parallelization examples =&lt;br /&gt;
A simple way to execute several modules in parallel (developed by Sören Gebbert) &lt;br /&gt;
is the [https://grass.osgeo.org/grass71/manuals/libpython/pygrass.modules.interface.html?highlight=parallelmodulequeue#pygrass.modules.interface.module.ParallelModuleQueue ParallelModuleQueue class]. The basic idea is to create a queue with all the modules that must be execute in parallel. The ParallelModuleQueue class is based on the Module class of the pygrass library, here is a small example for computation of solar irradiance during day:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from copy import deepcopy&lt;br /&gt;
from grass.pygrass.modules import Module, ParallelModuleQueue&lt;br /&gt;
&lt;br /&gt;
def main(elevation):&lt;br /&gt;
    # compute slope and aspect for r.sun&lt;br /&gt;
    Module('r.slope.aspect', elevation=elevation, aspect='aspect', slope='slope', overwrite=True)&lt;br /&gt;
    # initialize an empty queue and list&lt;br /&gt;
    queue = ParallelModuleQueue(nprocs=4)&lt;br /&gt;
    sun_name = 'sun_{}'&lt;br /&gt;
    # set computational region&lt;br /&gt;
    Module('g.region', raster=elevation)&lt;br /&gt;
    # initialize a module instance with shared inputs&lt;br /&gt;
    sun = Module('r.sun', elevation=elevation, slope='slope', aspect='aspect',&lt;br /&gt;
                 beam_rad='beam', step=1, day=123, run_=False, overwrite=True)&lt;br /&gt;
&lt;br /&gt;
    for t in range(6, 22):&lt;br /&gt;
        # create a copy of the module and set the remaining parameters&lt;br /&gt;
        print t&lt;br /&gt;
        m = deepcopy(sun)(beam_rad=sun_name.format(t), time=t)&lt;br /&gt;
        queue.put(m)&lt;br /&gt;
    queue.wait()&lt;br /&gt;
&lt;br /&gt;
    # set color table&lt;br /&gt;
    Module('r.colors', map=[sun_name.format(t) for t in range(6, 22)], color='grey', flags='e')&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    main(elevation)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This simple parallel implementation uses Python class Pool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from multiprocessing import Pool&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
&lt;br /&gt;
def rsun(params):&lt;br /&gt;
    gscript.run_command('r.sun', **params)&lt;br /&gt;
&lt;br /&gt;
def main(elevation):&lt;br /&gt;
    parameters = []&lt;br /&gt;
    sun_name = 'sun_{}'&lt;br /&gt;
    for t in range(6, 22):&lt;br /&gt;
        params = dict(elevation=elevation, slope='slope', aspect='aspect',&lt;br /&gt;
                      step=1, day=123, beam_rad=sun_name.format(t), time=t, overwrite=True)&lt;br /&gt;
        parameters.append(params)&lt;br /&gt;
    pool = Pool(4)&lt;br /&gt;
    p = pool.map_async(rsun, parameters)&lt;br /&gt;
    p.get()&lt;br /&gt;
        &lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    main(elevation)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example shows parallelization by splitting computation into tiles using [https://grass.osgeo.org/grass71/manuals/libpython/pygrass.modules.grid.html?highlight=gridmodule#pygrass.modules.grid.grid.GridModule GridModule]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
from grass.pygrass.modules.grid import GridModule&lt;br /&gt;
&lt;br /&gt;
def main(elevation):&lt;br /&gt;
    region = gscript.region()&lt;br /&gt;
    width = region['cols'] // 2 + 1&lt;br /&gt;
    height = region['rows'] // 2 + 1&lt;br /&gt;
&lt;br /&gt;
    grd = GridModule('r.slope.aspect', elevation=elevation, slope='slope',&lt;br /&gt;
                     debug=False, width=width, height=height,&lt;br /&gt;
                     overlap=10, processes=4, overwrite=True)&lt;br /&gt;
    grd.run()&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elevation'&lt;br /&gt;
    gscript.run_command('g.region', raster=elevation)&lt;br /&gt;
    main(elevation)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tangible Landscape =&lt;br /&gt;
[[File:Tangible landscape setup.jpg|400px|thumbnail|right|Tangible Landscape setup]]&lt;br /&gt;
&lt;br /&gt;
[http://baharmon.github.io/foss4g-na-2016-workshop/ A brief introduction to Tangible Landscape]&lt;br /&gt;
&lt;br /&gt;
Tangible Landscape is a collaborative modeling environment for analysis of terrain changes.&lt;br /&gt;
We couple a scanner, projector and a physical 3D model with GRASS GIS.&lt;br /&gt;
We can analyze the impact of terrain changes by capturing the changes on the model,&lt;br /&gt;
bringing them into the GIS, performing desired analysis or simulation and projecting the results back on the model in real-time.&lt;br /&gt;
Tangible Landscape, as an easy-to-use 3D sketching tool, enables rapid design and scenarios testing for people with different backgrounds&lt;br /&gt;
and computer knowledge, as well as support for decision-making process.&lt;br /&gt;
&lt;br /&gt;
Tangible Landscape has been used for a variety of applications supported by the extensive set of geospatial analysis and modeling tools available in GRASS GIS. We have explored how dune breaches affect the extent of coastal flooding, the impact of different building configurations on cast shadows and solar energy potential, and the effectiveness of various landscape designs for controlling runoff and erosion. Have a look at our [http://www.springer.com/us/book/9783319257730 book], [https://www.youtube.com/channel/UCc37pVh-WE46Xkqeq-KZQsA Youtube channel], and [https://plus.google.com/112857255995703553144/photos Google+ photos].&lt;br /&gt;
&lt;br /&gt;
The software is free and open source and you can [https://github.com/ncsu-osgeorel/grass-tangible-landscape download it] and use it in your own setup of Tangible Landscape.&lt;br /&gt;
&lt;br /&gt;
== Running examples ==&lt;br /&gt;
We will use a Titanpad to collect code samples from workshop participants and then run them in Tangible Landscape environment.&lt;br /&gt;
Whenever a scanning cycle is complete, a specified Python file is imported and all analyses in that file are computed.&lt;br /&gt;
Analyses are organized into functions with defined interface - each function has to start with &amp;lt;tt&amp;gt;run_&amp;lt;/tt&amp;gt;.&lt;br /&gt;
Input parameter &amp;lt;tt&amp;gt;scanned_elev&amp;lt;/tt&amp;gt; is the scanned raster (our DEM) and &amp;lt;tt&amp;gt;env&amp;lt;/tt&amp;gt; is the environment which needs to be passed to individual subprocesses to correctly handle the region of the analysis.&lt;br /&gt;
&lt;br /&gt;
Since participants will develop and test the analyses on their computers before we apply them to Tangible Landscape,&lt;br /&gt;
we add here the 'main' function with predefined parameters and participants will run it as a script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
&lt;br /&gt;
def run_slope(scanned_elev, env, **kwargs):&lt;br /&gt;
    # compute the analysis&lt;br /&gt;
    gscript.run_command('r.slope.aspect', ..., env=env) &lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    import os&lt;br /&gt;
    os.environ['GRASS_OVERWRITE'] = '1'&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    run_slope(scanned_elev=elevation, env=None)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scripts can be run from terminal or GUI command console:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python /path/to/my/script.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On Windows the path will look differently, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python C:\Users\yourname\path\to\my\script.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure you set computational region to match your DEM. We will use raster DEM &amp;lt;tt&amp;gt;elev_lid792_1m&amp;lt;/tt&amp;gt; from the sample dataset.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
g.region raster=elev_lid792_1m -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here follow some basic examples of geospatial analyses we can do with Tangible Landscape.&lt;br /&gt;
At the end of this section you can find additional tasks, some of them combining multiple analyses.&lt;br /&gt;
&lt;br /&gt;
== Modeling topography ==&lt;br /&gt;
=== Computing slope ===&lt;br /&gt;
[[File:tangible landscape slope.jpg|400px|thumbnail|right|Tangible Landscape: topographic slope]]&lt;br /&gt;
Basic example how we can compute topographic slope in degrees:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
&lt;br /&gt;
def run_slope(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', env=env)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    env = None&lt;br /&gt;
    run_slope(scanned_elev=elevation, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We can compute slope in percent and reclassify the values into discrete intervals:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_slope(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope',&lt;br /&gt;
                        format='percent', env=env)&lt;br /&gt;
    # reclassify using rules passed as a string to standard input&lt;br /&gt;
    # 0:2:1 means reclassify interval 0 to 2 percent of slope to category 1 &lt;br /&gt;
    rules = ['0:2:1', '2:5:2', '5:8:3', '8:15:4', '15:30:5', '30:*:6']&lt;br /&gt;
    gscript.write_command('r.recode', input='slope', output='slope_class',&lt;br /&gt;
                          rules='-', stdin='\n'.join(rules), env=env)&lt;br /&gt;
    # set new color table: green - yellow - red&lt;br /&gt;
    gscript.run_command('r.colors', map='slope_class', color='gyr', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Curvatures ===&lt;br /&gt;
Explore concavity/convexity of terrain with curvatures computed by {{cmd|r.param.scale}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_curvatures(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.param.scale', input=scanned_elev, output='profile_curv',&lt;br /&gt;
                        method='profc', size=11, env=env)&lt;br /&gt;
    gscript.run_command('r.param.scale', input=scanned_elev, output='tangential_curv',&lt;br /&gt;
                        method='crosc', size=11, env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map=['profile_curv', 'tangential_curv'], color='curvature', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Change window size and see how it influences the result.&lt;br /&gt;
&lt;br /&gt;
=== Landform identification ===&lt;br /&gt;
[[File:Tangible landscape geomorphons.jpg|400px|thumbnail|right|Tangible Landscape: Landforms computed with {{AddonCmd|r.geomorphon}}]]&lt;br /&gt;
There are 2 different methods for landform (ridge, valley, ...) identification in GRASS GIS.&lt;br /&gt;
First one is implemented in {{cmd|r.param.scale}} and uses curvatures.&lt;br /&gt;
The second is implemented in an addon {{AddonCmd|r.geomorphon}} which uses multiscale line-of-sight approach. This addon can be installed&lt;br /&gt;
from GUI command line:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
g.extension r.geomorphon&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
or follow &lt;br /&gt;
[https://grasswiki.osgeo.org/wiki/Introduction_to_GRASS_GIS_with_terrain_analysis_examples#Step_5:_Adding_the_r.geomorphon_Addon this tutorial].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_curvatures(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.param.scale', input=scanned_elev, output='landforms1',&lt;br /&gt;
                        method='feature', size=10, env=env)&lt;br /&gt;
    gscript.run_command('r.geomorphon', dem=scanned_elev, forms='landforms2',&lt;br /&gt;
                        search=16, skip=6, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Building model based on difference raster ===&lt;br /&gt;
When building a model by hands based on a defined DEM, we can compute the difference between the scanned model and the original DEM.&lt;br /&gt;
By color-coding the difference, we can see where to add sand or remove it. &lt;br /&gt;
&lt;br /&gt;
If you are running this outside of Tangible Landscape, you can generate a raster (our hypothetical pile of sand)&lt;br /&gt;
and compute the difference. In this example we also vertically rescale and translate the scanned raster to match&lt;br /&gt;
the original DEM using {{cmd|r.regression.line}}.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
&lt;br /&gt;
def run_difference(real_elev, scanned_elev, env, **kwargs):&lt;br /&gt;
    regression_params = gscript.parse_command('r.regression.line', flags='g', mapx=scanned_elev, mapy=real_elev, env=env)&lt;br /&gt;
    gscript.mapcalc('{regression} = {a} + {b} * {before}'.format(a=regression_params['a'], b=regression_params['b'],&lt;br /&gt;
                                                                 before=scanned_elev, regression='regression'), env=env)&lt;br /&gt;
    gscript.mapcalc('{difference} = {regression} - {after}'.format(regression='regression', after=real_elev, difference='diff'), env=env)&lt;br /&gt;
    gscript.write_command('r.colors', map='diff', rules='-', stdin=&amp;quot;-100 black\n-20 red\n0 white\n20 blue\n100 black&amp;quot;, env=env)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    sand_pile = 'sand_pile'&lt;br /&gt;
    env = None&lt;br /&gt;
    gscript.run_command('r.surf.fractal', output=sand_pile)&lt;br /&gt;
    run_difference(real_elev=elevation, scanned_elev=sand_pile, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hydrology ==&lt;br /&gt;
=== Flooding with {{cmd|r.lake}} ===&lt;br /&gt;
[[File:tangible landscape rlake.jpg|200px|thumbnail|right|Example of simple flooding simulation with Tangible Landscape and {{cmd|r.lake}} module.]]&lt;br /&gt;
&lt;br /&gt;
Module {{cmd|r.lake}} fills a lake to a target water level from a given start point or seed raster.&lt;br /&gt;
The resulting raster map contains cells with values representing lake depth and NULL for all other cells beyond the lake.&lt;br /&gt;
&lt;br /&gt;
Example showing basic usage:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_lake(scanned_elev, env, **kwargs):&lt;br /&gt;
    coordinates = [638830, 220150]&lt;br /&gt;
    gscript.run_command('r.lake', elevation=scanned_elev, lake='output_lake',&lt;br /&gt;
                        coordinates=coordinates, water_level=120, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a lake where water level is relative to the altitude of the seed cell. Use function [https://grass.osgeo.org/grass70/manuals/libpython/script.html?script.raster.raster_what raster_what] to obtain the elevation value of the DEM and create a lake with water level being for example 5 m higher.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_lake(scanned_elev, env, **kwargs):&lt;br /&gt;
    coordinates = [638830, 220150]&lt;br /&gt;
    res = gscript.raster_what(map=scanned_elev, coord=[coordinates])&lt;br /&gt;
    elev_value = float(res[0][scanned_elev]['value'])&lt;br /&gt;
    gscript.run_command('r.lake', elevation=scanned_elev, lake='output_lake',&lt;br /&gt;
                        coordinates=coordinates, water_level=elev_value + 5, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;!--* {{cmd|r.lake}} can use not just coordinates, but also raster as seed, useful for example for simple river flooding. The task is to simulate raising water level from raster of lowest areas of the DEM. The lowest areas can be found using {{cmd|r.univar}} and extracted as {{cmd|r.mapcalc}}, we can for example specify low lying areas as cells with value smaller than 10th percentile.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Flow accumulation and watersheds ===&lt;br /&gt;
We can derive watersheds and flow accumulation using module {{cmd|r.watershed}} in one command:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_hydro(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.watershed', elevation=scanned_elev, accumulation='flow_accum',&lt;br /&gt;
                        basin='watersheds', threshold=1000, flags='a', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compute average slope value for each watershed. To do that use zonal statistics using {{cmd|r.stats.zonal}}:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_watershed_slope(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.watershed', elevation=scanned_elev, accumulation='flow_accum',&lt;br /&gt;
                        basin='watersheds', threshold=1000, env=env)&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', env=env)&lt;br /&gt;
    gscript.run_command('r.stats.zonal', base='watersheds', cover='slope', method='average',&lt;br /&gt;
                        output='watersheds_slope', env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map='watersheds_slope', color='bgyr', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Depression filling ===&lt;br /&gt;
[[File:tangible_landscape_r_fill_dir.jpg|400px|thumbnail|right|Tangible Landscape: example of using {{cmd|r.fill.dir}} to create ponds]]&lt;br /&gt;
We will use depression filling algorithm implemented in {{cmd|r.fill.dir}} not as preprocessing step for flow accumulation analysis, but for creating ponds.&lt;br /&gt;
Because depressions are often nested, we will run depression filling several times:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_ponds(scanned_elev, env, **kwargs):&lt;br /&gt;
    repeat = 2&lt;br /&gt;
    input_dem = scanned_elev&lt;br /&gt;
    output = &amp;quot;tmp_filldir&amp;quot;&lt;br /&gt;
    for i in range(repeat):&lt;br /&gt;
        gscript.run_command('r.fill.dir', input=input_dem, output=output, direction=&amp;quot;tmp_dir&amp;quot;, env=env)&lt;br /&gt;
        input_dem = output&lt;br /&gt;
    # filter depression deeper than 0.1 m to&lt;br /&gt;
    gscript.mapcalc('{new} = if({out} - {scan} &amp;gt; 0.1, {out} - {scan}, null())'.format(new='ponds', out=output,&lt;br /&gt;
                                                                                      scan=scanned_elev), env=env)&lt;br /&gt;
    gscript.write_command('r.colors', map='ponds', rules='-', stdin='0% aqua\n100% blue', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Overland water flow simulation ===&lt;br /&gt;
Module {{cmd|r.sim.water}} is an overland flow hydrology simulation using path sampling method.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_waterflow(scanned_elev, env, **kwargs):&lt;br /&gt;
    # first we need to compute x- and y-derivatives&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, dx='scan_dx', dy='scan_dy', env=env)&lt;br /&gt;
    gscript.run_command('r.sim.water', elevation=scanned_elev, dx='scan_dx', dy='scan_dy',&lt;br /&gt;
                        rain_value=150, depth='flow', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Erosion modeling ===&lt;br /&gt;
Landscape potential for soil erosion and deposition can be estimated and mapped using Unit Stream Power Based Erosion Deposition model (USPED). In this example we will use uniform land cover (c factor) and soil erodibility (K factor). Install addon {{AddonCmd|r.divergence}} using {{cmd|g.extension}}.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_usped(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', aspect='aspect', env=env)&lt;br /&gt;
    gscript.run_command('r.watershed', elevation=scanned_elev, accumulation='flow_accum', threshold=1000, flags='a', env=env)&lt;br /&gt;
    # topographic sediment transport factor&lt;br /&gt;
    resolution = gscript.region()['nsres']&lt;br /&gt;
    gscript.mapcalc(&amp;quot;sflowtopo = pow(flow_accum * {res}.,1.3) * pow(sin(slope),1.2)&amp;quot;.format(res=resolution), env=env)&lt;br /&gt;
    # compute sediment flow by combining the rainfall, soil and land cover factors with the topographic sediment transport factor. We use a constant value of 270 for rainfall intensity factor&lt;br /&gt;
    gscript.mapcalc(&amp;quot;sedflow = 270. * {k_factor} * {c_factor} * sflowtopo&amp;quot;.format(c_factor=0.05, k_factor=0.1), env=env)&lt;br /&gt;
    # compute divergence of sediment flow&lt;br /&gt;
    gscript.run_command('r.divergence', magnitude='sedflow', direction='aspect', output='erosion_deposition', env=env)&lt;br /&gt;
    colors = ['0% 100:0:100', '-100 magenta', '-10 red', '-1 orange', '-0.1 yellow', '0 200:255:200',&lt;br /&gt;
              '0.1 cyan', '1 aqua', '10 blue', '100 0:0:100', '100% black']&lt;br /&gt;
    gscript.write_command('r.colors', map='erosion_deposition',  rules='-', stdin='\n'.join(colors), env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Solar radiation and shades ==&lt;br /&gt;
We will first compute solar irradiation (daily radiation sum in Wh/m2.day) for a given day using {{cmd|r.sun}}:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_solar_radiation(scanned_elev, env, **kwargs):&lt;br /&gt;
    # convert date to day of year&lt;br /&gt;
    import datetime&lt;br /&gt;
    doy = datetime.datetime(2016, 5, 2).timetuple().tm_yday&lt;br /&gt;
    # precompute slope and aspect&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', aspect='aspect', env=env)&lt;br /&gt;
    gscript.run_command('r.sun', elevation=scanned_elev, slope='slope', aspect='aspect', beam_rad='beam', step=1, day=doy, env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map='beam', color='grey', flags='e')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we can also compute solar irradiance (W/m2) for a given day and hour (in local solar time) and extract the shades cast by topography:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_solar_radiance(scanned_elev, env, **kwargs):&lt;br /&gt;
    # convert date to day of year&lt;br /&gt;
    import datetime&lt;br /&gt;
    doy = datetime.datetime(2016, 5, 2).timetuple().tm_yday&lt;br /&gt;
    # precompute slope and aspect&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', aspect='aspect', env=env)&lt;br /&gt;
    gscript.run_command('r.sun', elevation=scanned_elev, slope='slope', aspect='aspect', beam_rad='beam', day=doy, time=8, env=env)&lt;br /&gt;
    # extract shade and set color to black and white&lt;br /&gt;
    gscript.mapcalc(&amp;quot;shade = if(beam == 0, 0, 1)&amp;quot;, env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map='beam', color='grey')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Visibility analysis ==&lt;br /&gt;
First example shows computing viewshed (visibility) from a given coordinate:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_viewshed(scanned_elev, env, **kwargs):&lt;br /&gt;
    coordinates = [638830, 220150]&lt;br /&gt;
    gscript.run_command('r.viewshed', input=scanned_elev, output='viewshed', coordinates=coordinates, observer_elevation=1.75, flags='b', env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map='viewshed', color='grey')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
== Cost surface and least cost path ==&lt;br /&gt;
[[File:least_cost_path.jpg|400px|thumbnail|right|Least cost path example where cost is slope]]&lt;br /&gt;
This example shows least cost path analysis with slope as cost. Coordinates will be provided by Tangible Landscape.&lt;br /&gt;
The resulting path will go through flat areas.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
def LCP(elevation, start_coordinate, end_coordinate, env):&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', env=env)&lt;br /&gt;
    gscript.run_command('r.cost', input='slope', output='cost', start_coordinates=start_coordinate,&lt;br /&gt;
                        outdir='outdir', flags='k', env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map='cost', color='gyr', env=env)&lt;br /&gt;
    gscript.run_command('r.drain', input='cost', output='drain', direction='outdir',&lt;br /&gt;
                        drain='drain', flags='d', start_coordinates=end_coordinate, env=env)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    env = None&lt;br /&gt;
    start = [638469, 220070]&lt;br /&gt;
    end = [638928, 220472]&lt;br /&gt;
    LCP(elevation, start, end, env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional tasks ==&lt;br /&gt;
# Compute topographic index using {{cmd|r.topidx}}.&lt;br /&gt;
# Compute topographic aspect (slope orientation) using {{cmd|r.slope.aspect}} and reclassify it into 8 main directions.&lt;br /&gt;
# Show areas with concave profile and tangential curvature (concave forms have negative curvature).&lt;br /&gt;
# Derive peaks using either {{AddonCmd|r.geomorphon}} or {{cmd|r.param.scale}} and convert them to points (using {{cmd|r.to.vect}} and {{cmd|v.to.points}}). From each of those points compute visibility with observer height of your choice a derive a cumulative viewshed layer where the value of each cell represents the number of peaks the cell is visible from (use {{cmd|r.series}}).&lt;br /&gt;
# Find a least cost path between 2 points (for example from x=638360, y=220030 to x=638888, y=220388) where cost is defined as topographic index (trying avoid areas). Use {{cmd|r.topidx}}.&lt;br /&gt;
# Compute erosion with spatially variable landcover and soil erodibility (use rasters &amp;lt;tt&amp;gt;cfactorbare_1m&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;soils_Kfactor&amp;lt;/tt&amp;gt; from the provided dataset). Reclassify the result into 7 classes based on severity of erosion and deposition:&lt;br /&gt;
&amp;lt;pre&amp;gt;-120000.:-10:1:1&lt;br /&gt;
-10.:-5.:2:2&lt;br /&gt;
-5.:-0.1:3:3&lt;br /&gt;
-0.1:0.1:4:4&lt;br /&gt;
0.1:5.:5:5&lt;br /&gt;
5.:10.:6:6&lt;br /&gt;
10.:150000.:7:7&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: Tutorial]]&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Python]]&lt;br /&gt;
[[Category: 2016]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Using_GRASS_GIS_through_Python_and_tangible_interfaces_(workshop_at_FOSS4G_NA_2016)&amp;diff=23076</id>
		<title>Using GRASS GIS through Python and tangible interfaces (workshop at FOSS4G NA 2016)</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Using_GRASS_GIS_through_Python_and_tangible_interfaces_(workshop_at_FOSS4G_NA_2016)&amp;diff=23076"/>
		<updated>2016-05-02T13:08:03Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: /* Tangible Landscape */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:FOSS4G NA 2016.png|center|none]]&lt;br /&gt;
&lt;br /&gt;
This is material for FOSS4G NA 2016 workshop Using GRASS GIS through Python and tangible interfaces held in Raleigh May 2, 2016 - 09:00 to 13:00. &lt;br /&gt;
&lt;br /&gt;
Learn about scripting, graphical and tangible (!) interfaces for GRASS GIS, the powerful desktop GIS and geoprocessing backend. We will start with the Python interface and finish with [https://geospatial.ncsu.edu/osgeorel/tangible-landscape.html Tangible Landscape], a new tangible interface for GRASS GIS.&lt;br /&gt;
Python is the primary scripting language for GRASS GIS. We will demonstrate how to use Python to automate your geoprocessing workflows with GRASS GIS modules and develop custom algorithms using a Pythonic interface to access low level GRASS GIS library functions. We will also review several tips and tricks for parallelization.&lt;br /&gt;
[https://geospatial.ncsu.edu/osgeorel/tangible-landscape.html Tangible Landscape] is an example of how the GRASS GIS Python API can be used to build new, cutting edge tools and advanced applications. Tangible Landscape is a collaborative 3D sketching tool which couples a 3D scanner, a projector and a physical 3D model with GRASS GIS. The workshop will be a truly hands-on experience – you will play with Tangible Landscape, using your hands to shape a sand model and drive geospatial processes.&lt;br /&gt;
&lt;br /&gt;
'''Software''': [https://grass.osgeo.org GRASS GIS 7]&lt;br /&gt;
&lt;br /&gt;
'''Data''': Download [https://grass.osgeo.org/sampledata/north_carolina/nc_spm_08_grass7.zip complete North Carolina sample dataset].&lt;br /&gt;
&lt;br /&gt;
= GRASS GIS introduction =&lt;br /&gt;
You need to create a GRASS database we will use for the tutorial. Please download the [https://grass.osgeo.org/sampledata/north_carolina/nc_spm_08_grass7.zip dataset] for the workshop, noting where the files are located on your local directory. &lt;br /&gt;
Now, create (unless you already have it) a directory named &amp;lt;tt&amp;gt;grassdata&amp;lt;/tt&amp;gt; (GRASS database) in your home folder (or Documents), unzip the downloaded data into this directory. You should now have a Location &amp;lt;tt&amp;gt;nc_spm_08_grass7&amp;lt;/tt&amp;gt; in grassdata. Start GRASS GIS in Mapset &amp;lt;tt&amp;gt;user1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
GRASS GUI introduction&lt;br /&gt;
* [http://www4.ncsu.edu/~akratoc/GRASS_intro/ Basic screenshot tutorial] how to use GRASS GIS GUI &lt;br /&gt;
* [[Workshop_on_urban_growth_modeling_with_FUTURES#GRASS_GIS_introduction|Introduction from Workshop on urban growth modeling with FUTURES]]&lt;br /&gt;
&lt;br /&gt;
= GRASS GIS Python API =&lt;br /&gt;
&lt;br /&gt;
== Python Scripting library ==&lt;br /&gt;
[[File:GRASS GUI Python shell.png|thumbnail|right|Python shell in GRASS GIS GUI]]&lt;br /&gt;
The GRASS GIS 7 Python Scripting Library provides functions to call GRASS modules within scripts as subprocesses. The most often used functions include:&lt;br /&gt;
* '''[https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.run_command run_command]''': most often used with modules which output raster/vector data where text output is not expected&lt;br /&gt;
* '''[https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.read_command read_command]''': used when we are interested in text output&lt;br /&gt;
* '''[https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.parse_command parse_command]''': used with modules producing text output as key=value pair&lt;br /&gt;
* '''[https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.write_command write_command]''': for modules expecting text input from either standard input or file&lt;br /&gt;
&lt;br /&gt;
Besides, this library provides several wrapper functions for often called modules.&lt;br /&gt;
&lt;br /&gt;
=== Calling GRASS GIS modules ===&lt;br /&gt;
We will use GRASS GUI Python Shell to run the commands. For longer scripts, you can create a text file, save it into your current working directory and run it with &amp;lt;tt&amp;gt;python myscript.py&amp;lt;/tt&amp;gt; from the GUI command console or terminal.&lt;br /&gt;
&lt;br /&gt;
'''Tip''': When copying Python code snippets to GUI Python shell, right click at the position and select '''Paste Plus''' in the context menu. Otherwise multiline code snippets won't work.&lt;br /&gt;
&lt;br /&gt;
We start by importing GRASS GIS Python Scripting Library:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Before running any GRASS raster modules, you need to set the computational region using {{cmd|g.region}}. In this example, we set the computational extent and resolution to the raster layer &amp;lt;tt&amp;gt;elevation&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.run_command('g.region', raster='elevation')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The run_command() function is the most commonly used one. Here, we apply the focal operation average ({{cmd|r.neighbors}}) to smooth the elevation raster layer. Note that the syntax is similar to bash syntax, just the flags are specified in a parameter.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.run_command('r.neighbors', input='elevation', output='elev_smoothed', method='average', flags='c')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If we run the Python commands from GUI Python console, we can use &amp;lt;tt&amp;gt;AddLayer&amp;lt;/tt&amp;gt; to add the newly created layer:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
AddLayer('elev_smoothed')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Calling GRASS GIS modules with textual input or output ===&lt;br /&gt;
Textual output from modules can be captured using the read_command() function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.read_command('g.region', flags='p')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.read_command('r.univar', map='elev_smoothed', flags='g')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Certain modules can produce output in key-value format which is enabled by the '''-g''' flag. The parse_command() function automatically parses this output and returns a dictionary. In this example, we call {{cmd|g.proj}} to display the projection parameters of the actual location.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.parse_command('g.proj', flags='g')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For comparison, below is the same example, but using the read_command() function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.read_command('g.proj', flags='g')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Certain modules require the text input be in a file or provided as standard input. Using the write_command() function we can conveniently pass the string to the module. Here, we are creating a new vector with one point with {{cmd|v.in.ascii}}. Note that ''stdin'' parameter is not used as a module parameter, but its content is passed as standard input to the subprocess.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.write_command('v.in.ascii', input='-', stdin='%s|%s' % (635818, 221342), output='point')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If we run the Python commands from GUI Python console, we can use &amp;lt;tt&amp;gt;AddLayer&amp;lt;/tt&amp;gt; to add the newly created layer:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
AddLayer('point')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Convenient wrapper functions ===&lt;br /&gt;
Some modules have wrapper functions to simplify frequent tasks.&lt;br /&gt;
For example we can obtain the information about a raster layer with [https://grass.osgeo.org/grass70/manuals/libpython/script.html?highlight=mapcalc#script.raster.raster_info raster_info] which is a wrapper of {{cmd|r.info}},&lt;br /&gt;
or a vector layer with [https://grass.osgeo.org/grass70/manuals/libpython/script.html?script.vector.vector_info vector_info].&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.raster_info('elevation')&lt;br /&gt;
gscript.vector_info('point')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Another example is using [https://grass.osgeo.org/grass70/manuals/libpython/script.html?highlight=mapcalc#script.raster.mapcalc r.mapcalc wrapper] for raster algebra:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.mapcalc(&amp;quot;elev_strip = if(elevation &amp;gt; 100 &amp;amp;&amp;amp; elevation &amp;lt; 125, elevation, null())&amp;quot;)&lt;br /&gt;
gscript.read_command('r.univar', map='elev_strip', flags='g')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Function [https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.region region] is a convenient way to retrieve the current region settings (i.e., computational region). It returns a dictionary with values converted to appropriate types (floats and ints). &lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
region = gscript.region()&lt;br /&gt;
print region&lt;br /&gt;
# cell area in map units (in projected Locations)&lt;br /&gt;
region['nsres'] * region['ewres']&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We can list data stored in a GRASS GIS location with {{cmd|g.list}} wrappers. With [https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.list_grouped list_grouped], the map layers are grouped by mapsets (in this example, raster layers):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gscript.list_grouped(type=['raster'])&lt;br /&gt;
gscript.list_grouped(type=['raster'], pattern=&amp;quot;landuse*&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here is an example of a different {{cmd|g.list}} wrapper [https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.list_pairs list_pairs] which structures the output as list of pairs (name, mapset). We obtain current mapset with {{cmd|g.gisenv}} wrapper.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
current_mapset = gscript.gisenv()['MAPSET']&lt;br /&gt;
gscript.list_pairs('raster', mapset=current_mapset)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exercise ===&lt;br /&gt;
Export all raster layers from your mapset with a name prefix &amp;quot;elev_*&amp;quot; as GeoTiff (see {{cmd|r.out.gdal}}). Don't forget to set the current region ({{cmd|g.region}}) for each map in order to match the individual exported raster layer extents and resolutions since they may differ from each other.&lt;br /&gt;
&lt;br /&gt;
== PyGRASS ==&lt;br /&gt;
PyGRASS is a library originally developed during the Google Summer of Code 2012. PyGRASS library adds two main functionalities:&lt;br /&gt;
* Python interface through the ctypes binding of the C API of GRASS, to read and write natively GRASS GIS 7 data structures,&lt;br /&gt;
* GRASS GIS module interface using objects to check the parameters and execute the respective modules.&lt;br /&gt;
For further discussion about the implementation ideas and performance are presented in the article:&lt;br /&gt;
''[http://www.mdpi.com/2220-9964/2/1/201 Zambelli, P.; Gebbert, S.; Ciolli, M. Pygrass: An Object Oriented Python Application Programming Interface (API) for Geographic Resources Analysis Support System (GRASS) Geographic Information System (GIS). ISPRS Int. J. Geo-Inf. 2013, 2, 201-219.]''&lt;br /&gt;
&lt;br /&gt;
Standard scripting with GRASS modules in Python may sometime seem discouraging especially when you have to do conceptually simple things like: iterate over vector features or raster rows/columns.&lt;br /&gt;
Using the C API (most of GRASS GIS is written in C), all this is much more simple since you can directly work on GRASS GIS data and do just what you need to do.&lt;br /&gt;
However, you perhaps want to stick to Python. Here, the PyGRASS library introduced several objects that allow to interact directly with the data using the underlying C API of GRASS GIS.&lt;br /&gt;
&lt;br /&gt;
=== Working with vector data (see [https://grass.osgeo.org/grass70/manuals/libpython/pygrass_vector.html manual page]) ===&lt;br /&gt;
Create a new vector map. Import the necessary classes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.vector import VectorTopo&lt;br /&gt;
from grass.pygrass.vector.geometry import Point&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create an instance of a vector map:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
my_points = VectorTopo('my_points')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Open the map in write mode:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
my_points.open(mode='w')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create some vector geometry features, like two points:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
point1 = Point(635818.8, 221342.4)&lt;br /&gt;
point2 = Point(633627.7, 227050.2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the above two points to the new vector map:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
my_points.write(point1)&lt;br /&gt;
my_points.write(point2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally close the vector map:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
my_points.close()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Display the newly created vector (from GUI Python Shell):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
AddLayer('my_points')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now do the same thing using the context manager syntax and set also the attribute table:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Define the columns of the new vector map&lt;br /&gt;
cols = [(u'cat',       'INTEGER PRIMARY KEY'),&lt;br /&gt;
        (u'name',      'TEXT')]&lt;br /&gt;
&lt;br /&gt;
with VectorTopo('my_points', mode='w', tab_cols=cols, overwrite=True) as my_points:&lt;br /&gt;
    # save the point and the attribute&lt;br /&gt;
    my_points.write(point1, ('pub', ))&lt;br /&gt;
    my_points.write(point2, ('restaurant', ))&lt;br /&gt;
    # save the changes to the database&lt;br /&gt;
    my_points.table.conn.commit()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Note: we don't need to close the vector map because it is already closed by the context manager.&lt;br /&gt;
&lt;br /&gt;
Go to Layer Manager, right click on 'my_points' and ''Show attribute data''.&lt;br /&gt;
&lt;br /&gt;
Read an existing vector map:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
with VectorTopo('my_points', mode='r') as points:&lt;br /&gt;
    for point in points:&lt;br /&gt;
        print(point, point.attrs['name'])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Working with raster data (see [https://grass.osgeo.org/grass70/manuals/libpython/pygrass_raster.html manual page]) ===&lt;br /&gt;
Create a new raster map and derive it's new values from &amp;lt;tt&amp;gt;elevation&amp;lt;/tt&amp;gt; raster. Import the necessary classes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.raster import RasterRow&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Open the existing raster in read mode and print first 5 values of the first row (indices from S to N):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
elev = RasterRow('elevation')&lt;br /&gt;
print elev.exist()&lt;br /&gt;
print elev.mapset&lt;br /&gt;
elev.open('r')&lt;br /&gt;
print elev[0][:5]&lt;br /&gt;
elev.close()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a new raster and write value 1 for cells with elevation &amp;lt; 120 and 0 otherwise:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
new = RasterRow('new')&lt;br /&gt;
new.open('w', overwrite=True)&lt;br /&gt;
for row in elev:&lt;br /&gt;
    new.put_row(row &amp;lt; 120)&lt;br /&gt;
new.close()&lt;br /&gt;
print new.exist()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Query old and new raster maps:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from grass.pygrass.vector import geometry&lt;br /&gt;
&lt;br /&gt;
new.open('r')&lt;br /&gt;
elev.open('r')&lt;br /&gt;
poi1 = geometry.Point(632942, 225757)&lt;br /&gt;
poi2 = geometry.Point(641780, 217455)&lt;br /&gt;
print elev.get_value(poi1), new.get_value(poi1)&lt;br /&gt;
print elev.get_value(poi2), new.get_value(poi2)&lt;br /&gt;
new.close()&lt;br /&gt;
elev.close()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more examples of using PyGRASS, please look at [https://github.com/wenzeslaus/python-grass-addon How to write a Python GRASS GIS 7 addon] workshop from FOSS4G-Europe 2015 and additional tutorials can be found [[Python/pygrass|on a PyGRASS wiki page]].&lt;br /&gt;
&lt;br /&gt;
= Parallelization examples =&lt;br /&gt;
A simple way to execute several modules in parallel (developed by Sören Gebbert) &lt;br /&gt;
is the [https://grass.osgeo.org/grass71/manuals/libpython/pygrass.modules.interface.html?highlight=parallelmodulequeue#pygrass.modules.interface.module.ParallelModuleQueue ParallelModuleQueue class]. The basic idea is to create a queue with all the modules that must be execute in parallel. The ParallelModuleQueue class is based on the Module class of the pygrass library, here is a small example for computation of solar irradiance during day:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from copy import deepcopy&lt;br /&gt;
from grass.pygrass.modules import Module, ParallelModuleQueue&lt;br /&gt;
&lt;br /&gt;
def main(elevation):&lt;br /&gt;
    # compute slope and aspect for r.sun&lt;br /&gt;
    Module('r.slope.aspect', elevation=elevation, aspect='aspect', slope='slope', overwrite=True)&lt;br /&gt;
    # initialize an empty queue and list&lt;br /&gt;
    queue = ParallelModuleQueue(nprocs=4)&lt;br /&gt;
    sun_name = 'sun_{}'&lt;br /&gt;
    # set computational region&lt;br /&gt;
    Module('g.region', raster=elevation)&lt;br /&gt;
    # initialize a module instance with shared inputs&lt;br /&gt;
    sun = Module('r.sun', elevation=elevation, slope='slope', aspect='aspect',&lt;br /&gt;
                 beam_rad='beam', step=1, day=123, run_=False, overwrite=True)&lt;br /&gt;
&lt;br /&gt;
    for t in range(6, 22):&lt;br /&gt;
        # create a copy of the module and set the remaining parameters&lt;br /&gt;
        print t&lt;br /&gt;
        m = deepcopy(sun)(beam_rad=sun_name.format(t), time=t)&lt;br /&gt;
        queue.put(m)&lt;br /&gt;
    queue.wait()&lt;br /&gt;
&lt;br /&gt;
    # set color table&lt;br /&gt;
    Module('r.colors', map=[sun_name.format(t) for t in range(6, 22)], color='grey', flags='e')&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    main(elevation)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This simple parallel implementation uses Python class Pool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from multiprocessing import Pool&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
&lt;br /&gt;
def rsun(params):&lt;br /&gt;
    gscript.run_command('r.sun', **params)&lt;br /&gt;
&lt;br /&gt;
def main(elevation):&lt;br /&gt;
    parameters = []&lt;br /&gt;
    sun_name = 'sun_{}'&lt;br /&gt;
    for t in range(6, 22):&lt;br /&gt;
        params = dict(elevation=elevation, slope='slope', aspect='aspect',&lt;br /&gt;
                      step=1, day=123, beam_rad=sun_name.format(t), time=t, overwrite=True)&lt;br /&gt;
        parameters.append(params)&lt;br /&gt;
    pool = Pool(4)&lt;br /&gt;
    p = pool.map_async(rsun, parameters)&lt;br /&gt;
    p.get()&lt;br /&gt;
        &lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    main(elevation)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example shows parallelization by splitting computation into tiles using [https://grass.osgeo.org/grass71/manuals/libpython/pygrass.modules.grid.html?highlight=gridmodule#pygrass.modules.grid.grid.GridModule GridModule]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
from grass.pygrass.modules.grid import GridModule&lt;br /&gt;
&lt;br /&gt;
def main(elevation):&lt;br /&gt;
    region = gscript.region()&lt;br /&gt;
    width = region['cols'] // 2 + 1&lt;br /&gt;
    height = region['rows'] // 2 + 1&lt;br /&gt;
&lt;br /&gt;
    grd = GridModule('r.slope.aspect', elevation=elevation, slope='slope',&lt;br /&gt;
                     debug=False, width=width, height=height,&lt;br /&gt;
                     overlap=10, processes=4, overwrite=True)&lt;br /&gt;
    grd.run()&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elevation'&lt;br /&gt;
    gscript.run_command('g.region', raster=elevation)&lt;br /&gt;
    main(elevation)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tangible Landscape =&lt;br /&gt;
[[File:Tangible landscape setup.jpg|400px|thumbnail|right|Tangible Landscape setup]]&lt;br /&gt;
&lt;br /&gt;
A brief introduction to Tangible Landscape: [http://baharmon.github.io/foss4g-na-2016-workshop/]&lt;br /&gt;
&lt;br /&gt;
Tangible Landscape is a collaborative modeling environment for analysis of terrain changes.&lt;br /&gt;
We couple a scanner, projector and a physical 3D model with GRASS GIS.&lt;br /&gt;
We can analyze the impact of terrain changes by capturing the changes on the model,&lt;br /&gt;
bringing them into the GIS, performing desired analysis or simulation and projecting the results back on the model in real-time.&lt;br /&gt;
Tangible Landscape, as an easy-to-use 3D sketching tool, enables rapid design and scenarios testing for people with different backgrounds&lt;br /&gt;
and computer knowledge, as well as support for decision-making process.&lt;br /&gt;
&lt;br /&gt;
Tangible Landscape has been used for a variety of applications supported by the extensive set of geospatial analysis and modeling tools available in GRASS GIS. We have explored how dune breaches affect the extent of coastal flooding, the impact of different building configurations on cast shadows and solar energy potential, and the effectiveness of various landscape designs for controlling runoff and erosion. Have a look at our [http://www.springer.com/us/book/9783319257730 book], [https://www.youtube.com/channel/UCc37pVh-WE46Xkqeq-KZQsA Youtube channel], and [https://plus.google.com/112857255995703553144/photos Google+ photos].&lt;br /&gt;
&lt;br /&gt;
The software is free and open source and you can [https://github.com/ncsu-osgeorel/grass-tangible-landscape download it] and use it in your own setup of Tangible Landscape.&lt;br /&gt;
&lt;br /&gt;
== Running examples ==&lt;br /&gt;
We will use a Titanpad to collect code samples from workshop participants and then run them in Tangible Landscape environment.&lt;br /&gt;
Whenever a scanning cycle is complete, a specified Python file is imported and all analyses in that file are computed.&lt;br /&gt;
Analyses are organized into functions with defined interface - each function has to start with &amp;lt;tt&amp;gt;run_&amp;lt;/tt&amp;gt;.&lt;br /&gt;
Input parameter &amp;lt;tt&amp;gt;scanned_elev&amp;lt;/tt&amp;gt; is the scanned raster (our DEM) and &amp;lt;tt&amp;gt;env&amp;lt;/tt&amp;gt; is the environment which needs to be passed to individual subprocesses to correctly handle the region of the analysis.&lt;br /&gt;
&lt;br /&gt;
Since participants will develop and test the analyses on their computers before we apply them to Tangible Landscape,&lt;br /&gt;
we add here the 'main' function with predefined parameters and participants will run it as a script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
&lt;br /&gt;
def run_slope(scanned_elev, env, **kwargs):&lt;br /&gt;
    # compute the analysis&lt;br /&gt;
    gscript.run_command('r.slope.aspect', ..., env=env) &lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    import os&lt;br /&gt;
    os.environ['GRASS_OVERWRITE'] = '1'&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    run_slope(scanned_elev=elevation, env=None)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scripts can be run from terminal or GUI command console:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python /path/to/my/script.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On Windows the path will look differently, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
python C:\Users\yourname\path\to\my\script.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure you set computational region to match your DEM. We will use raster DEM &amp;lt;tt&amp;gt;elev_lid792_1m&amp;lt;/tt&amp;gt; from the sample dataset.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
g.region raster=elev_lid792_1m -p&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here follow some basic examples of geospatial analyses we can do with Tangible Landscape.&lt;br /&gt;
At the end of this section you can find additional tasks, some of them combining multiple analyses.&lt;br /&gt;
&lt;br /&gt;
== Modeling topography ==&lt;br /&gt;
=== Computing slope ===&lt;br /&gt;
[[File:tangible landscape slope.jpg|400px|thumbnail|right|Tangible Landscape: topographic slope]]&lt;br /&gt;
Basic example how we can compute topographic slope in degrees:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
&lt;br /&gt;
def run_slope(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', env=env)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    env = None&lt;br /&gt;
    run_slope(scanned_elev=elevation, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We can compute slope in percent and reclassify the values into discrete intervals:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_slope(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope',&lt;br /&gt;
                        format='percent', env=env)&lt;br /&gt;
    # reclassify using rules passed as a string to standard input&lt;br /&gt;
    # 0:2:1 means reclassify interval 0 to 2 percent of slope to category 1 &lt;br /&gt;
    rules = ['0:2:1', '2:5:2', '5:8:3', '8:15:4', '15:30:5', '30:*:6']&lt;br /&gt;
    gscript.write_command('r.recode', input='slope', output='slope_class',&lt;br /&gt;
                          rules='-', stdin='\n'.join(rules), env=env)&lt;br /&gt;
    # set new color table: green - yellow - red&lt;br /&gt;
    gscript.run_command('r.colors', map='slope_class', color='gyr', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Curvatures ===&lt;br /&gt;
Explore concavity/convexity of terrain with curvatures computed by {{cmd|r.param.scale}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_curvatures(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.param.scale', input=scanned_elev, output='profile_curv',&lt;br /&gt;
                        method='profc', size=11, env=env)&lt;br /&gt;
    gscript.run_command('r.param.scale', input=scanned_elev, output='tangential_curv',&lt;br /&gt;
                        method='crosc', size=11, env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map=['profile_curv', 'tangential_curv'], color='curvature', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Change window size and see how it influences the result.&lt;br /&gt;
&lt;br /&gt;
=== Landform identification ===&lt;br /&gt;
[[File:Tangible landscape geomorphons.jpg|400px|thumbnail|right|Tangible Landscape: Landforms computed with {{AddonCmd|r.geomorphon}}]]&lt;br /&gt;
There are 2 different methods for landform (ridge, valley, ...) identification in GRASS GIS.&lt;br /&gt;
First one is implemented in {{cmd|r.param.scale}} and uses curvatures.&lt;br /&gt;
The second is implemented in an addon {{AddonCmd|r.geomorphon}} which uses multiscale line-of-sight approach. This addon can be installed&lt;br /&gt;
from GUI command line:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
g.extension r.geomorphon&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
or follow &lt;br /&gt;
[https://grasswiki.osgeo.org/wiki/Introduction_to_GRASS_GIS_with_terrain_analysis_examples#Step_5:_Adding_the_r.geomorphon_Addon this tutorial].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_curvatures(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.param.scale', input=scanned_elev, output='landforms1',&lt;br /&gt;
                        method='feature', size=10, env=env)&lt;br /&gt;
    gscript.run_command('r.geomorphon', dem=scanned_elev, forms='landforms2',&lt;br /&gt;
                        search=16, skip=6, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Building model based on difference raster ===&lt;br /&gt;
When building a model by hands based on a defined DEM, we can compute the difference between the scanned model and the original DEM.&lt;br /&gt;
By color-coding the difference, we can see where to add sand or remove it. &lt;br /&gt;
&lt;br /&gt;
If you are running this outside of Tangible Landscape, you can generate a raster (our hypothetical pile of sand)&lt;br /&gt;
and compute the difference. In this example we also vertically rescale and translate the scanned raster to match&lt;br /&gt;
the original DEM using {{cmd|r.regression.line}}.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
&lt;br /&gt;
def run_difference(real_elev, scanned_elev, env, **kwargs):&lt;br /&gt;
    regression_params = gscript.parse_command('r.regression.line', flags='g', mapx=scanned_elev, mapy=real_elev, env=env)&lt;br /&gt;
    gscript.mapcalc('{regression} = {a} + {b} * {before}'.format(a=regression_params['a'], b=regression_params['b'],&lt;br /&gt;
                                                                 before=scanned_elev, regression='regression'), env=env)&lt;br /&gt;
    gscript.mapcalc('{difference} = {regression} - {after}'.format(regression='regression', after=real_elev, difference='diff'), env=env)&lt;br /&gt;
    gscript.write_command('r.colors', map='diff', rules='-', stdin=&amp;quot;-100 black\n-20 red\n0 white\n20 blue\n100 black&amp;quot;, env=env)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    sand_pile = 'sand_pile'&lt;br /&gt;
    env = None&lt;br /&gt;
    gscript.run_command('r.surf.fractal', output=sand_pile)&lt;br /&gt;
    run_difference(real_elev=elevation, scanned_elev=sand_pile, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hydrology ==&lt;br /&gt;
=== Flooding with {{cmd|r.lake}} ===&lt;br /&gt;
[[File:tangible landscape rlake.jpg|200px|thumbnail|right|Example of simple flooding simulation with Tangible Landscape and {{cmd|r.lake}} module.]]&lt;br /&gt;
&lt;br /&gt;
Module {{cmd|r.lake}} fills a lake to a target water level from a given start point or seed raster.&lt;br /&gt;
The resulting raster map contains cells with values representing lake depth and NULL for all other cells beyond the lake.&lt;br /&gt;
&lt;br /&gt;
Example showing basic usage:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_lake(scanned_elev, env, **kwargs):&lt;br /&gt;
    coordinates = [638830, 220150]&lt;br /&gt;
    gscript.run_command('r.lake', elevation=scanned_elev, lake='output_lake',&lt;br /&gt;
                        coordinates=coordinates, water_level=120, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a lake where water level is relative to the altitude of the seed cell. Use function [https://grass.osgeo.org/grass70/manuals/libpython/script.html?script.raster.raster_what raster_what] to obtain the elevation value of the DEM and create a lake with water level being for example 5 m higher.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_lake(scanned_elev, env, **kwargs):&lt;br /&gt;
    coordinates = [638830, 220150]&lt;br /&gt;
    res = gscript.raster_what(map=scanned_elev, coord=[coordinates])&lt;br /&gt;
    elev_value = float(res[0][scanned_elev]['value'])&lt;br /&gt;
    gscript.run_command('r.lake', elevation=scanned_elev, lake='output_lake',&lt;br /&gt;
                        coordinates=coordinates, water_level=elev_value + 5, env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;!--* {{cmd|r.lake}} can use not just coordinates, but also raster as seed, useful for example for simple river flooding. The task is to simulate raising water level from raster of lowest areas of the DEM. The lowest areas can be found using {{cmd|r.univar}} and extracted as {{cmd|r.mapcalc}}, we can for example specify low lying areas as cells with value smaller than 10th percentile.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Flow accumulation and watersheds ===&lt;br /&gt;
We can derive watersheds and flow accumulation using module {{cmd|r.watershed}} in one command:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_hydro(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.watershed', elevation=scanned_elev, accumulation='flow_accum',&lt;br /&gt;
                        basin='watersheds', threshold=1000, flags='a', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compute average slope value for each watershed. To do that use zonal statistics using {{cmd|r.stats.zonal}}:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_watershed_slope(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.watershed', elevation=scanned_elev, accumulation='flow_accum',&lt;br /&gt;
                        basin='watersheds', threshold=1000, env=env)&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', env=env)&lt;br /&gt;
    gscript.run_command('r.stats.zonal', base='watersheds', cover='slope', method='average',&lt;br /&gt;
                        output='watersheds_slope', env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map='watersheds_slope', color='bgyr', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Depression filling ===&lt;br /&gt;
[[File:tangible_landscape_r_fill_dir.jpg|400px|thumbnail|right|Tangible Landscape: example of using {{cmd|r.fill.dir}} to create ponds]]&lt;br /&gt;
We will use depression filling algorithm implemented in {{cmd|r.fill.dir}} not as preprocessing step for flow accumulation analysis, but for creating ponds.&lt;br /&gt;
Because depressions are often nested, we will run depression filling several times:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_ponds(scanned_elev, env, **kwargs):&lt;br /&gt;
    repeat = 2&lt;br /&gt;
    input_dem = scanned_elev&lt;br /&gt;
    output = &amp;quot;tmp_filldir&amp;quot;&lt;br /&gt;
    for i in range(repeat):&lt;br /&gt;
        gscript.run_command('r.fill.dir', input=input_dem, output=output, direction=&amp;quot;tmp_dir&amp;quot;, env=env)&lt;br /&gt;
        input_dem = output&lt;br /&gt;
    # filter depression deeper than 0.1 m to&lt;br /&gt;
    gscript.mapcalc('{new} = if({out} - {scan} &amp;gt; 0.1, {out} - {scan}, null())'.format(new='ponds', out=output,&lt;br /&gt;
                                                                                      scan=scanned_elev), env=env)&lt;br /&gt;
    gscript.write_command('r.colors', map='ponds', rules='-', stdin='0% aqua\n100% blue', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Overland water flow simulation ===&lt;br /&gt;
Module {{cmd|r.sim.water}} is an overland flow hydrology simulation using path sampling method.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_waterflow(scanned_elev, env, **kwargs):&lt;br /&gt;
    # first we need to compute x- and y-derivatives&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, dx='scan_dx', dy='scan_dy', env=env)&lt;br /&gt;
    gscript.run_command('r.sim.water', elevation=scanned_elev, dx='scan_dx', dy='scan_dy',&lt;br /&gt;
                        rain_value=150, depth='flow', env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Erosion modeling ===&lt;br /&gt;
Landscape potential for soil erosion and deposition can be estimated and mapped using Unit Stream Power Based Erosion Deposition model (USPED). In this example we will use uniform land cover (c factor) and soil erodibility (K factor). Install addon {{AddonCmd|r.divergence}} using {{cmd|g.extension}}.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_usped(scanned_elev, env, **kwargs):&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', aspect='aspect', env=env)&lt;br /&gt;
    gscript.run_command('r.watershed', elevation=scanned_elev, accumulation='flow_accum', threshold=1000, flags='a', env=env)&lt;br /&gt;
    # topographic sediment transport factor&lt;br /&gt;
    resolution = gscript.region()['nsres']&lt;br /&gt;
    gscript.mapcalc(&amp;quot;sflowtopo = pow(flow_accum * {res}.,1.3) * pow(sin(slope),1.2)&amp;quot;.format(res=resolution), env=env)&lt;br /&gt;
    # compute sediment flow by combining the rainfall, soil and land cover factors with the topographic sediment transport factor. We use a constant value of 270 for rainfall intensity factor&lt;br /&gt;
    gscript.mapcalc(&amp;quot;sedflow = 270. * {k_factor} * {c_factor} * sflowtopo&amp;quot;.format(c_factor=0.05, k_factor=0.1), env=env)&lt;br /&gt;
    # compute divergence of sediment flow&lt;br /&gt;
    gscript.run_command('r.divergence', magnitude='sedflow', direction='aspect', output='erosion_deposition', env=env)&lt;br /&gt;
    colors = ['0% 100:0:100', '-100 magenta', '-10 red', '-1 orange', '-0.1 yellow', '0 200:255:200',&lt;br /&gt;
              '0.1 cyan', '1 aqua', '10 blue', '100 0:0:100', '100% black']&lt;br /&gt;
    gscript.write_command('r.colors', map='erosion_deposition',  rules='-', stdin='\n'.join(colors), env=env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Solar radiation and shades ==&lt;br /&gt;
We will first compute solar irradiation (daily radiation sum in Wh/m2.day) for a given day using {{cmd|r.sun}}:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_solar_radiation(scanned_elev, env, **kwargs):&lt;br /&gt;
    # convert date to day of year&lt;br /&gt;
    import datetime&lt;br /&gt;
    doy = datetime.datetime(2016, 5, 2).timetuple().tm_yday&lt;br /&gt;
    # precompute slope and aspect&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', aspect='aspect', env=env)&lt;br /&gt;
    gscript.run_command('r.sun', elevation=scanned_elev, slope='slope', aspect='aspect', beam_rad='beam', step=1, day=doy, env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map='beam', color='grey', flags='e')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we can also compute solar irradiance (W/m2) for a given day and hour (in local solar time) and extract the shades cast by topography:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_solar_radiance(scanned_elev, env, **kwargs):&lt;br /&gt;
    # convert date to day of year&lt;br /&gt;
    import datetime&lt;br /&gt;
    doy = datetime.datetime(2016, 5, 2).timetuple().tm_yday&lt;br /&gt;
    # precompute slope and aspect&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', aspect='aspect', env=env)&lt;br /&gt;
    gscript.run_command('r.sun', elevation=scanned_elev, slope='slope', aspect='aspect', beam_rad='beam', day=doy, time=8, env=env)&lt;br /&gt;
    # extract shade and set color to black and white&lt;br /&gt;
    gscript.mapcalc(&amp;quot;shade = if(beam == 0, 0, 1)&amp;quot;, env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map='beam', color='grey')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Visibility analysis ==&lt;br /&gt;
First example shows computing viewshed (visibility) from a given coordinate:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def run_viewshed(scanned_elev, env, **kwargs):&lt;br /&gt;
    coordinates = [638830, 220150]&lt;br /&gt;
    gscript.run_command('r.viewshed', input=scanned_elev, output='viewshed', coordinates=coordinates, observer_elevation=1.75, flags='b', env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map='viewshed', color='grey')&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
== Cost surface and least cost path ==&lt;br /&gt;
[[File:least_cost_path.jpg|400px|thumbnail|right|Least cost path example where cost is slope]]&lt;br /&gt;
This example shows least cost path analysis with slope as cost. Coordinates will be provided by Tangible Landscape.&lt;br /&gt;
The resulting path will go through flat areas.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import grass.script as gscript&lt;br /&gt;
def LCP(elevation, start_coordinate, end_coordinate, env):&lt;br /&gt;
    gscript.run_command('r.slope.aspect', elevation=scanned_elev, slope='slope', env=env)&lt;br /&gt;
    gscript.run_command('r.cost', input='slope', output='cost', start_coordinates=start_coordinate,&lt;br /&gt;
                        outdir='outdir', flags='k', env=env)&lt;br /&gt;
    gscript.run_command('r.colors', map='cost', color='gyr', env=env)&lt;br /&gt;
    gscript.run_command('r.drain', input='cost', output='drain', direction='outdir',&lt;br /&gt;
                        drain='drain', flags='d', start_coordinates=end_coordinate, env=env)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    elevation = 'elev_lid792_1m'&lt;br /&gt;
    env = None&lt;br /&gt;
    start = [638469, 220070]&lt;br /&gt;
    end = [638928, 220472]&lt;br /&gt;
    LCP(elevation, start, end, env)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional tasks ==&lt;br /&gt;
# Compute topographic index using {{cmd|r.topidx}}.&lt;br /&gt;
# Compute topographic aspect (slope orientation) using {{cmd|r.slope.aspect}} and reclassify it into 8 main directions.&lt;br /&gt;
# Show areas with concave profile and tangential curvature (concave forms have negative curvature).&lt;br /&gt;
# Derive peaks using either {{AddonCmd|r.geomorphon}} or {{cmd|r.param.scale}} and convert them to points (using {{cmd|r.to.vect}} and {{cmd|v.to.points}}). From each of those points compute visibility with observer height of your choice a derive a cumulative viewshed layer where the value of each cell represents the number of peaks the cell is visible from (use {{cmd|r.series}}).&lt;br /&gt;
# Find a least cost path between 2 points (for example from x=638360, y=220030 to x=638888, y=220388) where cost is defined as topographic index (trying avoid areas). Use {{cmd|r.topidx}}.&lt;br /&gt;
# Compute erosion with spatially variable landcover and soil erodibility (use rasters &amp;lt;tt&amp;gt;cfactorbare_1m&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;soils_Kfactor&amp;lt;/tt&amp;gt; from the provided dataset). Reclassify the result into 7 classes based on severity of erosion and deposition:&lt;br /&gt;
&amp;lt;pre&amp;gt;-120000.:-10:1:1&lt;br /&gt;
-10.:-5.:2:2&lt;br /&gt;
-5.:-0.1:3:3&lt;br /&gt;
-0.1:0.1:4:4&lt;br /&gt;
0.1:5.:5:5&lt;br /&gt;
5.:10.:6:6&lt;br /&gt;
10.:150000.:7:7&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: Tutorial]]&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Python]]&lt;br /&gt;
[[Category: 2016]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=FOSS4G_NA_2016:_GRASS_related_workshops_and_presentations&amp;diff=23070</id>
		<title>FOSS4G NA 2016: GRASS related workshops and presentations</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=FOSS4G_NA_2016:_GRASS_related_workshops_and_presentations&amp;diff=23070"/>
		<updated>2016-04-28T18:50:37Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Tangible landscape termite game.jpg|300px|thumb|right|Playing termites game during Coffee and Viz in NC State Hunt library (''Tangible interaction for GIS and Using GRASS GIS through Python and tangible interfaces'')]]&lt;br /&gt;
&lt;br /&gt;
[[File:Simple python editor v buffer.png|300px|thumb|right|Python interactive console and simple editor are one option how to interact with GRASS GIS (at the figure) the other is to touch it (''Using GRASS GIS through Python and tangible interfaces'')]]&lt;br /&gt;
&lt;br /&gt;
FOSS4G North America 2016, Raleigh, NC, USA, May 2-5, 2016, https://2016.foss4g-na.org/&lt;br /&gt;
&lt;br /&gt;
List of sessions labeled GRASS GIS: https://2016.foss4g-na.org/session/grass-gis&lt;br /&gt;
&lt;br /&gt;
There is also a Code Sprint and Unconference and GRASS GIS developers and users will be there.&lt;br /&gt;
&lt;br /&gt;
== Workshops ==&lt;br /&gt;
&lt;br /&gt;
* Anna Petrasova, Vaclav Petras, Brendan Harmon, Helena Mitasova (2016): ''[https://2016.foss4g-na.org/session/using-grass-gis-through-python-and-tangible-interfaces Using GRASS GIS through Python and tangible interfaces]'', FOSS4G North America 2016, Raleigh, NC, USA, May 2-5, 2016&lt;br /&gt;
** Description: Come and learn about scripting, graphical and tangible (!) interfaces for GRASS GIS, the powerful desktop GIS and geoprocessing backend. We will start with the Python interface and finish with Tangible Landscape, a new tangible interface for GRASS GIS. Python is the primary scripting language for GRASS GIS. We will demonstrate how to use Python to automate your geoprocessing workflows with GRASS GIS modules and develop custom algorithms using a Pythonic interface to access low level GRASS GIS library functions. We will also review several tips and tricks for parallelization. Tangible Landscape is an example of how the GRASS GIS Python API can be used to build new, cutting edge tools and advanced applications. Tangible Landscape is a collaborative 3D sketching tool which couples a 3D scanner, a projector and a physical 3D model with GRASS GIS. The workshop will be a truly hands-on experience – you will play with Tangible Landscape, using your hands to shape a sand model and drive geospatial processes. This workshop is open to beginners. There will be opportunities, however, to discuss more advanced topics tailored to individual interests in breakout sessions during the workshop. Participants should bring laptops with GRASS GIS 7 and their favorite Python editor. Beginners may consider using the latest OSGeo-Live virtual machine.&lt;br /&gt;
** Website: https://geospatial.ncsu.edu/osgeorel/tangible-landscape.html&lt;br /&gt;
** Workshop material: [[Using GRASS GIS through Python and tangible interfaces (workshop at FOSS4G NA 2016)|Using GRASS GIS through Python and tangible interfaces]]&lt;br /&gt;
&lt;br /&gt;
== Presentations ==&lt;br /&gt;
&lt;br /&gt;
[[File:Range on ground from north.png|300px|thumb|right|Range of z coordinates displayed on ground (''GRASS GIS loves lidar'')]]&lt;br /&gt;
[[File:Jeziorska uav grass puddle mar 18.png|300px|thumb|right|Comparison of simulated surface water flow and puddle in orthophoto (''Open the classroom window for... DRONES!'')]]&lt;br /&gt;
&lt;br /&gt;
* Brendan Harmon, Anna Petrasova, Vaclav Petras (2016): ''[https://2016.foss4g-na.org/session/tangible-interaction-gis Tangible interaction for GIS]'', Full talk in Other Cool Stuff track, FOSS4G North America 2016, Raleigh, NC, USA, May 2-5, 2016&lt;br /&gt;
** Description: Imagine being able to hold a GIS in your hands, feeling the shape of the earth, sculpting its topography, and directing the flow of water. We present Tangible Landscape, an open source tangible interface powered by GRASS GIS. Tangible Landscape physically, interactively manifests geospatial data so that you can naturally feel it, see it, and shape it. This makes GIS far more intuitive and accessible for beginners, empowers geospatial experts, and creates new exciting opportunities for developers - like gaming with GIS. In this talk we will introduce tangible interaction and why it matters for all things spatial, demonstrate a few applications such as disaster management and gaming, discuss how to digitally fabricate models, and show you how to implement and build your own system.&lt;br /&gt;
** Slides: http://baharmon.github.io/foss4g-na-2016/&lt;br /&gt;
** Website: https://geospatial.ncsu.edu/osgeorel/tangible-landscape.html&lt;br /&gt;
*  Vaclav Petras, Anna Petrasova, Helena Mitasova (2016): ''[https://2016.foss4g-na.org/session/grass-gis-loves-lidar GRASS GIS loves lidar]'', Full talk in Using FOSS4G track, FOSS4G North America 2016, Raleigh, NC, USA, May 2-5, 2016&lt;br /&gt;
** Description: Lidar and UAV measurements produce huge point clouds which cannot be handled by classic GIS tools. Not true! New GRASS GIS version offers several tools which are specifically designed for processing of lidar data and point clouds in general. Lidar devices and structure from motion (SfM) processing of UAV imagery are generating large and dense points clouds which are hard to handle as classic GIS vectors. Fortunately, GRASS GIS, a powerful desktop and backend GIS, has a selection of tools which can handle this kind of data. For example, various point cloud decimations are useful as a pre-processing step before interpolation. However, the most significant group of provided analyses uses 2D and 3D binning for highly efficient digital terrain model creation and also for various vegetation and surface analyses. Additionally, we will explore old and new ground classification techniques in GRASS GIS and which analyses PDAL has to offer in connection with GRASS GIS. In this talk we will also look at point clouds from small scanners, namely Kinect, and how these can be processed in GRASS GIS in combination with PCL to couple digital elevation models with scaled physical models. The tools available in GRASS GIS can be used through a graphical user interface or in Bash and Python scripts which can accommodate individual user workflows as well as specific developer needs. We will see how these relate and how to take advantage of all of them.&lt;br /&gt;
** Slides: http://wenzeslaus.github.io/grass-lidar-talks/&lt;br /&gt;
** Related modules: {{cmd|v.in.lidar}}, {{cmd|r.in.lidar}}, {{cmd|version=71|v.decimate}}, {{cmd|v.lidar.edgedetection}}, {{AddonCmd|v.lidar.mcc}}, ...&lt;br /&gt;
* Justyna Jeziorska, Helena Mitasova, Anna Petrasova, Vaclav Petras, Brendan Harmon (2016): ''[https://2016.foss4g-na.org/session/open-classroom-window-drones Open the classroom window for... DRONES!]'', Short talk in Education and Research track, FOSS4G North America 2016, Raleigh, NC, USA, May 2-5, 2016&lt;br /&gt;
** Description: Drones have recently moved from the battlefields to our backyards. Their use is exploding across the U.S. and the rest of the world. Engineers, photographers, journalists, surveyors, researchers and… Amazon, all speak with one voice: drones are here to stay. How does the open source software handle this attack? Can they win the battle with the proprietary solutions for geoprocessing the data from Unmanned Aerial Vehicles? We faced the problem designing innovative graduate level course “Spatiotemporal Analysis with UAV and LiDAR Data” at NC State. In this talk we will present our findings and the results of the processing combining proprietary and open source photogrammetric and GIS solutions. Turning photo imagery into very high resolution digital terrain models (couple cm/pix) gave us opportunity took the investigation various spatial phenomena on a new level. What challenges needed to be overcame for the open source to reach this level? We take our data to OpenDroneMap and Grass GIS, but why do we use proprietary software in some stages of the processing? Those are only some of the problems that we will tackle in this talk.&lt;br /&gt;
&lt;br /&gt;
== Community sprint ==&lt;br /&gt;
&lt;br /&gt;
We are meeting at the FOSS4G NA Code Sprint and Unconference on May 6 and May 7. See the dedicated [[GRASS GIS Raleigh meetups 2016|Raleigh meetups]] page for details.&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Conferences]]&lt;br /&gt;
[[Category: 2016]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=FOSS4G_NA_2016:_GRASS_related_workshops_and_presentations&amp;diff=23069</id>
		<title>FOSS4G NA 2016: GRASS related workshops and presentations</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=FOSS4G_NA_2016:_GRASS_related_workshops_and_presentations&amp;diff=23069"/>
		<updated>2016-04-28T15:38:23Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: /* Presentations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Tangible landscape termite game.jpg|300px|thumb|right|Playing termites game during Coffee and Viz in NC State Hunt library (''Tangible interaction for GIS and Using GRASS GIS through Python and tangible interfaces'')]]&lt;br /&gt;
&lt;br /&gt;
[[File:Simple python editor v buffer.png|300px|thumb|right|Python interactive console and simple editor are one option how to interact with GRASS GIS (at the figure) the other is to touch it (''Using GRASS GIS through Python and tangible interfaces'')]]&lt;br /&gt;
&lt;br /&gt;
FOSS4G North America 2016, Raleigh, NC, USA, May 2-5, 2016, https://2016.foss4g-na.org/&lt;br /&gt;
&lt;br /&gt;
List of sessions labeled GRASS GIS: https://2016.foss4g-na.org/session/grass-gis&lt;br /&gt;
&lt;br /&gt;
There is also a Code Sprint and Unconference and GRASS GIS developers and users will be there.&lt;br /&gt;
&lt;br /&gt;
== Workshops ==&lt;br /&gt;
&lt;br /&gt;
* Anna Petrasova, Vaclav Petras, Brendan Harmon, Helena Mitasova (2016): ''[https://2016.foss4g-na.org/session/using-grass-gis-through-python-and-tangible-interfaces Using GRASS GIS through Python and tangible interfaces]'', US-IALE 2016 Annual Meeting, April 3, 2016, Asheville, NC, USA, Full-day workshop&lt;br /&gt;
** Description: Come and learn about scripting, graphical and tangible (!) interfaces for GRASS GIS, the powerful desktop GIS and geoprocessing backend. We will start with the Python interface and finish with Tangible Landscape, a new tangible interface for GRASS GIS. Python is the primary scripting language for GRASS GIS. We will demonstrate how to use Python to automate your geoprocessing workflows with GRASS GIS modules and develop custom algorithms using a Pythonic interface to access low level GRASS GIS library functions. We will also review several tips and tricks for parallelization. Tangible Landscape is an example of how the GRASS GIS Python API can be used to build new, cutting edge tools and advanced applications. Tangible Landscape is a collaborative 3D sketching tool which couples a 3D scanner, a projector and a physical 3D model with GRASS GIS. The workshop will be a truly hands-on experience – you will play with Tangible Landscape, using your hands to shape a sand model and drive geospatial processes. This workshop is open to beginners. There will be opportunities, however, to discuss more advanced topics tailored to individual interests in breakout sessions during the workshop. Participants should bring laptops with GRASS GIS 7 and their favorite Python editor. Beginners may consider using the latest OSGeo-Live virtual machine.&lt;br /&gt;
** Website: https://geospatial.ncsu.edu/osgeorel/tangible-landscape.html&lt;br /&gt;
** Workshop material: [[Using GRASS GIS through Python and tangible interfaces (workshop at FOSS4G NA 2016)|Using GRASS GIS through Python and tangible interfaces]]&lt;br /&gt;
&lt;br /&gt;
== Presentations ==&lt;br /&gt;
&lt;br /&gt;
[[File:Range on ground from north.png|300px|thumb|right|Range of z coordinates displayed on ground (''GRASS GIS loves lidar'')]]&lt;br /&gt;
[[File:Jeziorska uav grass puddle mar 18.png|300px|thumb|right|Comparison of simulated surface water flow and puddle in orthophoto (''Open the classroom window for... DRONES!'')]]&lt;br /&gt;
&lt;br /&gt;
* Brendan Harmon, Anna Petrasova, Vaclav Petras (2016): ''[https://2016.foss4g-na.org/session/tangible-interaction-gis Tangible interaction for GIS]'', Full talk in Other Cool Stuff track, FOSS4G North America 2016, Raleigh, NC, USA, May 2-5, 2016&lt;br /&gt;
** Description: Imagine being able to hold a GIS in your hands, feeling the shape of the earth, sculpting its topography, and directing the flow of water. We present Tangible Landscape, an open source tangible interface powered by GRASS GIS. Tangible Landscape physically, interactively manifests geospatial data so that you can naturally feel it, see it, and shape it. This makes GIS far more intuitive and accessible for beginners, empowers geospatial experts, and creates new exciting opportunities for developers - like gaming with GIS. In this talk we will introduce tangible interaction and why it matters for all things spatial, demonstrate a few applications such as disaster management and gaming, discuss how to digitally fabricate models, and show you how to implement and build your own system.&lt;br /&gt;
** Slides: http://baharmon.github.io/foss4g-na-2016/&lt;br /&gt;
** Website: https://geospatial.ncsu.edu/osgeorel/tangible-landscape.html&lt;br /&gt;
*  Vaclav Petras, Anna Petrasova, Helena Mitasova (2016): ''[https://2016.foss4g-na.org/session/grass-gis-loves-lidar GRASS GIS loves lidar]'', Full talk in Using FOSS4G track, FOSS4G North America 2016, Raleigh, NC, USA, May 2-5, 2016&lt;br /&gt;
** Description: Lidar and UAV measurements produce huge point clouds which cannot be handled by classic GIS tools. Not true! New GRASS GIS version offers several tools which are specifically designed for processing of lidar data and point clouds in general. Lidar devices and structure from motion (SfM) processing of UAV imagery are generating large and dense points clouds which are hard to handle as classic GIS vectors. Fortunately, GRASS GIS, a powerful desktop and backend GIS, has a selection of tools which can handle this kind of data. For example, various point cloud decimations are useful as a pre-processing step before interpolation. However, the most significant group of provided analyses uses 2D and 3D binning for highly efficient digital terrain model creation and also for various vegetation and surface analyses. Additionally, we will explore old and new ground classification techniques in GRASS GIS and which analyses PDAL has to offer in connection with GRASS GIS. In this talk we will also look at point clouds from small scanners, namely Kinect, and how these can be processed in GRASS GIS in combination with PCL to couple digital elevation models with scaled physical models. The tools available in GRASS GIS can be used through a graphical user interface or in Bash and Python scripts which can accommodate individual user workflows as well as specific developer needs. We will see how these relate and how to take advantage of all of them.&lt;br /&gt;
** Slides: http://wenzeslaus.github.io/grass-lidar-talks/&lt;br /&gt;
** Related modules: {{cmd|v.in.lidar}}, {{cmd|r.in.lidar}}, {{cmd|version=71|v.decimate}}, {{cmd|v.lidar.edgedetection}}, {{AddonCmd|v.lidar.mcc}}, ...&lt;br /&gt;
* Justyna Jeziorska, Helena Mitasova, Anna Petrasova, Vaclav Petras, Brendan Harmon (2016): ''[https://2016.foss4g-na.org/session/open-classroom-window-drones Open the classroom window for... DRONES!]'', Short talk in Education and Research track, FOSS4G North America 2016, Raleigh, NC, USA, May 2-5, 2016&lt;br /&gt;
** Description: Drones have recently moved from the battlefields to our backyards. Their use is exploding across the U.S. and the rest of the world. Engineers, photographers, journalists, surveyors, researchers and… Amazon, all speak with one voice: drones are here to stay. How does the open source software handle this attack? Can they win the battle with the proprietary solutions for geoprocessing the data from Unmanned Aerial Vehicles? We faced the problem designing innovative graduate level course “Spatiotemporal Analysis with UAV and LiDAR Data” at NC State. In this talk we will present our findings and the results of the processing combining proprietary and open source photogrammetric and GIS solutions. Turning photo imagery into very high resolution digital terrain models (couple cm/pix) gave us opportunity took the investigation various spatial phenomena on a new level. What challenges needed to be overcame for the open source to reach this level? We take our data to OpenDroneMap and Grass GIS, but why do we use proprietary software in some stages of the processing? Those are only some of the problems that we will tackle in this talk.&lt;br /&gt;
&lt;br /&gt;
== Community sprint ==&lt;br /&gt;
&lt;br /&gt;
We are meeting at the FOSS4G NA Code Sprint and Unconference on May 6 and May 7. See the dedicated [[GRASS GIS Raleigh meetups 2016|Raleigh meetups]] page for details.&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Conferences]]&lt;br /&gt;
[[Category: 2016]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_GIS_Raleigh_meetups_2016&amp;diff=22979</id>
		<title>GRASS GIS Raleigh meetups 2016</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_GIS_Raleigh_meetups_2016&amp;diff=22979"/>
		<updated>2016-04-21T14:35:01Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A group of people contributing or interested in contributing to GRASS GIS met [[Christmas GRASS GIS potential contributors meeting in Raleigh|at the end of 2015 in Raleigh]], NC and decided to meet regularly in the following year. This is a page to organize meetings and to record what was done or discussed during the meetings.&lt;br /&gt;
&lt;br /&gt;
Contact person: [[User:Wenzeslaus|Vaclav Petras]] (Vashek, wenzeslaus gmail com)&lt;br /&gt;
&lt;br /&gt;
== May 6-7 ==&lt;br /&gt;
&lt;br /&gt;
[[File:Red_hat_raleigh.jpg|thumbnail|right|Red Hat Tower in Downtown Raleigh]]&lt;br /&gt;
&lt;br /&gt;
* For April and May we are meeting at [https://2016.foss4g-na.org/ FOSS4G NA] Code Sprint and Unconference.&lt;br /&gt;
* date: May 6 (Friday) - May 7 (Saturday)&lt;br /&gt;
* time: starts at 10:00am on Friday, ends at 5:00pm on Saturday&lt;br /&gt;
* place: Red Hat Inc. - 100 East Davie Street, Raleigh, NC 27601&lt;br /&gt;
* participants:&lt;br /&gt;
** Brendan Harmon&lt;br /&gt;
&lt;br /&gt;
== March 19 ==&lt;br /&gt;
&lt;br /&gt;
* date: March 19 (Saturday)&lt;br /&gt;
* time: 1:30pm - 5:30pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see below)&lt;br /&gt;
* room: 4502 The Fishbowl (note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
** Brendan Harmon&lt;br /&gt;
** Doug Newcomb&lt;br /&gt;
** Makiko Shukunobe&lt;br /&gt;
** and 3 others&lt;br /&gt;
* topics:&lt;br /&gt;
** fix {{cmd|r.in.lidar}} and large rasters ({{rev|68083}})&lt;br /&gt;
** turning a Python script into a GRASS addon module&lt;br /&gt;
** planning next two meetings in relation to [https://2016.foss4g-na.org/ FOSS4G NA 2016] which is in Raleigh on May 2-5. and related possible code sprint (May 6-7)&lt;br /&gt;
** discussing needed graphic improvements of GRASS manual pages (index, graphical index, module man page)&lt;br /&gt;
** and several other things&lt;br /&gt;
&lt;br /&gt;
== February 20 ==&lt;br /&gt;
&lt;br /&gt;
[[File:Grass gis raleigh meetup feb20 2016.png|thumbnail|right|In the Fishbowl on February 20]]&lt;br /&gt;
&lt;br /&gt;
* date: February 20 (Saturday)&lt;br /&gt;
* time: 1:30pm - 5:30pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see below)&lt;br /&gt;
* room: 4502 The Fishbowl (note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
** Makiko Shukunobe&lt;br /&gt;
** and 2 others&lt;br /&gt;
* topics: [https://grass.osgeo.org/grass64/manuals/addons/r.wind.sun.py.html r.wind.sun] port to version 7 as possible beginners topic ([https://trac.osgeo.org/grass/browser/grass-addons/grass6/raster/r.wind.sun/r.wind.sun.py?rev=67404 source code]), {{Cmd|v.overlay}} interface and possible v.clip, [https://trac.osgeo.org/grass/ticket/2663 submitting code through a ticket], GRASS GIS in QGIS, GRASS Story video ([http://dx.doi.org/10.5446/12963 HD], [https://www.youtube.com/watch?v=U3Hf0qI4JLc YouTube], [https://grass.osgeo.org/uploads/grass/history_docs/grass_movie_CERL_1987.mov MOV]), [https://2016.foss4g-na.org FOSS4G NA]&lt;br /&gt;
&lt;br /&gt;
== January 30 ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Room3208 jan30.jpg|thumb|400px|The room 3208 on January 30 with GRASS GIS logo on whiteboard to make the room easy to find]]&lt;br /&gt;
&lt;br /&gt;
* date: January 30 (moved from January 23 because of the weather)&lt;br /&gt;
* time: 1:00pm - 6:30pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see [[#Location|below]])&lt;br /&gt;
* room: 3208 (Large Group Study Room; close to the Game Lab and the wide yellow stairs; note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* food: your own supplies, [http://dining.ncsu.edu/locations/restaurants-cafes/hunt-library/ Common Grounds Café] at Hunt (closes at 5pm), [http://dining.ncsu.edu/locations/restaurants-cafes/on-the-oval/ On The Oval] (closes at 8pm)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
** Doug Newcomb&lt;br /&gt;
** Brendan Harmon&lt;br /&gt;
** Makiko Shukunobe&lt;br /&gt;
** and 2 others&lt;br /&gt;
* some of the topics:&lt;br /&gt;
** starting with Python API and running scripts in command line on Linux&lt;br /&gt;
** [[Compiling on MacOSX]] (ended up using brew because of problems with separately installed GDAL)&lt;br /&gt;
** debugging missing APPDATA on MS Windows, improved in {{rev|67709}}&lt;br /&gt;
** automated testing with Python and generating artificial data, e.g. &amp;lt;tt&amp;gt;r.mapcalc &amp;quot;plane = row()&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;r.mapcalc &amp;quot;surface = sin(2)&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
** discussing some GRASS concepts and more&lt;br /&gt;
&lt;br /&gt;
== Location ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Hunt 2015 2.jpg|thumb|400px|The Hunt Library]]&lt;br /&gt;
&lt;br /&gt;
* Raleigh, North Carolina, USA&lt;br /&gt;
* Centennial Campus of North Carolina State University&lt;br /&gt;
* [https://www.lib.ncsu.edu/huntlibrary James B. Hunt Jr. Library], 1070 Partners Way, Raleigh, NC 27606 ([http://www.openstreetmap.org/way/177166351 map])&lt;br /&gt;
** [https://www.lib.ncsu.edu/huntlibrary/explorespaces Floor plan].&lt;br /&gt;
*** The building is vertically split into two sections (library and another partially private space) and that the floor with the main desk and access to Oval is 2nd floor.&lt;br /&gt;
*** The elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can.&lt;br /&gt;
** Info about [https://www.lib.ncsu.edu/spaces/fishbowl Fishbowl]&lt;br /&gt;
** Info about [https://www.lib.ncsu.edu/spaces/group-study-rooms-large Group Study Rooms - Large]&lt;br /&gt;
* free parking on Saturdays: Oval West Parking Deck, Partners Way ([https://www.openstreetmap.org/way/164125158 map])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- https://www.lib.ncsu.edu/spaces/fishbowl --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Code Sprint]]&lt;br /&gt;
[[Category: 2016]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_GIS_Raleigh_meetups_2016&amp;diff=22612</id>
		<title>GRASS GIS Raleigh meetups 2016</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_GIS_Raleigh_meetups_2016&amp;diff=22612"/>
		<updated>2016-02-28T14:00:25Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A group of people contributing or interested in contributing to GRASS GIS met [[Christmas GRASS GIS potential contributors meeting in Raleigh|at the end of 2015 in Raleigh]], NC and decided to meet regularly in the following year. This is a page to organize meetings and to record what was done or discussed during the meetings.&lt;br /&gt;
&lt;br /&gt;
Contact person: [[User:Wenzeslaus|Vaclav Petras]] (Vashek, wenzeslaus gmail com)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== March 19 ==&lt;br /&gt;
&lt;br /&gt;
* date: March 19 (Saturday)&lt;br /&gt;
* time: 1:30pm - 5:30pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see below)&lt;br /&gt;
* room: 4502 The Fishbowl (note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
** Brendan Harmon&lt;br /&gt;
** ... ''(add yourself)&lt;br /&gt;
* topics proposed so far: getting your Python script to the GRASS GIS Addons repository, ... ''(add topic you are interested in)''&lt;br /&gt;
&lt;br /&gt;
== February 20 ==&lt;br /&gt;
&lt;br /&gt;
[[File:Grass gis raleigh meetup feb20 2016.png|thumbnail|right|In the Fisbow on February 20]]&lt;br /&gt;
&lt;br /&gt;
* date: February 20 (Saturday)&lt;br /&gt;
* time: 1:30pm - 5:30pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see below)&lt;br /&gt;
* room: 4502 The Fishbowl (note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
** Makiko Shukunobe&lt;br /&gt;
** and 2 others&lt;br /&gt;
* topics: [https://grass.osgeo.org/grass64/manuals/addons/r.wind.sun.py.html r.wind.sun] port to version 7 as possible beginners topic ([https://trac.osgeo.org/grass/browser/grass-addons/grass6/raster/r.wind.sun/r.wind.sun.py?rev=67404 source code]), {{Cmd|v.overlay}} interface and possible v.clip, [https://trac.osgeo.org/grass/ticket/2663 submitting code through a ticket], GRASS GIS in QGIS, GRASS Story video ([http://dx.doi.org/10.5446/12963 HD], [https://www.youtube.com/watch?v=U3Hf0qI4JLc YouTube], [https://grass.osgeo.org/uploads/grass/history_docs/grass_movie_CERL_1987.mov MOV]), [https://2016.foss4g-na.org FOSS4G NA]&lt;br /&gt;
&lt;br /&gt;
== January 30 ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Room3208 jan30.jpg|thumb|400px|The room 3208 on January 30 with GRASS GIS logo on whiteboard to make the room easy to find]]&lt;br /&gt;
&lt;br /&gt;
* date: January 30 (moved from January 23 because of the weather)&lt;br /&gt;
* time: 1:00pm - 6:30pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt library (see [[#Location|below]])&lt;br /&gt;
* room: 3208 (Large Group Study Room; close to the Game Lab and the wide yellow stairs; note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* food: your own supplies, [http://dining.ncsu.edu/locations/restaurants-cafes/hunt-library/ Common Grounds Café] at Hunt (closes at 5pm), [http://dining.ncsu.edu/locations/restaurants-cafes/on-the-oval/ On The Oval] (closes at 8pm)&lt;br /&gt;
* participants:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
** Doug Newcomb&lt;br /&gt;
** Brendan Harmon&lt;br /&gt;
** Makiko Shukunobe&lt;br /&gt;
** and 2 others&lt;br /&gt;
* some of the topics:&lt;br /&gt;
** starting with Python API and running scripts in command line on Linux&lt;br /&gt;
** [[Compiling on MacOSX]] (ended up using brew because of problems with separately installed GDAL)&lt;br /&gt;
** debugging missing APPDATA on MS Windows, improved in {{rev|67709}}&lt;br /&gt;
** automated testing with Python and generating artificial data, e.g. &amp;lt;tt&amp;gt;r.mapcalc &amp;quot;plane = row()&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;r.mapcalc &amp;quot;surface = sin(2)&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
** discussing some GRASS concepts and more&lt;br /&gt;
&lt;br /&gt;
== Location ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Hunt 2015 2.jpg|thumb|400px|The Hunt Library]]&lt;br /&gt;
&lt;br /&gt;
* Raleigh, North Carolina, USA&lt;br /&gt;
* Centennial Campus of North Carolina State University&lt;br /&gt;
* [https://www.lib.ncsu.edu/huntlibrary James B. Hunt Jr. Library], 1070 Partners Way, Raleigh, NC 27606 ([http://www.openstreetmap.org/way/177166351 map])&lt;br /&gt;
** [https://www.lib.ncsu.edu/huntlibrary/explorespaces Floor plan] (note that building is vertically split into two sections (library and another partially private space) and that the floor with the main desk and access to Oval is 2nd floor)&lt;br /&gt;
** Info about [https://www.lib.ncsu.edu/spaces/group-study-rooms-large Group Study Rooms - Large]&lt;br /&gt;
* free parking on Saturdays: Oval West Parking Deck, Partners Way ([https://www.openstreetmap.org/way/164125158 map])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- https://www.lib.ncsu.edu/spaces/fishbowl --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Code Sprint]]&lt;br /&gt;
[[Category: 2016]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=GRASS_GIS_Raleigh_meetups_2016&amp;diff=22305</id>
		<title>GRASS GIS Raleigh meetups 2016</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=GRASS_GIS_Raleigh_meetups_2016&amp;diff=22305"/>
		<updated>2016-01-29T20:01:55Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: Added name&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A group of people contributing or interested in contributing to GRASS GIS met [[Christmas GRASS GIS potential contributors meeting in Raleigh|at the end of 2015 in Raleigh]] and decided to meet regularly in the following months. This is a page to organize meetings and record what was done or discussed during them&lt;br /&gt;
&lt;br /&gt;
Contact person: [[User:Wenzeslaus|Vaclav Petras (Vashek, wenzeslaus gmail com)]]&lt;br /&gt;
&lt;br /&gt;
== January 30 ==&lt;br /&gt;
&lt;br /&gt;
* date: January 30 (moved from January 23 because of the weather)&lt;br /&gt;
* time: 1:00pm - 6:30pm (feel free to come and leave anytime)&lt;br /&gt;
* place: Hunt (see [[#Location|below]])&lt;br /&gt;
* food: your own supplies, [http://dining.ncsu.edu/locations/restaurants-cafes/hunt-library/ Common Grounds Café] at Hunt (closes at 5pm), [http://dining.ncsu.edu/locations/restaurants-cafes/on-the-oval/ On The Oval] (closes at 8pm)&lt;br /&gt;
* room: 3208 (Large Group Study Room; close to the Game Lab and the wide yellow stairs; note that the elevator from the 1st floor will take you just to the 2nd floor, use the stairs if you can)&lt;br /&gt;
* coming:&lt;br /&gt;
** Vaclav Petras&lt;br /&gt;
** Anna Petrasova&lt;br /&gt;
** Doug Newcomb&lt;br /&gt;
** Brendan Harmon&lt;br /&gt;
&lt;br /&gt;
== Location ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Hunt 2015 2.jpg|thumb|400px]]&lt;br /&gt;
&lt;br /&gt;
* Raleigh, North Carolina, USA&lt;br /&gt;
* Centennial Campus of North Carolina State University&lt;br /&gt;
* [https://www.lib.ncsu.edu/huntlibrary James B. Hunt Jr. Library], 1070 Partners Way, Raleigh, NC 27606 ([http://www.openstreetmap.org/way/177166351 map])&lt;br /&gt;
** [https://www.lib.ncsu.edu/huntlibrary/explorespaces Floor plan] (note that building is vertically split into two sections (library and another partially private space) and that the floor with the main desk and access to Oval is 2nd floor)&lt;br /&gt;
** Info about [https://www.lib.ncsu.edu/spaces/group-study-rooms-large Group Study Rooms - Large]&lt;br /&gt;
* free parking on Saturdays: Oval West Parking Deck, Partners Way ([https://www.openstreetmap.org/way/164125158 map])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- https://www.lib.ncsu.edu/spaces/fishbowl --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Code Sprint]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Christmas_GRASS_GIS_potential_contributors_meeting_in_Raleigh&amp;diff=22223</id>
		<title>Christmas GRASS GIS potential contributors meeting in Raleigh</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Christmas_GRASS_GIS_potential_contributors_meeting_in_Raleigh&amp;diff=22223"/>
		<updated>2015-12-30T22:29:09Z</updated>

		<summary type="html">&lt;p&gt;⚠️Baharmon: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:Hunt fishbowl 2015 1.jpg|thumb|400px]]&lt;br /&gt;
[[Image:Hunt 2015 2.jpg|thumb|400px]]&lt;br /&gt;
&lt;br /&gt;
A group of people contributing or interested in contributing to GRASS GIS met on December 19, 2015 at the Hunt library, which is a quite inspiring place located on NC State University Centennial campus.&lt;br /&gt;
&lt;br /&gt;
Contact person: [[User:Wenzeslaus|Vaclav Petras (Vashek)]]&lt;br /&gt;
&lt;br /&gt;
== Discussed topics ==&lt;br /&gt;
&lt;br /&gt;
* How tickets work, example: [https://trac.osgeo.org/grass/ticket/2750 #2750]&lt;br /&gt;
* [https://github.com/wenzeslaus/python-grass-addon/blob/master/04_script_to_grass_module.ipynb Writing a GRASS module]&lt;br /&gt;
** [https://trac.osgeo.org/grass/browser/grass/trunk/scripts/r.shade Example Python module (r.shade)]&lt;br /&gt;
** [https://trac.osgeo.org/grass/browser/grass/trunk/raster/r.patch Example C module (r.patch)]&lt;br /&gt;
* [http://gis.stackexchange.com/questions/172162/grass-gis-number-of-cpu-cores-to-use/173555#173555 Parallelizing (GIS SE)], [[Parallelizing Scripts]], [[Parallel GRASS jobs]], [[OpenMP]]&lt;br /&gt;
* [https://grass.osgeo.org/support/mailing-lists/ Mailing list]&lt;br /&gt;
* [https://grass.osgeo.org/documentation/manuals/ Manuals]&lt;br /&gt;
* Review and testing&lt;br /&gt;
** Continuous integration (builds) on [https://travis-ci.org/GRASS-GIS/grass-ci/builds Travis]&lt;br /&gt;
** Automated testing ([http://fatra.cnr.ncsu.edu/grassgistests/ results on NCSU server fatra], [http://fatra.cnr.ncsu.edu/grassgistests/reports_for_date-2015-12-19-08-00/report_for_nc_basic_spm_grass7_nc/testfiles.html example result for one day], [https://grass.osgeo.org/grass71/manuals/libpython/gunittest_testing.html documenation])&lt;br /&gt;
*** [https://trac.osgeo.org/grass/changeset/65145 example test contribution]&lt;br /&gt;
** [https://trac.osgeo.org/grass/timeline GRASS GIS Trac Timeline]&lt;br /&gt;
** Example of file history: wxGUI mapcalc [https://trac.osgeo.org/grass/log/grass/trunk/gui/wxpython/modules/mcalc_builder.py change log] and [https://trac.osgeo.org/grass/browser/grass/trunk/gui/wxpython/modules/mcalc_builder.py?annotate=blame authorship per line]&lt;br /&gt;
** [https://www.openhub.net/p/grass_gis Open Hub statistics]&lt;br /&gt;
* GRASS GIS Database with maps in native format versus linked files, e.g. using [https://grass.osgeo.org/grass71/manuals/r.external.html r.external]&lt;br /&gt;
* [https://grass.osgeo.org/download/logos/ Logo resources]&lt;br /&gt;
* Installation versus compilation on Ubuntu&lt;br /&gt;
** [https://grass.osgeo.org/download/software/linux/ installation from PPA]&lt;br /&gt;
* Suggestion for starting with C development&lt;br /&gt;
** fix [https://grass.osgeo.org/grass71/manuals/r.cross.html r.cross] problems when overlaying layers with no-data [https://trac.osgeo.org/grass/ticket/1674 #1674]&lt;br /&gt;
** fix [https://trac.osgeo.org/grass/ticket/2310 #2310]&lt;br /&gt;
** Some modules are setting color tables which are the same as the predefined ones available through r.colors but these modules have the values hardcoded, thus causing duplication (e.g. [https://trac.osgeo.org/grass/browser/grass/trunk/lib/rst/interp_float/output2d.c#L214 v.surf.rst in lib/rst] and [https://trac.osgeo.org/grass/browser/grass/trunk/raster/r.slope.aspect/main.c#L1054 r.slope.aspect]). Solution is to move the code for creating color tables from the r.color module to the library.&lt;br /&gt;
&lt;br /&gt;
== Participants ==&lt;br /&gt;
&lt;br /&gt;
* Vaclav Petras (Vashek)&lt;br /&gt;
* Anna Petrasova&lt;br /&gt;
* Michael Reno&lt;br /&gt;
* Makiko Shukunobe&lt;br /&gt;
* Brendan Harmon&lt;br /&gt;
* and 2 others&lt;br /&gt;
&lt;br /&gt;
== Location ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Hunt 2015 1.jpg|thumb|200px]]&lt;br /&gt;
&lt;br /&gt;
* Raleigh, North Carolina, USA&lt;br /&gt;
* [https://www.lib.ncsu.edu/huntlibrary James B. Hunt Jr. Library], 1070 Partners Way, Raleigh, NC 27606 ([http://www.openstreetmap.org/way/177166351 map])&lt;br /&gt;
* free parking (Saturdays): Oval West Parking Deck, Partners Way ([https://www.openstreetmap.org/way/164125158 map])&lt;br /&gt;
&lt;br /&gt;
== Press release ==&lt;br /&gt;
&lt;br /&gt;
''Prepared upon request from the [http://www.geoforall.org/newsletters/ GeoForAll Newsletter] (international audience).''&lt;br /&gt;
&lt;br /&gt;
The local GRASS GIS community in Raleigh, North Carolina, USA is pleased to announce a successful meeting, held on Saturday December 19, 2015, dedicated to learning about how to contribute to GRASS GIS. The meeting took place at the inspiring James B. Hunt Jr. Library at the North Carolina State University Centennial Campus. Though it is true that a libre and open source project such as GRASS GIS necessitates many types of non-coding contributions, including documentation and tests, this event focused on describing the tools and processes associated with making contributions to the codebase itself.  Bug fixes and enhancements, both in C and Python, were generally considered.  These themes and others will continue to be discussed at the first follow up meeting of 2016, planned for late January.&lt;br /&gt;
&lt;br /&gt;
== Photos ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Hunt fishbowl 2015 3.jpg|center|thumb|400px]]&lt;br /&gt;
[[Image:Hunt fishbowl 2015 2.jpg|center|thumb|400px]]&lt;br /&gt;
&lt;br /&gt;
For higher resolution images contact [[User:Wenzeslaus|Vaclav Petras]].&lt;br /&gt;
&lt;br /&gt;
[[Category: Workshops]]&lt;br /&gt;
[[Category: Code Sprint]]&lt;/div&gt;</summary>
		<author><name>⚠️Baharmon</name></author>
	</entry>
</feed>