display.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. # MODULE: grass.jupyter.display
  2. #
  3. # AUTHOR(S): Caitlin Haedrich <caitlin DOT haedrich AT gmail>
  4. #
  5. # PURPOSE: This module contains functions for non-interactive display
  6. # in Jupyter Notebooks
  7. #
  8. # COPYRIGHT: (C) 2021 Caitlin Haedrich, and by the GRASS Development Team
  9. #
  10. # This program is free software under the GNU General Public
  11. # License (>=v2). Read the file COPYING that comes with GRASS
  12. # for details.
  13. import os
  14. import shutil
  15. from pathlib import Path
  16. from IPython.display import Image
  17. import grass.script as gs
  18. class GrassRenderer:
  19. """GrassRenderer creates and displays GRASS maps in
  20. Jupyter Notebooks.
  21. Elements are added to the display by calling GRASS display modules.
  22. Basic usage::
  23. >>> m = GrassRenderer()
  24. >>> m.run("d.rast", map="elevation")
  25. >>> m.run("d.legend", raster="elevation")
  26. >>> m.show()
  27. GRASS display modules can also be called by using the name of module
  28. as a class method and replacing "." with "_" in the name.
  29. Shortcut usage::
  30. >>> m = GrassRenderer()
  31. >>> m.d_rast(map="elevation")
  32. >>> m.d_legend(raster="elevation")
  33. >>> m.show()
  34. """
  35. def __init__(
  36. self, env=None, width=600, height=400, filename="map.png", text_size=12
  37. ):
  38. """Creates an instance of the GrassRenderer class.
  39. :param int height: height of map in pixels
  40. :param int width: width of map in pixels
  41. :param str filename: filename or path to save a PNG of map
  42. :param str env: environment
  43. :param int text_size: default text size, overwritten by most display modules
  44. :param renderer: GRASS renderer driver (options: cairo, png, ps, html)
  45. """
  46. if env:
  47. self._env = env.copy()
  48. else:
  49. self._env = os.environ.copy()
  50. self._env["GRASS_RENDER_WIDTH"] = str(width)
  51. self._env["GRASS_RENDER_HEIGHT"] = str(height)
  52. self._env["GRASS_RENDER_TEXT_SIZE"] = str(text_size)
  53. self._env["GRASS_RENDER_IMMEDIATE"] = "cairo"
  54. self._env["GRASS_RENDER_FILE"] = str(filename)
  55. self._env["GRASS_RENDER_FILE_READ"] = "TRUE"
  56. self._legend_file = Path(filename).with_suffix(".grass_vector_legend")
  57. self._env["GRASS_LEGEND_FILE"] = str(self._legend_file)
  58. self._filename = filename
  59. self.run("d.erase")
  60. def run(self, module, **kwargs):
  61. """Run modules from "d." GRASS library"""
  62. # Check module is from display library then run
  63. if module[0] == "d":
  64. gs.run_command(module, env=self._env, **kwargs)
  65. else:
  66. raise ValueError("Module must begin with letter 'd'.")
  67. def __getattr__(self, name):
  68. """Parse attribute to GRASS display module. Attribute should be in
  69. the form 'd_module_name'. For example, 'd.rast' is called with 'd_rast'.
  70. """
  71. # Check to make sure format is correct
  72. if not name.startswith("d_"):
  73. raise AttributeError(_("Module must begin with 'd_'"))
  74. # Reformat string
  75. grass_module = name.replace("_", ".")
  76. # Assert module exists
  77. if not shutil.which(grass_module):
  78. raise AttributeError(_("Cannot find GRASS module {}").format(grass_module))
  79. def wrapper(**kwargs):
  80. # Run module
  81. self.run(grass_module, **kwargs)
  82. return wrapper
  83. def show(self):
  84. """Displays a PNG image of the map"""
  85. return Image(self._filename)