Skip to content

Commit

Permalink
Merge pull request #553 from 3r3n-n/add-feature-histogram-function
Browse files Browse the repository at this point in the history
add feature_histogram() function
  • Loading branch information
giswqs authored Jul 5, 2021
2 parents ff20723 + b51fe47 commit 53bca28
Show file tree
Hide file tree
Showing 4 changed files with 327 additions and 5 deletions.
Binary file added .DS_Store
Binary file not shown.
Binary file added examples/.DS_Store
Binary file not shown.
196 changes: 196 additions & 0 deletions examples/notebooks/79_chart_histogram.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "c8e4fe74-fe9f-4cab-a0b0-b7a9a11ebd3b",
"metadata": {},
"source": [
"[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/giswqs/geemap/blob/master/examples/notebooks/79_chart_histogram.ipynb)"
]
},
{
"cell_type": "markdown",
"id": "5f731179-ca4f-43be-88e3-71801aa4b08f",
"metadata": {},
"source": [
"Uncomment the following line to install [geemap](https://geemap.org) if needed."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "32fb1f00-46b6-4dc6-be1f-948a627b74df",
"metadata": {},
"outputs": [],
"source": [
"# !pip install geemap"
]
},
{
"cell_type": "markdown",
"id": "956a608f-829c-4bd2-950a-4019c4b5a686",
"metadata": {},
"source": [
"Install the necessary libraries."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0b9c023d-0fcc-4911-b08a-708900a67af9",
"metadata": {},
"outputs": [],
"source": [
"import ee\n",
"import geemap\n",
"import geemap.chart as chart"
]
},
{
"cell_type": "markdown",
"id": "d5436f2d-721c-405e-85fd-ff3d49788ff1",
"metadata": {},
"source": [
"Initialize GEE."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e9c39bdc-b8c1-468a-878c-83e5a1d61a64",
"metadata": {},
"outputs": [],
"source": [
"ee.Initialize()"
]
},
{
"cell_type": "markdown",
"id": "ebcba2d6-8a64-48d6-bf7e-d7f8ac2ce735",
"metadata": {},
"source": [
"Set the data and plot options."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fbe7052a-be33-48ae-83c9-d65ce902c4bc",
"metadata": {},
"outputs": [],
"source": [
"source = ee.ImageCollection('OREGONSTATE/PRISM/Norm81m').toBands()\n",
"region = ee.Geometry.Rectangle(-123.41, 40.43, -116.38, 45.14)\n",
"my_sample = source.sample(region, 5000)\n",
"property = '07_ppt'"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "92ff81dd-ef42-4e4c-ac9c-0cc7c20a5631",
"metadata": {},
"outputs": [],
"source": [
"options = {\"title\": 'July Precipitation Distribution for NW USA',\n",
" \"xlabel\": 'Precipitation (mm)',\n",
" \"ylabel\": 'Pixel count',\n",
" \"colors\": ['#1d6b99']\n",
" }"
]
},
{
"cell_type": "markdown",
"id": "a337adcf-10ff-470b-b7eb-93b767215158",
"metadata": {},
"source": [
"Generate histogram with default number of bins:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "304b9c4b-5eb5-4ace-8903-340ad03e2d67",
"metadata": {},
"outputs": [],
"source": [
"chart.feature_histogram(my_sample, property, **options)"
]
},
{
"cell_type": "markdown",
"id": "7dd9d9fa-7a68-4eb8-a468-a703798c0cc6",
"metadata": {},
"source": [
"Generate histogram and set a maximum number of bins:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e64a479e-5805-4ef9-85a5-63e5d4089e3e",
"metadata": {},
"outputs": [],
"source": [
"chart.feature_histogram(my_sample, property, maxBuckets = 30, **options)"
]
},
{
"cell_type": "markdown",
"id": "78306cd7-17d5-4308-80ed-e6871c37a113",
"metadata": {},
"source": [
"Generate histogram and set a minimum bin size:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b460444e-7c99-4317-98e7-6165e933e58a",
"metadata": {},
"outputs": [],
"source": [
"chart.feature_histogram(my_sample, property, minBucketWidth = 0.5, **options)"
]
},
{
"cell_type": "markdown",
"id": "a6302898-bd41-4603-898a-c74858687b53",
"metadata": {},
"source": [
"Generate histogram, set a maximum number of bins and a minimum bin size:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2b3a462b-d4f6-4061-acf3-0c26ef718a12",
"metadata": {},
"outputs": [],
"source": [
"chart.feature_histogram(my_sample, property, minBucketWidth = 3, maxBuckets = 30, **options)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
136 changes: 131 additions & 5 deletions geemap/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,11 @@ def feature_groups(features, xProperty, yProperty, seriesProperty, **kwargs):
Plots the value of one property for each feature.
Reference:
https://developers.google.com/earth-engine/guides/charts_feature#uichartfeaturegroups
Args:
features (ee.FeatureCollection): The feature collection to make a chart from.
xProperty (str): Features labeled by xProperty.
yProperty (str): Features labeled by yProperty.
seriesProperty (str): The property used to label each feature in the legend.
Raises:
Exception: Errors when creating the chart.
"""
Expand Down Expand Up @@ -275,9 +273,137 @@ def feature_groups(features, xProperty, yProperty, seriesProperty, **kwargs):
raise Exception(e)


def feature_histogram(features, property, maxBuckets, minBucketWidth, maxRaw, **kwargs):
# TODO
pass

def feature_histogram(features, property, maxBuckets=None, minBucketWidth=None, **kwargs):
"""
Generates a Chart from a set of features.
Computes and plots a histogram of the given property.
- X-axis = Histogram buckets (of property value).
- Y-axis = Frequency
Reference:
https://developers.google.com/earth-engine/guides/charts_feature#uichartfeaturehistogram
Args:
features (ee.FeatureCollection): The features to include in the chart.
property (str): The name of the property to generate the histogram for.
maxBuckets (int, optional): The maximum number of buckets (bins) to use when building a histogram;
will be rounded up to a power of 2.
minBucketWidth (float, optional): The minimum histogram bucket width, or null to allow any power of 2.
Raises:
Exception: If the provided xProperties is not a list or dict.
Exception: If the chart fails to create.
"""
import math

def nextPowerOf2(n):
return pow(2, math.ceil(math.log2(n)))

def grow_bin(bin_size,ref):
while bin_size < ref:
bin_size *= 2
return bin_size

try:

raw_data = pd.to_numeric(pd.Series(features.aggregate_array(property).getInfo()))
y_data = raw_data.tolist()

if "ylim" in kwargs:
min_value = kwargs["ylim"][0]
max_value = kwargs["ylim"][1]
else:
min_value = raw_data.min()
max_value = raw_data.max()

data_range = max_value - min_value

if not maxBuckets:
initial_bin_size = nextPowerOf2(data_range / pow(2,8))
if minBucketWidth:
if minBucketWidth < initial_bin_size:
bin_size = grow_bin(minBucketWidth,initial_bin_size)
else:
bin_size = minBucketWidth
else:
bin_size = initial_bin_size
else:
initial_bin_size = math.ceil(data_range / nextPowerOf2(maxBuckets))
if minBucketWidth:
if minBucketWidth < initial_bin_size:
bin_size = grow_bin(minBucketWidth,initial_bin_size)
else:
bin_size = minBucketWidth
else:
bin_size = initial_bin_size

start_bins = (math.floor(min_value / bin_size) * bin_size) - (bin_size/2)
end_bins = (math.ceil(max_value / bin_size) * bin_size) + (bin_size/2)

if start_bins < min_value:
y_data.append(start_bins)
else:
y_data[y_data.index(min_value)] = start_bins
if end_bins > max_value:
y_data.append(end_bins)
else:
y_data[y_data.index(max_value)] = end_bins

num_bins = math.floor((end_bins - start_bins) / bin_size)

if "title" not in kwargs:
title = ""
else:
title = kwargs["title"]

fig = plt.figure(title=title)

if "width" in kwargs:
fig.layout.width = kwargs["width"]
if "height" in kwargs:
fig.layout.height = kwargs["height"]

if "xlabel" not in kwargs:
xlabel=""
else:
xlabel= kwargs["xlabel"]

if "ylabel" not in kwargs:
ylabel=""
else:
ylabel= kwargs["ylabel"]

histogram = plt.hist(
sample = y_data,
bins=num_bins,
axes_options={
'count':{'label':ylabel},
'sample':{'label':xlabel}
}
)

if "colors" in kwargs:
histogram.colors = kwargs["colors"]
if "stroke" in kwargs:
histogram.stroke = kwargs["stroke"]
else:
histogram.stroke = "#ffffff00"
if "stroke_width" in kwargs:
histogram.stroke_width = kwargs["stroke_width"]
else:
histogram.stroke_width = 0

if ("xlabel" in kwargs) and ("ylabel" in kwargs):
histogram.tooltip = Tooltip(
fields=["midpoint", "count"], labels=[kwargs["xlabel"], kwargs["ylabel"]]
)
else:
histogram.tooltip = Tooltip(fields=["midpoint", "count"])
plt.show()

except Exception as e:
raise Exception(e)


def image_byClass(
Expand Down

0 comments on commit 53bca28

Please sign in to comment.