Thursday, 7 April 2016

Updating a Google map using HTML radio buttons

I have markers on a Google Map created with the Google Map API. How do I update the map to show other markers on the basis of a HTML radio button selection? This is quite simple to implement.

The following HTML code (refresh.html) is adapted from the Google Map Hello World example. Three radio buttons are added above the map that share the same name place. Each button has an onclick() methods defined that call the myredraw() function that is defined in the an external Javascript file named refreshlib.js that is in the same directory as the HTML file.


<!DOCTYPE html>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <title>Radio button markers</title>
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      #map {
        height: 100%;
  // initMap function loads the default map and markers.
     function initMap() {
        var myLatLng = {lat: -25.363, lng: 131.044};

        var map = new google.maps.Map(document.getElementById('map'), {
          zoom: 4,
          center: myLatLng

        var marker = new google.maps.Marker({
          position: myLatLng,
          map: map
 <!-- Load Google Maps API once page fully parsed -->
    <script async defer
 <!-- Link to external Javascript file -->
 <script type="text/javascript" src="refreshlib.js"></script>
 <!-- Three radio buttons named 'place' -->
  <input type="radio" name="place" value="1" checked onclick="myredraw(this);" /> 1<br>
  <input type="radio" name="place" value="2" onclick="myredraw(this);" /> 2<br>
  <input type="radio" name="place" value="3" onclick="myredraw(this);" /> 3
 <!-- The HTML division within which the map is displayed -->
    <div id="map"></div>

 The myredraw() function first creates an array that contains the  HTML elements named 'place', i.e. the radio buttons. This array is looped though until the the checked element is located.
The value of the checked element is obtained (radio_value) and an if...else if...else clause used to
create a Google Maps LatLng object with a different coordinate pair.
The map division is then obtained, and the new zoom and map center set. Finally a new marker is added.


function myredraw() {
 // Get array of input objects named 'place'
 var radios = document.getElementsByName('place');
 // Loop through the array of HTML elements named 'place'
 // and return the value of the checked radio button.
 for (var i = 0, length = radios.length; i < length; i++) {
  if (radios[i].checked) {
   // Get value of checked
   var radio_value = radios[i].value;
   // only one radio can be logically checked, don't check the rest
 // Conditional clause in now used to specify what occurs
 // depending on the value of the checked radio button.
 // In this case a Google Maps LatLng element is created with 
 // different coordinates.
 if (radio_value == 1) {
  var myLatLng = {lat: -25.363, lng: 131.044};
 } else if (radio_value == 2) {
  var myLatLng = {lat: 50, lng: 135};
 } else {
  var myLatLng = {lat: 3, lng: 145};

 // map div ig obtained forom 
    var map = new google.maps.Map(document.getElementById('map'), {
       zoom: 4,
       center: myLatLng
     var marker = new google.maps.Marker({
        position: myLatLng,
        map: map

Tuesday, 31 March 2015

Some useful videos on basic hydrological modelling in ArcGIS

OpenTopography: Compute watershed grids: fill, flow direction, and flow accumulation 


 Usman Buhari: ArcMap 10.2: Hydrology analysis using ArcGIS.


 Karl Olsen: ArcGIS - Hydrology Tools


How to convert an ArcGIS flow accumulation layer into a "Boolean" stream layer

A flow accumulation layer is a continuous raster that stores the number of upstream raster cells that flow into each cell. As water accumulates in cells as it flows downhill, higher accumulation values should correspond to larger streams. To create vector stream channel lines from a flow accumulation layer it must first be reclassified to a Boolean layer that defines if a channel exists within each cell or not. To do this a flow accumulation threshold must be set that defines how much flow a cell must have to be identified as a 'channel'. 

Boolean layers contain store one of two values in each cell that represent either 'true' or 'false' ('yes'/'no') in respect of the entity being modelled. In Boolean mathematics, "true" is assigned the value '1', and false '0'. But in some situations, including reclassifying  an ArcGIS flow accumulation layer, data needs to classed '1' for 'true' and 'NoData' for 'false'.

In the HydroGIS practical, you create a flow accumulation layer from your hydrologically correct DEM. Flow accumulation ranges from 0 (no flow from no other cells flow into this cell) to 10119 (the number of upstream cells that flow into a cell).

To convert the flow accumulation surface into vector stream channel lines you must select a threshold flow accumulation value above which a cell is defined as containing a stream channel (channel = 'true'), and below which no channel is present (channel = 'false'). This threshold determines the density of stream lines that will be created. A higher threshold will result in fewer stream cells than a lower threshold.

A good way to select a threshold is to change the symbology of the flow accumulation layer so that it only displays cells with values above the threshold. You can then view the density of channel cells before creating your Boolean channel raster layer.

Open the flow accumulation Layer Properties and select the Symbology tab. Now set the layer to show two classified values. The class containing lower values represents 'false' cells that do not contain stream channels. The class containing higher values 'true' cells that contain channels. Select the Classify... button to change the threshold between the two classes.
See how a flow accumulation threshold to 3036 results in very few stream channel cells (above), whereas a threshold of 100 defines many more stream channel cells (below).

When you have chosen your threshold, use the Spatial Analyst Reclassify tool to create a 'Boolean' raster that stores '1' in channel cells and 'NoData' in non-channel cells. To do this you must change the 'New values' from the default incremental integer classes to '1' and 'NoData'.

The 'Stream to Feature' tool in the Hydrology tool set can now be used to generate vector streamlines from this 'channel layer' (Input stream raster) and the flow direction raster for the hydrologically correct DEM the stream lines were derived from.

Friday, 6 March 2015

How to find flat triangles in a TIN

Flat triangles and edges are common artifacts in triangular irregular network (TIN) surfaces created from contour line. They occur where the three nodes of a triangle, or the two nodes of a triangle edge, are derived from the same elevation contour. They are artifacts of the model which do not represent the true elevation at these places.

Flat triangles and edges can be located in a number of ways in ArcGIS.

  1. Display the original contour lines or the TIN soft-edges over the TIN model and look for triangles and edges in with nodes derived from contour lines with the same elevation.
  2. Use the Information tool to explore how values change within a triangle or along an edge. If all values are the same it is flat.
  3. Display the TIN in ArcScene and look for "flat looking" triangles. Confirm with the information tool.
  4. Render the TIN to show slope. In the TIN Symbology tab Add... a Face slope with graduated color ramp renderer.  Now change to symbology levels to differentiate triangles with very low slope from those with a slope.

The red triangles are flat or very nearly flat.

ArcGIS Background Processing error

If a tool returns a Background Processing error then you should try running the tool with background processing turned off.

To turn off background processing select Geoprocessing Options... from the Geoprocessing menu and, in the dialog, uncheck the Enable Background Processing checkbox.

Disabling background processing means that you cannot work in ArcGIS until tools have finished working. A minor issue compared to the tool not working at all. If this does not fix the problem then report it to the KU IT Helpdesk and the module leader.

ArcGIS: Tool Not Licensed error

You will get a "Tool Not Licensed" error when trying to use an ArcGIS Tool, such as Create TIN or Flow Direction, and the ArcGIS Extension that the tool is part of is not enabled.

To use the tool you must active the extension. The error dialog should inform you which extension the tool is part of. In this case the Flow Direction tool is part of the Spatial Analyst extension, whereas the Create TIN tool is part of the 3D Analyst extension.

To enable extensions, select Extensions.. from the Customize menu and check the extensions that you need. The tool should now work.

Tuesday, 2 December 2014

HTML checkboxes, Javascript and PHP

So you want to select one or more HTML checkboxes and then use Javascript call a PHP program that returns data from a database usingan SQL query that OR's the checked items?

In this example, data on London Tube Stations in one or more zones is extracted from a MySQL database when any of the check boxes for zones is toggled.


First we need to write the HTML to display a check box for each zone. When the user checks, or unchecks, the getstations() Javascript function fires. This program posts an HTTP get request to stations.php, which returns information on stations. The results are written to an HTML div. For brevity only three zones are coded.

      <title>Checkbox Example</title>  
      <script type="text/javascript" src="stations.js"></script>  
      <script type="text/javascript" src="utils.js"></script>  
           <h1>Display Stations in Zones</h1>  
                <input type="checkbox" name="zone" value="1" onclick="getstations();"> Zone 1<br>  
                <input type="checkbox" name="zone" value="2" onclick="getstations();"> Zone 2<br>  
                <input type="checkbox" name="zone" value="3" onclick="getstations();"> Zone 3<br>  
           <h2> Stations</h2>  
           <div id="stations">  


We shall now write a PHP program that returns an XML file containing data on the stations. Data is encoded as attributes within station tags.

   // Make a MySQL Connection  
   $connection = mysql_connect("localhost", "root", "");  
   if (!$connection) {  
    die('Not connected : ' . mysql_error());  
   // Use the kyr_db DB  
   $db_selected = mysql_select_db("kyr_db");  
   if (!$db_selected) {  
    die ('Can\'t use db : ' . mysql_error());  
   // get the zone HTTP parameter  
   $zone_list = $_GET["zones"];  
   // Explode comma separated list of zones  
   $zones = explode(",",$zone_list);  
   // Build SQL Query  
   // The query needs an OR operator inserted for the second and subsequent clauses.  
   $query = "SELECT * FROM kyr_london_tube_stations WHERE";  
   $or = 0;  
   foreach ($zones as $zone) {  
           if ($or == 0) {  
                $query = $query . " zone = " . $zone;  
                $or = 1;  
           } else {  
           $query = $query . " OR zone = " . $zone;  
   // Retrieve data from the stations table  
   $result = mysql_query($query);  
   if (!$result) {  
    die('Invalid query: ' . mysql_error());  
   // Set the content type, then write the XML file  
  header ("Content-Type:text/xml");  
   // Open shapes tag  
   echo '<stations>';  
   // Loop through results extracting values   
   while ($row = mysql_fetch_array($result)) {  
           $name = htmlentities($row['NAME']);  
           $zone = htmlentities($row['ZONE']);;  
           echo '<station name="' . $name . '" zone="' . $zone . '"/>';   
   // Close shapes tag  
  echo '</stations>';  
   // Close database connection  


Finally, need to write the getstations() Javascript function that will make an AJAX request to the MySQL database. This function calls the downloadUrl() function in utils.js to undertake the XmlHttpRequest.

 function getstations() {  
       var zones = document.getElementsByName("zone");  
      var zone_ids = [];  
      var text = "";  
      // Clear text in div  
      document.getElementById("stations").innerHTML = text  
      for (var i = 0; i < zones.length; i++) {  
           if (zones[i].checked) {  
      if (zone_ids.length > 0) {  
           var ids_list = zone_ids.toString();  
           url = "stations.php?zones=" + ids_list;  
           downloadUrl(url, function(data) {  
                var rows = data.documentElement.getElementsByTagName("station");  
                if (rows.length > 0) {  
                     for (var i = 0; i < rows.length; i++) {  
                          text = text + rows[i].getAttribute("name") + " " + rows[i].getAttribute("zone") + "</br>";  
                // Write text to div  
                document.getElementById("stations").innerHTML = text;