How can I find all the lakes in a region (bounded by polgon) in earth engine? - google-earth

The problem statement is that a region of interest is given.
I need to find all the lakes in a polygon bounded region using the NDWI index for water bodies, which are at a height of more than 1500m. Then display the changes in the area of lake's surface water starting from the year 1984 till 2018 on a 2-year interval in a table like structure in Google Earth Engine. I have used Landsat 5 and 7 data.
I have created the following code:
Earth Engine Code
Now I need to display the results in the polygon marked region in a table sort of structure in the following format:-
Rows - (Lake 1, Lake 2, Lake 3... Lake n)
Columns - (Surface Area in 1984, Surface Area in 1986, ....2018)
How should I go about doing it?

I answer this question in regard of the code posted in the comments, hopefully the question is updated with the code posted in the comments.
Filtering: ok.
Just a comment, I wouldn't name an image collection variable with name img, it's just confusing to me, but variables names are up to you.
var mf = ee.Filter.calendarRange(10, 12, 'month');
var img1 = ee.ImageCollection(l5
.filterDate('1984-01-01','1999-12-31')
.filterBounds(roi)
.filter(mf));
var img2 = ee.ImageCollection(l7
.filterDate('2000-01-01','2018-12-31')
.filterBounds(roi)
.filter(mf));
add NDWI: This is your code:
var addNDWI = function(image){
var ndwi = image.normalizedDifference(['B2', 'B4']).rename('NDWI');
var ndwiMask = ndwi.gte(0.3);
return image.addBands(ndwi);
};
var image1 = img1.map(addNDWI);
var image2 = img2.map(addNDWI);
you are not saving ndwiMask, so you won't be able to use it outside of this function. Again, I wouldn't name them image as they are not images but image collections.
elevation mask: you have to select the elevation band:
var elevMask = elevation.select('elevation').gt(1500)
This mask image will have ones where elevation is greater than 1500 and zeros where not.
applying masks: in this part you have to remember that Earth Engine uses functional programming, so objects are not mutable, this means that you cannot update the state of an object using a method, you have to catch the output of the method you are calling. Here you need ndwi mask, so you have to compute it with NDWI band.
var mask = function(image){
var ndwiMask = image.select('NDWI').gt(0.3)
var ndwi_masked = image.updateMask(ndwiMask);
return ndwi_masked.updateMask(elevMask);
};
var maskedImg = image1.map(mask); // ImageCollection!
var maskedImg2 = image2.map(mask); // ImageCollection!
Visualizing: As the results are ImageCollection, when you add it to the map EE makes a mosaic and that is what you would see. Keep that in mind for further processing.
var ndwiViz = {bands: ['NDWI'], min: 0.5, max: 1, palette: ['00FFFF', '0000FF']};
Map.addLayer(maskedImg, ndwiViz, 'Landsat 5 masked collection');

Related

How to show only one of the clusters in Goole Earth Engine unsupervised classification

Suppose we have the following codes for unsupervised classification. My goal is to identify the water bodies across the area. How can I mask out other classes (clusters) and only map one of the clusters (water bodies)in my results:
// Load a pre-computed Landsat composite for input
var input = ee.Image('LANDSAT/LE7_TOA_1YEAR/2001');
// Define a region in which to generate a sample of the input.
var region = ee.Geometry.Rectangle(29.7, 30, 32.5, 31.7);
// Display the sample region.
Map.setCenter(31.5, 31.0, 8);
Map.addLayer(ee.Image().paint(region, 0, 2), {}, 'region');
// Make the training dataset.
var training = input.sample({
region: region,
scale: 30,
numPixels: 5000
});
// Instantiate the clusterer and train it.
var clusterer = ee.Clusterer.wekaKMeans(5).train(training);
// Cluster the input using the trained clusterer.
var result = input.cluster(clusterer);
// Display the clusters with random colors.
Map.addLayer(result.randomVisualizer(), {}, 'clusters');
I only need the cluster (0) so I could mask the rest of the classes using the codes below:
// showing only one cluster.
var subset = result.select("cluster").eq(0).selfMask();

Leaflet meters to pixels per zoom level

I'm creating an app using Leaflet library
I have a field radius that contains distance in meters (m).
const radius = 1000;
I would need to convert this field to pixels, but on different zoom levels
For zoom levels, I get values from 8 till 18
I have this function that converts successfully on the current zoom level
function disToPixeldistance(distance){
var l2 = L.GeometryUtil.destination(map.getCenter(),90,distance);
var p1 = map.latLngToContainerPoint(map.getCenter())
var p2 = map.latLngToContainerPoint(l2)
return p1.distanceTo(p2)
}
But I would need to pass different zoom levels as an additional parameter and then convert them from meters to pixels
Like:
function disToPixeldistance(distance, zoomLevel)
Does anyone knows how could I achieve this ? Thank you in advance :)
Change the map.latlngToContainerPoint(latlng) to map.project(latlng,zoom)
function disToPixeldistance(distance, zoom){
zoom = zoom || map.getZoom();
var l2 = L.GeometryUtil.destination(map.getCenter(),90,distance);
var p1 = map.project(map.getCenter(), zoom)
var p2 = map.project(l2,zoom)
return p1.distanceTo(p2)
}

Can map.getBounds be executed for a different coordinate system?

I execute the following code in my leaflet webmap
map.getBounds().getWest() + "&y1=" +
map.getBounds().getSouth() + "&x2=" +
map.getBounds().getEast() + "&y2=" +
map.getBounds().getNorth()
This results in a result showing me four coordinates in the WGS84 (standard) coordinate system.
Is there any way to alter this so it will output 28992 coordinates instead?
I guess that by "28992 coordinates" you're referring to the EPSG:28992 Coordinate Reference System.
The canonical way to use "non-standard" CRSs in Leaflet is to leverage proj4leaflet. This answer assumes that you're already doing so.
So the getBounds() method of L.Map always returns a L.LatLngBounds instance, which refer to unprojected WGS84 coordinates. However, we can use the map's CRS to project a L.LatLng into a L.Point with the projected coordinates, in the map's display CRS; e.g.
var map = L.map('containerId`, { crs: crsForEpsg28992 });
var foo = map.options.crs.project(L.latLng([60.3,21.1]));
var qux = map.options.crs.project(map.getCenter());
Because of how map projections work (they rotate and bend the coordinate spaces), and because of how proj4js is implemented, it's not possible to project a bounding box into a bounding box. (In most cases, the projection of a bounding box would be a curved polygon!). This image from an article by Gregor Aisch illustrates the issue:
We can, however, do an approximation: project the four corners of the bounding box, e.g.:
var mapBounds = map.getBounds();
var crs = map.options.crs;
var nw = crs.project(mapBounds.getNorthWest());
var ne = crs.project(mapBounds.getNorthEast());
var sw = crs.project(mapBounds.getSouthWest());
var se = crs.project(mapBounds.getSouthEast());
We can even create a L.Bounds (but not a L.LatLngBounds!) from those projected coordinates; that'll be a bbox in the specified CRS that contains all corners, e.g.:
var bbox = L.bounds([nw, ne, sw, se]);
It's not gonna be perfect, but that approximation should be enough for most use cases.
See also this working example (based off on one of the proj4leaflet examples), which should further illustrate the issue.

Leaflet latLngToContainerPoint and containerPointToLatLng not reciprocal?

Anybody know why the following is not reciprocal? latLng and new
var point = dispmap.latLngToContainerPoint(latlng);
var newPoint = L.point([point.x, point.y]);
var newLatLng = dispmap.containerPointToLatLng(newPoint);
When I execute this code I send in latlng=(26.75529,-80.93581)
newLatLng, which by inspection of the code above I would expect to reciprocate gives back...
newLatLng = (26.75542,-80.93628)
I'm wanting to array some markers with identical lat-lons around the shared spot on a map, and bumping each by some screen coordinates looks like the best method based on some blog/issue reading I've done.
I'm, "close" to what I want to achieve, but as I try to validate what these leaflet calls are doing for me I hit the fundamental question above.
They can't be ...
Latitude and longitude are float values while x and y are integer values.
This means that there are an (theoretically) infinite number of latlng's and a rather small number of points on your view (width * height).
Furthermore, I'm not sure how you define identical latlng's; the best you can't to is to speak of proximity.
If I read between the lines, identical may mean that the markers overlap. Then the best way is to have a look how Leaflet.MarkerCluster are tackling with the problem.
I was able to achieve my desired result by altering zoom level to avoid pixel-point quantization effects on my translations. The screenshot below illustrates an orange and two green circle markers that represent an identical lat-lon, but I want the green arrayed around the orange in a circular fashion...in this example there are only 2 green.
I perform simple circular array math with an angular step size of PI/4 in this example. The KEY to getting the visual effect correct is the "dispmap.setZoom(dispmap._layersMaxZoom)" call BEFORE I do the math, and then I invoke "dispmap.setZoom(mats.zoom)" after the math, which will give the user the desired zoom level as specified by variable mats.zoom.
var arrayRad=20;
var dtheta=Math.PI/4;
var theta=0;
dispmap.setZoom(dispmap._layersMaxZoom)
L.geoJson(JSON.parse(mats.intendeds), {
pointToLayer: function (feature, latlng) {
var point = dispmap.latLngToContainerPoint(latlng);
dx = arrayRad*Math.cos(theta);
dy = arrayRad*Math.sin(theta);
theta += dtheta;
var newPoint = L.point([point.x + dx, point.y+ dy]);
var newLatLng = dispmap.containerPointToLatLng(newPoint);
return L.circleMarker(newLatLng, intendedDeliveryLocationMarkerOptions);
}, onEachFeature: onEachIntendedLocFeature }).addTo(dispmap);
dispmap.setZoom(mats.zoom);
Sample screen shot at max zoom level: 2 arrayed markers

Annotations on a JFreeChart Pie Chart

Specifically I am looking to add text annotations to specific locations to a JFreeChart that is being output to a png file for web use. Can/how do annotations get added to pie charts. I have been able to successfully add annotations to XYPlots, but don't know how to overlay or add one to a PiePlot.
My full task is to use the PiePlot to create a sort of clock. So far everything has worked great, but now I need to add labels at the 12, 3, 6, and 9 o'clock locations and completely stumped.
Adam
Bit of an old question, but here's how I did something similar (annotation at 1, 2, 3, ... o'clock positions) using a polar plot. It uses a ChoiceFormatter and the NumberTickUnit:
final JFreeChart chart = ChartFactory.createPolarChart(
"HAPI Hourly Usage (UTC)", ds, true, true, false);
final PolarPlot plot = (PolarPlot) chart.getPlot();
// Create a ChoiceFormat to map the degrees to clock positions
double[] limits = new double[12];
String[] formats = new String[12];
limits[0] = 0;
formats[0] = "12";
// degrees = 360/12
for (int i = 1; i < limits.length; i++) {
limits[i] = degrees * (i);
formats[i] = Integer.toString(i);
}
ChoiceFormat clock = new ChoiceFormat(limits, formats);
TickUnit tickUnit = new NumberTickUnit(degrees, clock);
// now configure the plot
plot.setAngleTickUnit(tickUnit); // sets the ticks
plot.setAngleLabelsVisible(true); // makes the labels visible
plot.setAngleLabelPaint(Color.LIGHT_GRAY); // user choice
plot.setAngleGridlinesVisible(true); // must set this to display the
// labels
plot.setAngleGridlinePaint(Color.BLACK); // plot's background color
// (makes lines invisible)
plot.setRadiusGridlinesVisible(false); //turn off the radius value circles
ValueAxis axis = plot.getAxis();
axis.setTickLabelsVisible(false); //turn off the radius value labels
winds up looking like http://img522.imageshack.us/img522/6693/hapihours.jpg
After a fairly strenuous search I don't believe this is currently possible (JFreeChart 1.0.13).
Possible options are:
Create a second chart with an XYPlot to generate a second image with needed annotations. Overlay this image on the page. This option is bad because it doubles the number of chart images to be uploaded.
Set the image as a background on the page and HTML the text over the image. Bad because it isn't maintainable and makes a headache of data transfer.
Personally I am just going to find another way to communicate the information in the title, but I wanted to post my findings for the next person.
Adam