Tag Archives: REST API

Excel Geocoder

17 Apr

ESRI makes maps for Office. I thought this could be interesting and went to work on trying to insert a map in to a spreadsheet. I did not have much luck. Instead, I decided to throw together a quick macro that would geocode addresses in a spreadsheet and give back coordinates. I do not think VB Script can parse JSON, so the result is ugly, but you get the idea.

Start with a spreadsheet of addresses

sheet

 

Then create a Macro – I copied the code for reading the URL from Ryan Farley.

Sub Macro1()
Range(“A2”).Select
i = 2

Do Until IsEmpty(ActiveCell)

URL = “http://coagisweb.cabq.gov/arcgis/rest/services/locators/CABQ_NetCurr/GeocodeServer/findAddressCandidates?f=json&outSR=4326&street=” & ActiveCell.Value
Dim objHttp
Set objHttp = CreateObject(“Msxml2.ServerXMLHTTP”)
objHttp.Open “GET”, URL, False
objHttp.Send
Cells(i, 2).Value = objHttp.ResponseText
i = i + 1
ActiveCell.Offset(1, 0).Select
Set objHttp = Nothing
Loop

End Sub

The code starts at cell A2 and reads addresses until it reaches an empty cell. It takes the value and sends it to the ESRI REST endpoint for the City of Albuquerque Geocoding Service. It sets the cell next to it with the results. They should really be parsed, but I am too lazy and was just curious if it could be done. It can. The result is below.

results

I am still thinking of how to embed a web page in the sheet.

Advertisements

Load ESRI Data in Map Without Plugin

12 Feb

I am sure at some point I have shown how to load ESRI REST API data in to a Leaflet.js map. I usually use a plugin called Leaflet Vector Layers which works great, but sometimes you may want to do it for yourself. In this example, I will show you how to parse points from an ESRI REST API Endpoint and map them with no additional leaflet.js plugins.

The map with filming location points

The map with filming location points

As we have done with all the REST API examples, you will make an AJAX call to the service. We will use a where clause of 1=1, an outSR of 4326, and out fields = *. We will also specify f=json so that we can easily parse it.

var params = “f=json&where=1=1&outSR=4326&outFields=*”;
var url = “http://coagisweb.cabq.gov/arcgis/rest/services/public/FilmLocations/MapServer/0/query”;

http=new XMLHttpRequest();
http.open(“POST”, url, true);
http.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
Code goes here
}}}http.send(params);

Now all we need to do is convert the response to JSON, parse out the coordinates and throw in a popup with some additional attributes. Put the code below in place of the “code goes here” line.

var result= JSON.parse(http.responseText);
console.log(Object.keys(result.features).length)
for(x=0;x<Object.keys(result.features).length;x++){
L.marker([result.features[x].geometry.y,result.features[x].geometry.x]).addTo(map).bindPopup(“<h3>”+result.features[x].attributes.Title+”</h3><h3>”+result.features[x].attributes.Type+”</h3><h3><a href='”+result.features[x].attributes.IMDbLink+”‘>IMDB</a></h3><h3>”+result.features[x].attributes.Address+”</h3><h3>”+result.features[x].attributes.Site+”</h3><h3>”+result.features[x].attributes.ShootDate+”</h3><h3>”+result.features[x].attributes.OriginalDetails+”</h3>”);

The ESRI REST API will hand back the features and geometry. Once you have them, parsing them for the coordinates is simple. For a polygon or polyline, it becomes slightly more difficult.

Adding Polygons to the map

Adding Polygons to the map

To parse a polygon, we will use the Municipal Limits data. The AJAX call is the same as for points, but we will create a geoJSON object for each boundary passing the rings as the coordinates.

for(x=0;x<Object.keys(result.features).length;x++){
var pts=result.features[x].geometry.rings;
var b = [{
“type”: “Polygon”,
“coordinates”:pts}];

var bStyle = {
“color”: “red”,
“opacity”:1,
“weight”: 10
};

var project = L.geoJson(b, { style: bStyle}).addTo(map);
}

Now you know how to parse points and polygons from an ESRI REST API Endpoint with no additional libraries or plugins.

City of Albuquerque 311 API

30 Jan

The City of Albuquerque has a 311 service that can be reached by calling 311. They have also use SeeClickFix for web and app based submitting.  This post will show you how to query the SeeClickFix API to retrieve Albuquerque Data.

The finished Application

The finished Application

The API

The SeeClickFix API is rather uncomplicated. You can find the details on their development site. To see issues, you will call the API by going to the issues service and passing parameters.

https://seeclickfix.com/api/v2/issues?page=1&per_page=1

The code above grabs a single issue on page 1. Change page to 2 and it will be a different issue. Change issues to 100 and you will hit the maximum of issues per page. Look through the JSON and make not of the fields and also that the addresses are for cities throughout the country – not just Albuquerque.

Using the API for Albuquerque Data

To narrow the data for Albuquerque, you could grab all the data and filter based on address but that would require reading TONS of data. Not the way to go. Using the API, we can filter by an envelope. The coordinates for a bounding box around the City of Albuquerque are (35.02212, -106.79672),(35.20636, -106.48911). Using the API, we can enter the URL below and get back some issues for Albuquerque.

https://seeclickfix.com/api/v2/issues?min_lat=35.02212&min_lng=-106.79672&max_lat=35.20636&max_lng=-106.48911

I will add that I want only open tickets on page 1 with 100 records on the page.

https://seeclickfix.com/api/v2/issues?min_lat=35.02212&min_lng=-106.79672&max_lat=35.20636&max_lng=-106.48911&status=open&page=1&per_page=100

Now you should see 100 open 311 issues in the City of Albuquerque.

Mapping the Data

With the URLs working for our requests, we can automate calling them using AJAX and parse out the response to display the points on a leaflet.js map. I have covered how to do this multiple times on this blog, but the code is below.

var url = “https://seeclickfix.com/api/v2/issues?min_lat=35.02212&min_lng=-106.79672&max_lat=35.20636&max_lng=-106.48911&status=open&page=1&per_page=100&#8221;;

http=new XMLHttpRequest();
http.open(“GET”, url, true);
http.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
http.onreadystatechange = function() {
if(http.readyState == 4 && http.status == 200) {
console.log(http.responseText);
var result= JSON.parse(http.responseText);
for(x=0;x<Object.keys(result.issues).length;x++){

markers.addLayer(L.marker([result.issues[x].lat,result.issues[x].lng]).bindPopup(“<ul><li>”+result.issues[x].summary+”</li><li><a href='”+result.issues[x].media.image_full+”‘>Image</a></li><li>”+result.issues[x].created_at+”</li></ul>”));

}//end for
markers.addTo(map);

}}
http.send();

The code above makes the request, parses the response as JSON then grabs the coordinates. When creating the marker, I went ahead and added some other fields in a popup so that we could have more information about the request.

In a future post, I will show you how to post to SeeClickFix to report a problem.

Revit REST API: More Detail

29 Jan

I have ideas in my head about why a Revit REST API is cool and what it can do. I also know that I fail to explain or show what I am thinking in the best possible way. Often, my examples are quick and dirty. I really love the Revit REST API idea and have built out a slightly more detailed example to show what can be done. The images below show a more complete site. I have sorted many of the tables by the field that makes the most sense. Remember, the data can be edited – without a Revit license I might add.  The model I used was the sampel that comes with Revit 2014.

The sample model

The sample model

walls

rooms

levels

sheets

views

 

Parcel Values in Bernalillo County

6 Jan

In the last post, you learned how to use the ESRI REST API to access data. I am going to show one more example. this example will grab 2500 parcel records and return the total property value for all the parcels.

The example is almost identical to the previous post. You will create an array to hold the values of each parcel. Then we will use a reduce function to sum them. The full code is below.

Results of REST query

Results of REST query

<html>
<head>
<title>PUBLIC ART</title>
</head>
<body>
<div id=”title”>Loading…</div>
<div id=”total”></div>
<div id=”tax”></div>
<script>
var query;
var holdtotal=[0];

var params = “where=1=1&outfields=TOTVALUE&f=json”;
var url = “http://coagisweb.cabq.gov/arcgis/rest/services/public/BernCoParcels/MapServer/0/query&#8221;;
http=new XMLHttpRequest();
http.open(“POST”, url, true);
http.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
http.onreadystatechange = function() {
if(http.readyState == 4 && http.status == 200) {
theGeom= JSON.parse(http.responseText);
var key, count = 0;
for(key in theGeom.features) {
if(theGeom.features.hasOwnProperty(key)) {
count++;
}}
document.getElementById(“title”).innerHTML=”<h3>I grabbed “+count+” parcels in Bernalillo County”;

for(i=0;i<count;i++){

holdtotal.push(theGeom.features[i].attributes.TOTVALUE);
}

var grandtotal=holdtotal.reduce(function(t,n){return t+n},0);

document.getElementById(“total”).innerHTML=”The total value of the parcels is $”+grandtotal.toLocaleString();

}}

http.send(params);
</script>
</body>
</html>

 

The above code should be straight forward with the exception of the variable grandtotal. The reduce function allows you to iterate through an array and add the previous value to the next returning a single value. the variable t is the total starting at 0 and n is the next value. when it is added, the value of t increases and adds itself to the next item. Then you just write the value to HTML.

With this technique you can create forms that would allow users to query data that you already publish in GIS. You can change your where clause to only grab residential properties, properties owned by a specific person or by lot size. Try some variations like where=acreage>600.

Database Queries Using GIS: The ESRI REST API Without Geography

6 Jan

When people think of GIS they think of maps. But GIS is about data and if we think about it as data it is not special. In this post, I will show you how to use your GIS data as a database and nothing more. I am going to build a website that displays a table of all the public art in Albuquerque with the artist, title and a link to an image of the piece.

First, go to the Albuquerque Public Data website and select Public Art. You will see a directory listing. Choose the last option: PublicArtREST. You will then see a bunch of the ArcServer information for the service. This URL could be used to load the data in to a map for display, but we are only interested in the tabular data at this time. On the bottom of the page you will see the supported operations. We are going to use the query operation. Click the query link and you will see a form. In the where box, type 1=1 and then click the button query (GET). a list of features will show up under the form. See the geographic data available as (x.y) coordinates? In the outfields box, type a *. Then set the return geometry option to False. Now press Query (GET) again. Now you have all the data from the database (there are x,y fields only because they are an actual column in the table. This is not the geometry from ESRI. You can tell because the projection changed – it is now in wkid:4326 and the ESRI version is in wkid:3857).

Now you know where the data lives and how to get it without the geographic portion. The next step is to grab it using AJAX. The key line in the AJAX query will be the parameters:

var params = “where=1=1&outfields=*&f=json”;

You used the first two parameters in the form. The 1=1 returns all the records(ArcServer limits the number of results so a large dataset may only return between 1000-2500 unless it is set for more). The outfield=* returns all the fields for each feature. The last parameter “f=JSON” is returning the JSON data and not the HTML underneath the form. This makes it easy to parse in JavaScript.

The complete code will create two DIV elements: one for the count of public art pieces; and one for the table of results. It will make an AJAX post request, count the records and write out the number, then create a table of the results by sticking each line in to an array then dumping it at the end. The result is below with the complete code after the image.

Table of Public Art with Link to Image

Table of Public Art with Link to Image

<html>
<head>
<title>PUBLIC ART</title>
</head>
<body>
<div id=”count”></div>
<div id=”data”></div>
<script>
var lines=[“<table border=’1′><tr><td>TITLE</td><td>ARTIST</td><td>IMAGE URL</td></tr>”];
var params = “where=1=1&outfields=*&f=json”;
var url = “http://coagisweb.cabq.gov/arcgis/rest/services/public/PublicArt/MapServer/0/query&#8221;;
http=new XMLHttpRequest();
http.open(“POST”, url, true);
http.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
http.onreadystatechange = function() {
if(http.readyState == 4 && http.status == 200) {
theGeom= JSON.parse(http.responseText);
var key, count = 0;
for(key in theGeom.features) {
if(theGeom.features.hasOwnProperty(key)) {
count++;
}}
document.getElementById(“count”).innerHTML=”<h3>There are “+count+” pieces of Public Art in Albuquerque</h3>”;

for(i=0;i<count;i++){

lines.push(“<tr><td>”+theGeom.features[i].attributes.TITLE+”</td><td>”+theGeom.features[i].attributes.ARTIST+”</td><td><a href='”+theGeom.features[i].attributes.IMAGE_URL+”‘>Image</a></td></tr>”);}

lines.push(“</table>”);

document.getElementById(“data”).innerHTML=lines.join(” “);

}}

http.send(params);
</script>
</body>
</html>

Now you know how to use a GIS service to retrieve data without a map. You can refine your query to only pieces by a certain artist, or create a table that lists artists and the number of pieces they have in the collection.

Happy Hacking.

ESRI Attachments with ArcServer and Javascript

10 Dec
Upload Image from Phone Camera

Upload Image from Phone Camera

I was working on the following problem:

How can we take a photo of a GIS feature and put it on the network in a folder named after a property of the feature?

I started by creating a map that displayed the feature and grabbed the property value. I coded a popup for the feature that used a form to allow the uploading of images from a phone camera. The code for the form is below:

<form target=”_blank”‘+theaction+'” enctype=”multipart/form-data” method=”post” accept=”image/*;capture=camera”><input type=”file” name=”upload” multiple=”multiple”><br><input type=”submit” value=”Upload”></form>

The next step was handling the files the form sent on the server side. Using Node.js, I displayed the map and handled the file transfer from the form. The problem was solved.

Was it the best solution? No. Keeping the geometry and images separate means extra coordination – if a point is deleted we have to find the image as well.

The end goal was an image associated with a GIS feature. I came up with a better solution. We could just use a blob field and put the photo in the database as a field. As I was starting to work on it, I remembered ArcGIS allows attachments. It will accept a blob and handle the relation between the geometry and the point features. This would be the best solution.

I created my feature class and enabled attachments. Now, using the ESRI REST API, I can upload attachments (images) using a form with the action set to the url of the service:

http://ServerName/arcgis/rest/services/ServiceName/0/OBJECTID/addAttachment

This solution is much simpler than the Node.js solution. first, it doesn’t require a new server application – it uses our already running ArcServer. I don’t have to justify to the IT Department my use of Node.js – ArcServer is already allowed.  Finally, the relationship between the feature and the images are handled by ArcServer. If a point is deleted, so is the image.

My final application displays a map. When you click on the map a point is placed and a popup is opened. The popup contains a combo box that allows you to select the feature class for your point. Using the REST API, the point is added to the feature class. The popup content then changes to the attachment upload form. You can click the select button and the camera application is launched on your phone. Once an image is captured, you click submit and a new tab opens showing the result of the file upload. I have a separate map application that displays the points from the feature classes with a popup detailing the associated attachments for viewing and downloading.