Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: make sure every plot can be called without ax paramaters #365

Merged
merged 5 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added docs/_static/usage/plot/index/histogram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/usage/plot/index/hydroshed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@
autoapi_keep_files = False

# -- Options for intersphinx output --------------------------------------------
intersphinx_mapping = {}
intersphinx_mapping = {
"matplotlib": ("https://matplotlib.org/stable/", None),
}

# -- options for the autolabel extension ---------------------------------------
autosectionlabel_prefix_document = True
Expand Down
91 changes: 89 additions & 2 deletions docs/usage/plot/index.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,99 @@
Plotting
========

We embed some plotting capabilities in the library to help you visualize your data.
We embed some plotting capabilities in the library to help you visualize your data. For simplicity we decided to map all the plotting function to the :doc:`matplotlib <matplotlib:index>` library as it's the most used static plotting library in the Python ecosystem.

.. toctree::
:hidden:
:maxdepth: 1

plot-featurecollection
plot-image
plot-imagecollection
map-image
map-featurecollection
map-featurecollection

.. grid:: 1 2 3 3

.. grid-item::

.. card:: :icon:`fa-solid fa-chart-simple` FeatureCollection
:link: plot-featurecollection.html

.. grid-item::

.. card:: :icon:`fa-solid fa-chart-simple` Image
:link: plot-image.html

.. grid-item::

.. card:: :icon:`fa-solid fa-chart-simple` ImageCollection
:link: plot-imagecollection.html

.. grid-item::

.. card:: :icon:`fa-solid fa-image` Image
:link: map-image.html

.. grid-item::

.. card:: :icon:`fa-solid fa-map` FeatureCollection
:link: map-featurecollection.html



In all these examples we will use the object interface of matplotlib creating the :py:class:`Figure <matplotlib.figure.Figure>` and :py:class:`Axes <matplotlib.axes.Axes>` object before plotting the data. This is the recommended way to use matplotlib as it gives you more control over the plot and the figure.

.. code-block:: python

# custom image for this specific chart
modisSr = (
ee.ImageCollection("MODIS/061/MOD09A1")
.filter(ee.Filter.date("2018-06-01", "2018-09-01"))
.select(["sur_refl_b01", "sur_refl_b02", "sur_refl_b06"])
.mean()
)
histRegion = ee.Geometry.Rectangle([-112.60, 40.60, -111.18, 41.22])

#create a matplotlib figure
fig, ax = plt.subplots(figsize=(10, 4))

# plot the histogram of the reds
modisSr.geetools.plot_hist(
bands = ["sur_refl_b01", "sur_refl_b02", "sur_refl_b06"],
labels = [['Red', 'NIR', 'SWIR']],
colors = ["#cf513e", "#1d6b99", "#f0af07"],
ax = ax,
bins = 100,
scale = 500,
region = histRegion,
)

# once created the axes can be modified as needed using pure matplotlib functions
ax.set_title("Modis SR Reflectance Histogram")
ax.set_xlabel("Reflectance (x1e4)")

.. image:: ../../_static/usage/plot/index/histogram.png
:alt: Modis SR Reflectance Histogram
:align: center

If you are used to the :py:mod:`pyplot <matplotlib.pyplot>` interface of matplotlib you can still use it with the state-base module of matplotlib. Just be aware that the module is a stateful interface and you will have less control over the figure and the plot.

.. code-block:: python

# get all hydroshed from the the south amercias within the WWF/HydroATLAS dataset.
region = ee.Geometry.BBox(-80, -60, -20, 20);
fc = ee.FeatureCollection('WWF/HydroATLAS/v1/Basins/level04').filterBounds(region)

# create the plot
fc.geetools.plot(property="UP_AREA", cmap="viridis")

# Customized display
plt.colorbar(ax.collections[0], label="Upstream area (km²)")
plt.title("HydroATLAS basins of level4")
plt.xlabel("Longitude (°)")
plt.ylabel("Latitude (°)")

.. image:: ../../_static/usage/plot/index/hydroshed.png
:alt: HydroATLAS basins of level4
:align: center
88 changes: 17 additions & 71 deletions docs/usage/plot/map-featurecollection.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -115,46 +115,13 @@
"\n",
"A single property can be ploted on a map using matplotlib. The following example is showing the bassin area in km².\n",
"\n",
"First create a matplotlib figure and axis:\n"
"First create a matplotlib figure and axis, then you can add the bassins to the map using the `plot` method. By default it will display the first property of the features. In our case we will opt to display the area of the bassins in km² i.e. the \"UP_AREA\" property. Finally that we have the plot, we can customize it with matplotlib. For example, we can add a title and a colorbar."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"plt.ioff() # remove interactive for the sake of the example\n",
"fig, ax = plt.subplots(figsize=(10, 10))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then you can add the bassins to the map using the `plot` method. By default it will display the first property of the features. In our case we will opt to display the area of the bassins in km² i.e. the \"UP_AREA\" property."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"fc.geetools.plot(ax=ax, property=\"UP_AREA\", cmap=\"viridis\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that we have the plot, we can customize it with matplotlib. For example, we can add a title and a colorbar."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
Expand All @@ -168,13 +135,19 @@
}
],
"source": [
"# create the plot\n",
"fig, ax = plt.subplots(figsize=(10, 10))\n",
"\n",
"# generate the graph\n",
"fc.geetools.plot(ax=ax, property=\"UP_AREA\", cmap=\"viridis\")\n",
"\n",
"# you can then customize the figure as you would for any other matplotlib object\n",
"fig.colorbar(ax.collections[0], label=\"Upstream area (km²)\")\n",
"ax.set_title(\"HydroATLAS basins of level4\")\n",
"ax.set_xlabel(\"Longitude (°)\")\n",
"ax.set_ylabel(\"Latitude (°)\")\n",
"\n",
"display(fig)"
"plt.show()"
]
},
{
Expand All @@ -185,45 +158,12 @@
"\n",
"Alternatively if you only want to plot the geometries of the featurecollection on a map, you can use the `plot` method with the `boundares` parameter set to `True`.\n",
"\n",
"Similarly to the previous example we start by creating a pyplot figure and axis:"
"Similarly to the previous example we start by creating a pyplot figure and axis, then you can start plotting the geometries and finally customize the plot."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"plt.ioff() # remove interactive for the sake of the example\n",
"fig, ax = plt.subplots(figsize=(10, 10))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then you can start plotting the geometries:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"fc.geetools.plot(ax=ax, boundaries=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"and finally customize the plot:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 7,
"metadata": {},
"outputs": [
{
Expand All @@ -238,12 +178,18 @@
}
],
"source": [
"plt.ioff() # remove interactive for the sake of the example\n",
"fig, ax = plt.subplots(figsize=(10, 10))\n",
"\n",
"# create the graph\n",
"fc.geetools.plot(ax=ax, boundaries=True)\n",
"\n",
"# you can then customize the figure as you would for any other matplotlib object\n",
"ax.set_title(\"Borders of the HydroATLAS basins of level4\")\n",
"ax.set_xlabel(\"Longitude (°)\")\n",
"ax.set_ylabel(\"Latitude (°)\")\n",
"\n",
"display(fig)"
"plt.show()"
]
},
{
Expand Down
137 changes: 37 additions & 100 deletions docs/usage/plot/map-image.ipynb

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion geetools/ee_feature_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ def plot_hist(

def plot(
self,
ax: Axes,
ax: Axes | None = None,
property: str = "",
crs: str = "EPSG:4326",
cmap: str = "viridis",
Expand Down Expand Up @@ -460,6 +460,9 @@ def plot(
fig, ax = plt.subplots()
fc.geetools.plot("ADM2_CODE", ax)
"""
if ax is None:
fig, ax = plt.subplots()

# get the data from the server
names = self._obj.first().propertyNames()
names = names.filter(ee.Filter.stringStartsWith("item", "system:").Not())
Expand Down
Loading