Mapbox heatmap by point value - mapbox

There is an example of the heatmap https://www.mapbox.com/mapbox-gl-js/example/heatmap/ by the number of markers/points on the area. But is there a way to display a heatmap by average pins/markers values? For example if I have 5 pins and their average prop value speed=3 then it will be shown as green cluster/heatmap and if their av. prop val is 6 then it will be red cluster/heatmap.
I found that "clusterAggregates" property can help, but can't find any example of using it.
Thanks

I'll leave my way to do so. Old question, which is sometimes risen, but there are no nice sollution, so... Turf's hexgrid (http://turfjs.org/docs/#hexGrid) can help:
const hexagons = hexGrid(bbox, size);
const collection = // collection of your points;
const hexagonsWithin = collect(hexagons, collection, "propertyToAgretateFrom", "propertyToAggregateIn");
const notEmptyHexagonValues = hexagonsWithin.features.filter(({ properties }) => properties.propertyToAggregateIn.length !== 0);
const notEmptyHexagons = {
"type": "FeatureCollection",
"features": notEmptyHexagonValues,
};
// at this point you're having not empty hexagons as a geojson, which you can add to the map
collect is another method from turf, whatcollection should be you can look up in the docs, because it's changing a lot.
The general idea behind is to "divide" visible part of map (bbox) into hexagons by hexGrid method and and aggregate some properties that you need from every marker inside of every hexagon you'll have into the array, so you can get an average value, for example. And assign a color based on it.
Let's say we have feature.properties.propertyToAgretateFrom as 4 and 5 in two markers. After the aggregation, if these markers were inside one polygon, you'll have it feature.properties.propertyToAggregateIn: [4, 5] - this feature is polygon. From this on you can do pretty much everything you want.

Related

Is there a way to get the ECharts series symbol to be passed in as the marker in the tooltip

I've got an ECharts chart that has multiple line series and a scatter series that represents events. For the line series, we left the symbol at the default, but for the event scatter series we set the symbol to 'diamond'. These symbols show up on the chart & in the series legend as expected. However, the tooltip always shows a 10 pixel dot for the marker. The color however is picked up from the series (and even from the visualMap config!). My initial assumption had been that the symbol would also be picked up from the series. In our case we wanted to use a function for tooltip.formatter and even in that function we couldn't figure out how to access and swap in the series symbol for the marker. We ended up working around it by just custom styling our own html to plug in for the marker that matched the diamond symbol pretty well.
So the open questions are:
Is there a way to have the tooltip marker pick up the symbol from the series?
If not, is this a bug? I'm happy to put in an issue on the project but I don't want to do that until I understand a bit more.
Here's some code to illustrate what we had to do to get the diamond in there in case it helps the discussion or if others want to leverage this workaround:
formatTooltip(args){
let time = DateTime.fromISO(args[0].data[0], { zone: this.user.timeZone })
let tooltip = `<div><b>${time.toFormat(TOOLTIP_FORMAT)}</b></div>`
args.forEach(({ marker, seriesName, value }) => {
if (seriesName === 'Events'){
let myMarker = `<span style="display:inline-block;margin-right:4px;width:10px;height:10px;background:${value[4]};transform:rotate(45deg);"></span>`
tooltip += `<div>${myMarker} ${value[3] ? value[3]: ''}</div>`
} else {
value = value || [0, 0]
tooltip += `<div>${marker} ${seriesName}: ${value[1]}</div>`
}
})
return tooltip
},

Swift fit annotations

I have a few locations in parse which I'm query-ing. It shows all annotations but it only zoom the last one. How can I find max and min latitudes and longitudes and make them fit ?
There is plenty of these on stackoverflow but they're almost all in objective-c.
The examples in Objective-C are still essentially valid since the underlying SDK/API is still the same -- just being called using a different language (and there's always the documentation).
To show all annotations, there are essentially two ways to do it:
Use the convenient showAnnotations method. You pass it an array of annotations and it will automatically calculate a reasonable region to display. You call it after adding all the annotations (after your for loop). In fact, showAnnotations will even add the annotations itself if they aren't already on the map. To show all annotations that are already on the map, just pass it the map's own annotations array. Example:
self.mapView.showAnnotations(self.mapView.annotations, animated: true)
If you are not happy with the default region calculated by showAnnotations, you can calculate one yourself. Instead of calculating minimum/maximum latitudes and longitudes, etc, I prefer to use the built-in MKMapRectUnion function to create an MKMapRect that fits all annotations and then call setVisibleMapRect(mapRect,edgePadding,animated) which lets one conveniently define padding in screen points around the fitted map rect. This technique was originally found in a very early map view sample app from Apple. Example:
var allAnnMapRect = MKMapRectNull
for object in objects! {
//existing code that creates annotation...
//existing code that calls addAnnotation...
let thisAnnMapPoint = MKMapPointForCoordinate(annotation.coordinate)
let thisAnnMapRect = MKMapRectMake(thisAnnMapPoint.x, thisAnnMapPoint.y, 1, 1)
allAnnMapRect = MKMapRectUnion(allAnnMapRect, thisAnnMapRect)
}
//Set inset (blank space around all annotations) as needed...
//These numbers are in screen CGPoints...
let edgeInset = UIEdgeInsetsMake(20, 20, 20, 20)
self.mapView.setVisibleMapRect(allAnnMapRect, edgePadding: edgeInset, animated: true)

How to display polygons that are within a specific range (circle) using Leaflet

I am trying find a solution on how to display polygons that are only within a specific range, a circle with radius using leaflet.
Polygons screenshots
Before, I have ask for help regarding on the display of points within a specific range but this time, since a polygon have many nodes/coordinates, i don't have any idea of how it can be done for polygons; a foreach statement?
Any solution? Thanks for the help!
Similar problem solved for displaying points within a specific range
Since you're using MongoDB, the best solution here is (if that's possible), to handle this in the database. Put 2dsphere indexes on your document's loc field and use a $geoWithin query in combination with $centerSphere:
The following example queries grid coordinates and returns all documents within a 10 mile radius of longitude 88 W and latitude 30 N. The query converts the distance to radians by dividing by the approximate radius of the earth, 3959 miles:
db.places.find( {
loc: { $geoWithin: { $centerSphere: [ [ -88, 30 ], 10/3959 ] } }
} )
2dsphere reference: http://docs.mongodb.org/manual/core/2dsphere/
$geoWithin reference: http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
$centerSphere reference: http://docs.mongodb.org/manual/reference/operator/query/centerSphere/
If you really want to do this clientside (which i absolutely wouldn't recommend) and you don't want to build your on solution (which is possible) you could take a look at GeoScript.
GeoScript's geom.Geometry() class has a contains method:
Tests if this geometry contains the other geometry (without boundaries touching).
Geom.geometry reference: http://geoscript.org/js/api/geom/geometry.html
EDIT: Here's the pure JS/Leaflet solution as requested in the comments, this is quick-n-dirty, but it should work. Here the containsPolygon method returns true when all of the polygon's points are within the circle:
L.Circle.include({
'containsPoint': function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
},
'containsPolygon': function (polygon) {
var results = [];
polygon.getLatLngs().forEach(function (latLng) {
results.push(this.containsPoint(latLng));
}, this);
return (results.indexOf(false) === -1);
}
});
Here's a working example: http://plnkr.co/edit/JlFToy?p=preview
If you want to return true if one or more of the polygon's points are within the circle than you must change the return statement to this:
return (results.indexOf(true) !== -1);

iText - PdfAnnotation.createInk

I am trying to parse annotation data in XFDF and draw it using the iText Library. I want to draw the annotation like the attached image.
Following is my code to test the PdfAnnotation.createInk function, but it is not working after run the code.
I have Google and read the documents, but not much information provided. Any suggestions and advice? Thanks!
// step 1
Document document = new Document(PageSize.A4);
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destFile));
// step 3
document.open();
PdfContentByte pcb = new PdfContentByte(writer);
pcb.setColorStroke(BaseColor.RED);
Rectangle rect = new Rectangle(52.92f, 397.56f, 173.36f, 530.67f);
float[][] inkList = {{61.736111f,530.669250f},{61.295139f,525.820984f},{61.295139f,518.768860f},
{61.295139f,505.986969f},{61.295139f,490.560547f},{61.295139f,470.726562f},{59.972221f,452.214844f},
{57.767361f,434.143890f},{56.003471f,418.276703f},{53.357639f,404.172516f},{51.593750f,391.390625f},
{50.711807f,382.134766f},{49.829861f,376.845703f}
};
//float inkList[][] =
PdfAnnotation an = PdfAnnotation.createInk(writer, rect, "", inkList);
an.setPage(1);
an.setColor(BaseColor.RED);
an.setFlags(PdfAnnotation.FLAGS_PRINT);
writer.addAnnotation(an);
//Step 5
document.close();
The output PDF seemingly does not contain an annotation because the defined annotation is a mere collection of isolated points.
The float[][] parameter of PdfAnnotation.createInk corresponds to the InkList entry of the Ink annotation dictionary:
InkList array (Required) An array of n arrays, each representing a stroked path. Each
array shall be a series of alternating horizontal and vertical coordinates in
default user space, specifying points along the path. When drawn, the
points shall be connected by straight lines or curves in an
implementation-dependent way.
Thus, in case of the OPs array
float[][] inkList = {{61.736111f,530.669250f},{61.295139f,525.820984f},{61.295139f,518.768860f},
{61.295139f,505.986969f},{61.295139f,490.560547f},{61.295139f,470.726562f},{59.972221f,452.214844f},
{57.767361f,434.143890f},{56.003471f,418.276703f},{53.357639f,404.172516f},{51.593750f,391.390625f},
{50.711807f,382.134766f},{49.829861f,376.845703f}
};
we have a collection of 13 paths each of which contain only a single point. So, nothing is drawn.
If we combine all the points in a single path, though,
float[][] inkList = {{61.736111f,530.669250f,61.295139f,525.820984f,61.295139f,518.768860f,
61.295139f,505.986969f,61.295139f,490.560547f,61.295139f,470.726562f,59.972221f,452.214844f,
57.767361f,434.143890f,56.003471f,418.276703f,53.357639f,404.172516f,51.593750f,391.390625f,
50.711807f,382.134766f,49.829861f,376.845703f}
};
the result is this:
which looks like the left line of the "H" in the screenshot in the question.

Line chart/graph with an irregular threshold field

Looking to create a bar chart with an irregular, colored threshold field in the background, so that each data point has its own individual set of min/max thresholds, which ultimately would look something like this: http://dcalvitti.webs.com/plant/SAMPLE.png
Looked at D3 examples like this one: http://bl.ocks.org/mbostock/4062844
Can the latter example be manipulated to look more like the image I created?
Thanks in advance..
The graph shown in your sample image is actually much easier than the linked example; for that, you don't need to create a clipping path and you don't need to draw the line twice with two different colours.
For drawing the coloured background, use an area-path generator, created with d3.svg.area(). Set the y0 accessor function to be extract your minimum value for each point in your data array, and the y1 accessor function to extract the maximum value.
Then draw the line overtop as a normal line graph with a d3.svg.line() path generator.
Working example, adapted from the fiddles in the comments: http://jsfiddle.net/h45CD/12/
(Note: I commented out half the dataset, since the "year" values were repeated, not sure what that was supposed to represent.)
Key code:
// Define the value line path generator
var line = d3.svg.line()
.x( function(d) { return x(d.year); } )
.y( function(d) { return y(d.temp); } );
// Define the area path generator
var area = d3.svg.area()
.x( function(d) { return x(d.year); } )
.y0( function(d) { return y(d.min); } )
.y1( function(d) { return y(d.max); } );
/* ... */
// Add the background area showing the historic range
svg.append("path")
.datum(data)
.attr("class", "historicRange")
.attr("d", area);
// Add the value line
svg.append("path")
.datum(data)
.attr("class", "dataline")
.attr("d", line);
Edit based on comments
If you do want a line that changes colour depending on historic values, as opposed to a line drawn overtop of a background range, the most straight-forward solution is probably to create a <pattern> element consisting of the different coloured regions, and use this to stroke the value line.
You'll want to familiarize yourself with the different options for the pattern element. This MDN tutorial has a good intro, or you could dive into the full W3 specs.
For this situation, we want the pattern to be sized and positioned relative to the coordinate system used for drawing the line, regardless of the size or shape of the line itself. That means we will be setting both the patternUnits and the patternContentUnits to be userSpaceOnUse. The height and width of the pattern will be the height and width of the plotting area.
Within the pattern we will draw the area that represents the max-min range, but we also need to draw separate areas, with different colours, for values above the max and values below the min. We can use the same area generator for each, but need to change the y0/y1 accessor functions each time.
Key code:
// Add the pattern showing the historic range
var pattern = defs.append("pattern")
.datum(data) //add the data to the <pattern> element
//so it will be inherited by each <path> we append
.attr({
"patternUnits":"userSpaceOnUse",
"patternContentUnits":"userSpaceOnUse",
"width": width,
"height": height
})
.attr("id", "strokePattern");
pattern.append("path")
.attr("class", "historicRange between")
.attr("d", area);
pattern.append("path")
.attr("class", "historicRange above")
.attr("d", area.y1( 0 )
.y0( function(d){return y(d.max);} )
);
pattern.append("path")
.attr("class", "historicRange below")
.attr("d", area.y1( function(d){return y(d.min);} )
.y0( height )
);
// Add the value line
plot.append("path")
.datum(data)
.attr("class", "dataline")
.attr("d", line)
.style("stroke", "url(#strokePattern)");
Working example: http://jsfiddle.net/h45CD/14/
I'm including a web page link with charts authored by myself based on AMCharts and with the help of that web site's founder. Contains several examples of the above question and more..
http://dcalvitti.webs.com/SAMPLE/NEWWEBINDEX.html
The charts provided are still being worked on. For example, AMcharts does have a function that clips the color of a line above/below a certain value which I didn't know about, so there is still work to be done. I spent many weeks on the charts and thought I'd share. I'm sure someone will find something new here down the road...