Plotting points on Mapnik - python-2.7

I followed this tutorial in the mapnik github wiki to make a world map: https://github.com/mapnik/mapnik/wiki/GettingStartedInPython
I modified this example, and have now embedded the code into a Pyside Qt Widget. My question now is, how does one plot points on this map using x and y coordinates, or latitude and longitude points?
Here is the code I'm using to generate the map and to embed it in the widget:
import mapnik
m = mapnik.Map(1200,600)
m.background = mapnik.Color('steelblue')
s = mapnik.Style()
r = mapnik.Rule()
polygon_symbolizer = mapnik.PolygonSymbolizer(mapnik.Color('#f2eff9'))
r.symbols.append(polygon_symbolizer)
line_symbolizer = mapnik.LineSymbolizer(mapnik.Color('rgb(50%,50%,50%)'),0.1)
r.symbols.append(line_symbolizer)
s.rules.append(r)
m.append_style('My Style',s)
ds = mapnik.Shapefile(file='/home/lee/shapefiles/ne_110m_admin_0_countries.shp')
layer = mapnik.Layer('world')
layer.datasource = ds
layer.styles.append('My Style')
m.layers.append(layer)
m.zoom_all()
im = mapnik.Image(1200,600)
mapnik.render(m, im)
qim = QImage()
qim.loadFromData(QByteArray(im.tostring('png')))
label = QLabel(self)
label.setPixmap(QPixmap.fromImage(qim))
self.layout.addWidget(label)

Usually, you would connect your map to a datasource such as a PostGIS or SQLite database and let mapnik populate the points from said database, similar to something like this. Either in a python script or generated from xml.
However, in answer to your question, you could plot Lat/Lon points by creating a new Feature from a WKT string and adding that feature to a mapnik.MemoryDatasource().
Below is a simple snippet from a script using the mapfile found here
First we create our style and add it to our map:
s = mapnik.Style() # style object to hold rules
r = mapnik.Rule() # rule object to hold symbolizers
point_sym = mapnik.PointSymbolizer()
point_sym.filename = './symbols/airport.p.16.png'
r.symbols.append(point_sym) # add the symbolizer to the rule object
s.rules.append(r)
m.append_style('airport point', s)
Now we create our data source and add a Point geometry in WKT format:
ds = mapnik.MemoryDatasource()
f = mapnik.Feature(mapnik.Context(), 1)
f.add_geometries_from_wkt("POINT(-92.289595 34.746481)")
ds.add_feature(f)
Now we must create a new layer, add our style that we created, and add the layer to our map:
player = mapnik.Layer('airport_layer')
#since our map is mercator but you wanted to add lat lon points
#we must make sure our layer projection is set to lat lon
player.srs = longlat.params()
player.datasource = ds
player.styles.append('airport point')
m.layers.append(player)
m.zoom_all()
You can look at the entire script here.

If you need to get a geographic coordinate(ie:lat/lon) from the pixel coordinate, you probably need to add your converter functions.
The Google Maps JS code is as follow could perhaps help :
https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
var TILE_SIZE = 256;
function bound(value, opt_min, opt_max) {
if (opt_min != null) value = Math.max(value, opt_min);
if (opt_max != null) value = Math.min(value, opt_max);
return value;
}
function degreesToRadians(deg) {
return deg * (Math.PI / 180);
}
function radiansToDegrees(rad) {
return rad / (Math.PI / 180);
}
/** #constructor */
function MercatorProjection() {
this.pixelOrigin_ = new google.maps.Point(TILE_SIZE / 2,
TILE_SIZE / 2);
this.pixelsPerLonDegree_ = TILE_SIZE / 360;
this.pixelsPerLonRadian_ = TILE_SIZE / (2 * Math.PI);
}
MercatorProjection.prototype.fromLatLngToPoint = function(latLng,
opt_point) {
var me = this;
var point = opt_point || new google.maps.Point(0, 0);
var origin = me.pixelOrigin_;
point.x = origin.x + latLng.lng() * me.pixelsPerLonDegree_;
// Truncating to 0.9999 effectively limits latitude to 89.189. This is
// about a third of a tile past the edge of the world tile.
var siny = bound(Math.sin(degreesToRadians(latLng.lat())), -0.9999,
0.9999);
point.y = origin.y + 0.5 * Math.log((1 + siny) / (1 - siny)) *
-me.pixelsPerLonRadian_;
return point;
};
MercatorProjection.prototype.fromPointToLatLng = function(point) {
var me = this;
var origin = me.pixelOrigin_;
var lng = (point.x - origin.x) / me.pixelsPerLonDegree_;
var latRadians = (point.y - origin.y) / -me.pixelsPerLonRadian_;
var lat = radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) -
Math.PI / 2);
return new google.maps.LatLng(lat, lng);
};

Related

Indexing Faces with AWS Rekognition

I am new to AWS and am trying to use Rekognition to identify certain people in a crowd. I am currently trying to index the images of the separate individuals but have hit a snag when trying to create a collection. There seems to a data type compatibility issue when I try using Amazon.Rekognition.Model.S3Object(). I have provided the code below. Does anyone have a solution or a better method? Thank you for your time!
private static void TryIndexFaces()
{
S3Client = new AmazonS3Client();
RekognitionClient = new AmazonRekognitionClient();
IndexFacesRequest indexRequest = new IndexFacesRequest();
Amazon.Rekognition.Model.Image img = new Amazon.Rekognition.Model.Image();
ListObjectsV2Request req = new ListObjectsV2Request();
req.BucketName = "wem0020";
ListObjectsV2Response listObjectsResponse = S3Client.ListObjectsV2(req);
CreateCollectionRequest ccr = new CreateCollectionRequest();
ccr.CollectionId = "TestFaces";
//RekognitionClient.CreateCollection(ccr);
ListVersionsResponse lvr = S3Client.ListVersions(req.BucketName);
string version = lvr.Versions[0].VersionId;
foreach(Amazon.S3.Model.S3Object s3o in listObjectsResponse.S3Objects)
{
Console.WriteLine(s3o.Key);
try
{
if (s3o.Key.EndsWith(".jpg"))
{
Amazon.Rekognition.Model.S3Object reks3o = new Amazon.Rekognition.Model.S3Object();
reks3o.Bucket = req.BucketName;
reks3o.Name = s3o.Key;
Console.WriteLine(version);
reks3o.Version = version;
img.S3Object = reks3o;
indexRequest.Image = img;
indexRequest.CollectionId = ccr.CollectionId;
RekognitionClient.IndexFaces(indexRequest);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
To index faces, use the bounding boxes value returned from aws rekognition. I have done with python
widtho = 717 #width of the given image
heighto = 562 #height of the given image
counter = 0
facecount = 1
s3 = boto3.resource('s3')
bucket = s3.Bucket('rek')
if __name__ == "__main__":
#Choosing the file in s3 bucket
photo = 'sl.jpg'
bucket = 'rek'
#Intilization of rekognition and performing detect_faces
client = boto3.client('rekognition', region_name='eu-west-1')
response = client.detect_faces(
Image={'S3Object': {'Bucket': bucket, 'Name': photo}}, Attributes=['ALL'])
print('Detected faces for ' + photo)
print('The faces are detected and labled from left to right')
for faceDetail in response['FaceDetails']:
print('Face Detected= ', i)
#To mark a bounding box of the image using coordinates
print('Bounding Box')
bboxlen = len(faceDetail['BoundingBox'])
print(bboxlen)
width = faceDetail['BoundingBox'].get('Width')
height = faceDetail['BoundingBox'].get('Height')
left = faceDetail['BoundingBox'].get('Left')
top = faceDetail['BoundingBox'].get('Top')
w = int(width * widtho)
h = int(height * heighto)
x = int(left * widtho)
y = int(top * heighto)
cv2.rectangle(imagere, (x, y), (x + w, y + h), (255, 0, 0), 2)
this loop will index faces one by one in the single frame

How to fix the reprojection from EASE-2 grid product SMAP to geographic coordinates?

I'm have been working with SMAP data satellite, specially for moisture and soil proporties.
I follow the idea of use GDAL solve everything, and make something similar to this published in Link to first approach to download SMAP data
Modifing the code and testing:
import os
import h5py
import numpy as np
from osgeo import gdal, gdal_array, osr
# the file to download
https://n5eil01u.ecs.nsidc.org/SMAP/SPL4SMAU.003/2017.08.01/SMAP_L4_SM_aup_20170801T030000_Vv3030_001.h5
path = "/path/to/data"
h5File = h5py.File(path + "SMAP_L4_SM_aup_20170801T030000_Vv3030_001.h5", 'r')
data = h5File.get('Analysis_Data/sm_rootzone_analysis')
lat = h5File.get("cell_lat")
lon = h5File.get("cell_lon")
np_data = np.array(data)
np_lat = np.array(lat)
np_lon = np.array(lon)
num_cols = float(np_data.shape[1])
num_rows = float(np_data.shape[0])
xmin = np_lon.min()
xmax = np_lon.max()
ymin = np_lat.min()
ymax = np_lat.max()
xres = (xmax - xmin) / num_cols
yres = (ymax - ymin) / num_rows
nrows, ncols = np_data.shape
xres = (xmax - xmin) / float(ncols)
yres = (ymax - ymin) / float(nrows)
geotransform = (xmin, xres, 0, ymax, 0, -xres)
dataFileOutput = path + "sm_rootzone_analysis.tif"
output_raster = gdal.GetDriverByName('GTiff').Create(dataFileOutput, ncols, nrows, 1, gdal.GDT_Float32) # Open the file
output_raster.SetGeoTransform(geotransform)
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
output_raster.SetProjection(srs.ExportToWkt())
output_raster.GetRasterBand(1).WriteArray(np_data) # Writes my array to the raster
del output_raster
So, using this approach, the result is a global map with many problems of projections, as for example the image below, produced by the python code above.
To compare with a correct data, the same image was extract from h5, using HEG nasa software.
If the data is really in the EASE2 Global grid, you shouldn't assign EPSG:4326 as a the coordinate system with lat/lon degrees in the geotransform.
If you convert the lat/lon coordinates to the EASE2 Grid at 9km, your geotransform should be something like:
geotransform = (-17367530.44516138, 9000, 0, 7314540.79258289, 0, -9000.0)
and the srs:
srs.ImportFromEPSG(6933)

Creating a Normal Distribution graph with Chart.js

I've been tasked with implementing a Normal Distribution graph. I was wondering if Chart.js offers this functionality right out of the box or if I will need to extend it. The graph in question is here
Thank you
It is unfortunately not possible with Chart.js, except if you create it by yourself.
But, I found a library called ChartNew.js (Github) that provides a lot of functionalities that are not available on Chart.js :
Chart.js has been completely rewritten since ChartNew.js has been developed; Both code are now completely different. Most of the functionalities inserted in the new version of Chart.js are also available in ChartNew.js
And this library provides a Gaussian Function (also called Normal Distribution) :
To do it, take a look at the sample given in the Github.
I'm sure it will suit you if you change some data.
This Implementation has been done using React. The functions below can still be used in other programming languages built on top of Javascript.
The only two inputs required to plot a Normal Distribution curve will be Mean and Standard deviation
Defining states for mean and standard deviation & states for X and Y arrays
const [bellMean, setBellMean] = useState<number>(12.2036); //example
const [bellStdev, setBellStdev] = useState<number>(0.0008); //example
const [bellXValues, setBellXValues] = useState<(number)[]>([]);
const [bellYValues, setBellYValues] = useState<(number | null)[]>([]);
To Get X values for bell curve (if not using react can get rid of useEffect)
useEffect(() => {
// defining chart limits between which the graph will be plotted
let lcl = bellMean - bellStdev * 6;
let ucl = bellMean + bellStdev * 6;
let ticks = [lcl];
let steps = 100; // steps corresponds to the size of the output array
let stepSize = Math.round(((ucl - lcl) / steps) * 10000) / 10000;
let tickVal = lcl;
for (let i = 0; i <= steps; i++) {
ticks.push(Math.round(tickVal * 10000) / 10000); // rounding off to 4 decimal places
tickVal = tickVal + stepSize;
}
setBellXValues(ticks); //array for X values
}, [bellMean, bellStdev]);
To Get Y values for Bell curve (if not using react can get rid of useEffect)
useEffect(() => {
// Using PDF function from vega-statistics instead of importing the whole library
const densityNormal = (value: number, mean: number, stdev: number) => {
const SQRT2PI = Math.sqrt(2 * Math.PI);
stdev = (stdev == null) ? 1 : stdev;
const z = (value - (mean || 0)) / stdev;
return Math.exp(-0.5 * z * z) / (stdev * SQRT2PI);
};
let YValues = bellXValues.map((item: number) => {
if (bellMean === null || bellStdev === undefined) {
return null;
} else {
const pdfValue = densityNormal(item, bellMean, bellStdev);
return pdfValue === Infinity ? null : pdfValue;
}
});
setBellYValues(YValues); // array for Y values
}, [bellXValues]);
The arrays for X and Y can be fed to labels and data props of chartjs as it is.

Camera matrix invalid when aligned with up vector

I'm currently implementing cameras on my engine and I'm having an issue when the camera is looking from top to the floor (example, eye position 0.,0.,50. and target is 0.,0.,0.) my up vector is 0.,0.,1..
Then when I do the maths, the crossproduct of position and up gives 0.,0.,0. and then the view is screwed and nothing is rendered. If I move the camera, everything works as expected.
How can I solve this?
if (node==NULL || target==NULL) return;
node->Update();
eye=node->GetWorldMatrix()*GRPVECTOR(0.0,0.0,0.0); //converts from matrix to vector my vector transformation
target->Update();
obj=target->GetWorldMatrix()*GRPVECTOR(0.0,0.0,0.0);
GRPVECTOR ev;
GRPVECTOR z;
GRPVECTOR x_tmp;
GRPVECTOR x;
GRPVECTOR y;
ev = eye - obj;
ev.Normalize();
z=ev;
x_tmp.CrossProduct(&up,&z);
if (x_tmp.GetLengthf()==0.0f)
return; //my view is screwed, I return
x_tmp.Normalize();
x=x_tmp;
y.CrossProduct(&z,&x);
this->viewmatrix.matrix[0][0] = x.vector[0];
this->viewmatrix.matrix[0][1] = y.vector[0];
this->viewmatrix.matrix[0][2] = z.vector[0];
this->viewmatrix.matrix[0][3] = 0.0f;
this->viewmatrix.matrix[1][0] = x.vector[1];
this->viewmatrix.matrix[1][1] = y.vector[1];
this->viewmatrix.matrix[1][2] = z.vector[1];
this->viewmatrix.matrix[1][3] = 0.0f;
this->viewmatrix.matrix[2][0] = x.vector[2];
this->viewmatrix.matrix[2][1] = y.vector[2];
this->viewmatrix.matrix[2][2] = z.vector[2];
this->viewmatrix.matrix[2][3] = 0.0f;
this->viewmatrix.matrix[3][0] = -x.vector[0] * eye.vector[0] + -x.vector[1] * eye.vector[1] + -x.vector[2] * eye.vector[2];
this->viewmatrix.matrix[3][1] = -y.vector[0] * eye.vector[0] + -y.vector[1] * eye.vector[1] + -y.vector[2] * eye.vector[2];
this->viewmatrix.matrix[3][2] = -z.vector[0] * eye.vector[0] + -z.vector[1] * eye.vector[1] + -z.vector[2] * eye.vector[2];
this->viewmatrix.matrix[3][3] = 1.0f;
GRPMATRIX Translate;
Translate.BuildTranslationMatrix(-obj.vector[0],-obj.vector[1],-obj.vector[2]);
this->viewmatrix.GetMulplicationMatrix(&this->viewmatrix,&Translate);

Photoshop CS4 Script or Action to: Write 0 to 100 on separate text layers

My goal is to create 101 separate text layers containing 0-100 (i.e. 1, 2, 3...100) I know I can mass change the attributes but cant write or alter the containing text.
What you want can easily be done with a script (easier than renaming 100 layers in all the right order and record an action for it) This script will create 100 layers of text, each layer will be named 1,2,3..etc and the text will be the same. I think that's waht you are after, your description was rather short.
// call the source document
var srcDoc = app.activeDocument;
var numOfLayers = 100;
//var numOfLayers = srcDoc.layers.length;
var numPadding = "0";
var layerNum = 1; // change this to 0 to start layers at 0
var w = Math.floor(srcDoc.width.value/2);
var h = Math.floor(srcDoc.height.value/2);
// main loop starts here
for (var i = numOfLayers -1; i >= 0 ; i--)
{
if (layerNum < 10) numPadding = "0";
else numPadding ="";
createText("Arial-BoldMT", 20.0, 0,0,0, layerNum, w, h);
var currentLayer = srcDoc.activeLayer;
currentLayer.name = numPadding + layerNum;
layerNum +=1;
}
// function CREATE TEXT(typeface, size, R, G, B, content, Xpos, Ypos)
// --------------------------------------------------------
function createText(fface, size, colR, colG, colB, content, tX, tY)
{
var artLayerRef = srcDoc.artLayers.add()
artLayerRef.kind = LayerKind.TEXT
textColor = new SolidColor();
textColor.rgb.red = colR;
textColor.rgb.green = colG;
textColor.rgb.blue = colB;
textItemRef = artLayerRef.textItem
textItemRef.font = fface;
textItemRef.contents = content;
textItemRef.color = textColor;
textItemRef.size = size
textItemRef.position = new Array(tX, tY) //pixels from the left, pixels from the top
activeDocument.activeLayer.textItem.justification.CENTER
}
Save this out as numberLayers1-100.jsx and then reun it from Photoshop via the Files -> Scripts menu.