Wednesday, January 31, 2024

The Five Minute Fantasy Map Maker

This is Middle England an interactive fantasy map which I made in under 5 minutes, using World Anvil. Middle England is a sacred a magical realm steeped in the ancient lores of rune-crafting, dream-weaving and alchemy.

World Anvil bills itself as a "Worldbuilding Toolset & RPG Campaign Manager Created for Writers, Gamemasters & Creatives". One of the tools in this tool-set is a map wizard which allows you to create an interactive fantasy map from any static image. Creating an interactive fantasy map with World Anvil is as simple as uploading an image file of your map and then pointing to where you want to add markers.

Before using World Anvil I created the Middle England map using Azgaar’s Fantasy Map Generator. The Fantasy Map Generator is an impressive procedural map generator, which can be used to create and edit fantasy maps. The tool comes with a number of options which allow you to control the look and design of your generated fantasy map. When you are happy with the result you can then download your map as a still image.

This static image map can then be turned into an interactive fantasy map with World Anvil. After registering with World Anvil you simply need to upload the static image of your fantasy map and it will automatically turn it into an interactive map which can be panned and zoomed. The free version of World Anvil allows you to add markers to your fantasy map. If you become a paying subscriber you can unlock more tools which then allow you to also add map labels, polylines and polygons to your map.

 

Tuesday, January 30, 2024

Using AI to Age OSM Maps

The screenshot above, from the SynthMap Demo, shows a side-by-side view of an Open Street Map and an AI generated map of the same OSM data changed to look like a 19th Century era Ordnance Survey map. This Victorian cosplaying map (on the right) was developed by Zekun Li, of the University of Minnesota, who trained an AI to transform OpenStreetMap data into images that resemble the style of early British Ordnance Survey maps.

As you can see the results of this attempt to Generate synthetic historical maps from OSM map tiles is very impressive. But what is the point of an artificially aged digital map? I hear you ask! To which question there is a very good answer. These synthetically generated vintage maps are being created in order to teach AI models how to read historic maps.  

You may remember that in August of last year the David Rumsey Map Collection unveiled a new Text on Maps feature which allows you to search one of the world's largest collections of digitized maps by text. Using this new Text on Maps feature you can now search for any word in order to see where it appears on any of the collection's 57,000+ vintage maps. For example here are the results for searching 57,000 vintage maps for gold mine.

The reason that we are now able to search the David Rumsey Map Collection for individual words on vintage maps is because of huge advances in AI text recognition. Zekun Li's generated synthetic maps make AI models tasked with reading map labels even better. These AI generated maps closely resemble historical maps in style but have accurate 21st-century label information. Which means that the AI text recognition models can actually be trained on maps which have visual challenges similar to those in the actual vintage maps, but also have text labels which we know are accurate.This 'clean' data can then be used to train AI text recognition models on how to see and read map labels on real vintage maps. 

You can read more about Zekun Li's work on Maps with a sense of the past: what are synthetic maps, and why do we love them? on the National Library of Scotland blog.

Monday, January 29, 2024

Styling with Bard

This is the latest episode in my ongoing project to build a Meet in the Middle map using code suggested by Bard. Today's aims are mainly to improve the design and UI of the map.

First up I want to improve the design of the buttons used on the map.

Prompt No.1:

Give me the css styles to create a flat design button


To which Bard suggested:
Absolutely! Here's the CSS for a basic flat design button:

CSS
.flat-button {
  background-color: #4CAF50; /* Change this to your desired color */
  color: #fff;
  padding: 10px 20px;
  border: none;
  border-radius: 5px; /* Adjust corner roundness here */
  font-size: 16px;
  font-weight: bold;
  cursor: pointer;
  transition: all 0.2s ease-in-out;
}

.flat-button:hover {
  background-color: #388E3C; /* Adjust hover color here */
}

.flat-button:active {
  transform: scale(0.95); /* Slight "press" effect on click */
}
Now we just need to assign this CSS style class to our buttons.

Prompt No.2:

How can I add the class 'flat-button' inline to this button - <button id="enter">Calculate Midpoint</button>


Bard replied:
Add the class 'flat-button inline within the HTML: 

<button id="enter" class="flat-button">Calculate Midpoint</button>

Now our buttons look a lot nicer! Next-up I'd like to use fitbounds to adjust the map when the midpoint marker is added to the map. This should ensure that the map nicely frames the three user added markers when the midpoint marker appears.

Prompt No.3:

in leafletjs I have three markers defined in javascript

'var latA = markerA.getLatLng().lat;  var lngA = markerA.getLatLng().lng;  var latB = markerB.getLatLng().lat;  var lngB = markerB.getLatLng().lng;  var latC = markerC.getLatLng().lat;  var lngC = markerC.getLatLng().lng;'

How can I make the map fit the bounds of all three markers?


Bard responded with:
 Here's how you can make the Leaflet map fit the bounds of all three markers using JavaScript:

// Get the LatLng objects of the markers
  const markerALatLng = markerA.getLatLng();
  const markerBLatLng = markerB.getLatLng();
  const markerCLatLng = markerC.getLatLng();

  // Create a LatLngBounds object that encompasses all three markers
  const bounds = new L.LatLngBounds([
    markerALatLng,
    markerBLatLng,
    markerCLatLng
  ]);

  // Fit the map to the bounds
  map.fitBounds(bounds);
Now when the midpoint marker is added the map also zooms to neatly encompass all three user added markers.

It's time to give Bard a more difficult challenge. Currently Our Meet in the Middle map calculates the midpoint between three different locations. This isn't very useful if only two people want to meet. So it would be nice to offer our users the option to calculate a midpoint between just two different locations.

First up we need to add another button to the map which will display after the second marker has been added to the map. This button will give the users the option to calculate a midpoint between only two locations, instead of adding another (third) location to the map.

Prompt No.4:

In this Javascript statement can you add a button with the id 'meet2' to the innerHTML -

' // update the message in the 'instructions' div document.getElementById("instructions").innerHTML = "Now add the third marker to the map.";


Bard suggested:
// Update the message and add a button to the 'instructions' div
document.getElementById("instructions").innerHTML =
  "Now add the third marker to the map. <button id='meet2'>Click me</button>";
Now a new button appears after the seceond marker is added to the map. However nothing happens when we press it. We now need to ask Bard to write a function for this button so that when it is pressed a midpoint is calculated between markerA and markerB and a third (midpoint) marker is added to the map.

I copied the JavaScript of the existing calculateMidpoint() function into Bard and gave it the following prompt:  

Prompt No.5:

Create another function in Javascript exactly like this function only have it calculate a midpoint between MarkerA and MarkerB (ignoring Marker C completely).


Bard replied first time with:
function calculateMidpointAB() {
  var latA = markerA.getLatLng().lat;
  var lngA = markerA.getLatLng().lng;
  var latB = markerB.getLatLng().lat;
  var lngB = markerB.getLatLng().lng;

  // Calculate the midpoint between MarkerA and MarkerB
  var midLat = (latA + latB) / 2;
  var midLng = (lngA + lngB) / 2;

  // Create a LatLngBounds object only for MarkerA and MarkerB
  const bounds = new L.LatLngBounds([
    markerA.getLatLng(),
    markerB.getLatLng()
  ]);

  // Fit the map to the bounds of MarkerA and MarkerB
  map.fitBounds(bounds);

  // Create a marker for the midpoint
  var midpointMarker = L.marker([midLat, midLng]).addTo(map);
  midpointMarker.bindPopup("I'm the midpoint between A and B!");

  // Rest of the code remains the same, as it doesn't involve MarkerC
  // Share to Twitter, add button, fetch coffee shops, etc.
}
Now by simply adding an event listener to our 'meet2' button:
document.getElementById("meet2")
.addEventListener("click", calculateMidpointAB);
we have a Meet in the Middle map which works for either 2 or 3 person meet-ups.

Next-up I think it might be nice to offer users the choice to find nearby restaurants or bars, as an alternative to nearby coffee-shops.

The Interactive Anime Atlas

The Anime Site Mapping Project is a mapping project dedicated to plotting the real-world locations that are featured in popular anime series. It's like a giant treasure hunt for anime fans, but except instead of discovering gold, you can uncover the real-world cafes, shrines, and scenic vistas that inspired your favorite anime shows.

Currently the Anime Site Mapping Project consists of four main interactive maps. Three of the maps are dedicated to individual anime shows: Heya Camp, Kimi no Na wa and Yuru Camp. The fourth, main map allows you to explore the real-world locations of all three of the featured anime shows on one map. 

The Kawai Miyagawa Bus Stop, as feattured in Kimi no Na wa

The real fun for me though is hidden in the individual episode breakdowns for each anime series. On these episode pages individual locations featured in each episode of a show are listed with links to Open Street Map and Google Maps. Follow the Google Maps link and you can then compare an actual still of the anime depiction of the location with the real location on Google Maps Street View.

Via: Weekly OSM

Sunday, January 28, 2024

Using the Overpass API with Leaflet

In part 4 my AI Map Challenge I want to see if Bard can write some JavaScript code which will query the Overpass API for coffee shops located 500 meters around the midpoint location calculated by users of my Meet in the Middle map. I then need Bard's help to process the response and add markers showing the locations of all the coffee shops found by Overpass.

Prompt No.1:


using javascript is it possible to use the Overpass API to add the locations of cafes on a leaflet.js map


To which Bard responded: 
I'm designed solely to process and generate text, so I'm unable to assist you with that.
I then asked Bard "What is the Overpass API?" to which it gave a very long response, which included the example that it could be used to "Find bike lanes and repair shops near the user's location". This led me in turn to ask "How would I use the api to 'Find bike lanes and repair shops' near the user's location?" To which Bard finally gave me some JavaScript in its reply:

const userLatitude = /* user's latitude */;
const userLongitude = /* user's longitude */;
const radiusInMeters = 500; // adjust this based on your desired search area

const query = `
[out:json];
way[highway=cycleway](around:"${userLatitude},${userLongitude}",${radiusInMeters});
way[amenity=bicycle_repair](around:"${userLatitude},${userLongitude}",${radiusInMeters});
`;

// Send the query to the Overpass API
fetch("https://overpass-api.de/api/interpreter?data=" + encodeURIComponent(query))
  .then(response => response.json())
  .then(data => {
    // Process the data and display it on the map
  })
  .catch(error => console.error(error));
Unfortunately I want to find nearby coffee shops rather than bike lanes and repair shops.

After a very long and tedious conversation with Bard I failed to create a working Overpass query for finding coffee shops around a location. I almost gave up at this point but thought it might be worth asking ChatGPT instead. 

Prompt No.2:


Can you write a query in javascript to the Overpass API which will return "cuisine"="coffee_shop" in a radius of 500 meters around a location of 51.505,-0.0.9


To which ChatGPT responded: 
const overpassQuery = `
    [out:json];
    node["cuisine"="coffee_shop"](around:500,51.505,-0.09);
    out;
`;

fetch('https://overpass-api.de/api/interpreter', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: 'data=' + encodeURIComponent(overpassQuery)
})
.then(response => response.json())
.then(data => {
    // Process the data returned by the Overpass API
    console.log(data);
})
.catch(error => {
    console.error('Error fetching data:', error);
});
This actually works. So I simply need to change the 'around' search to '500, ${midLat},${midLng}' in order to use the location of the calculated midpoint in my map.

In ChatGPT's code the data returned by the Overpass API is just being sent to the developer console ('console.log(data)'). So I also now need to process the json response from the Overpass API and add the found coffee shops to my Meet in the Middle map. 

Prompt No.3:


Can you use the returned date from the Overpass API to add a marker to a Leaflet.js map for each coffee shop?



To which ChatGPT replied:

// Send the query to the Overpass API
fetch('https://overpass-api.de/api/interpreter?data=' + encodeURIComponent(query))
    .then(response => response.json())
    .then(data => {
        console.log(data);
        // Create markers for coffee shops
        const coffeeShopMarkers = data.elements.map(element => {
            const coordinates = [element.lat, element.lon]; 
            const marker = L.marker(coordinates);

            // Add a popup with the coffee shop's name (if available)
            if (element.tags.name) {
                marker.bindPopup(element.tags.name);
            } else {
                marker.bindPopup('Coffee Shop'); // Fallback popup text
            }

            return marker;
        });

        // Add the markers to the map (assuming you have a Leaflet map instance named 'map')
        map.addLayer(L.layerGroup(coffeeShopMarkers));
    })
Success!

So my Meet in the Middle map is now able to calculate the midpoint between three different locations. Show the locations of coffee shops in a 500 meter radius around that location. It also includes a button which allows the user to tweet a link to a shared map of the calculated midpoint location.

Saturday, January 27, 2024

Adding URL Parameters to an Interactive Map

It's Saturday so I have decided to give myself a 30 minute break. Today I will only be spending ½ an hour on the One Hour AI Map Challenge. In these 30 minutes I want to create URL parameters for Meet in the Middle which will allow us to replace the Google Maps link for shared meeting points with a link back to our own map.

Prompt No.1:


how can i add url parameters to a leaflet.js map to show the lat,lng and zoom


In response to this prompt Bard provided me with the following code:
const urlParams = new URLSearchParams(window.location.search);
const lat = parseFloat(urlParams.get('lat'));
const lng = parseFloat(urlParams.get('lng'));
const zoom = parseInt(urlParams.get('zoom'));

const map = L.map('map').setView([lat, lng], zoom);

map.on('moveend', () => {
  const center = map.getCenter();
  const zoom = map.getZoom();
  history.pushState(null, null, `?lat=${center.lat}&lng=${center.lng}&zoom=${zoom}`);
});

if (lat && lng && zoom) {
  map.setView([lat, lng], zoom);
} else {
  // Set default view if no parameters are present
}
This looks to be almost exactly what I want - except for the 'moveend' function. I don't need the map URL parameters to update every time the map is panned. So I can ignore that function. However I do need to remove the link to Google Map that gets posted to Twitter with a Meet in the Middle URL with our midpoint parameters. Which you can do like this:
https://meet-middle.glitch.me/?lat=" + midLat + "&lng=" + midLng + "&zoom=15
Now when the user presses the 'share' button they can post a link to their meet in the middle (or midpoint) location. When anyone clicks on that link they will be taken to a map centered on the midpoint location. 

However it would be nice to also show a marker at the midpoint location.

Prompt No.2:


is it possible to add a url parameter 'marker=yes'


To which Bard suggested: 
1. Retrieve the marker Parameter:  

const urlParams = new URLSearchParams(window.location.search);
const showMarker = urlParams.get('marker') === 'yes'; // Check if 'marker=yes' is present 

2. Conditionally Add the Marker:

if (showMarker) { const marker = L.marker([lat, lng]).addTo(map); // Create and add marker if 'marker=yes' }
So after around 15 minutes we should have a 'share' button which posts a URL with parameters which will link to our calculated midpoint. Well yes - except that you may have noticed in Bard's response to Prompt No. 1 a little bit of missing code:
else {
  // Set default view if no parameters are present }
It actually took me an additional 10 minutes of discussion with Bard to get the map to load with the default values if the URL to Meet in the Middle has no parameters. Which leads me nicely to this admission:

Important Caveat

These transcripts of my conversations with Bard have been edited for brevity's sake. Anyone who has used a generative AI will know that it often takes a number of prompts to retrieve an acceptable/working answer or response from the AI.

Therefore, for the sake of brevity, these transcripts often jump straight to the prompt which returned the response from Bard which actually worked.

This may give the reader a false impression that Bard provides flawless responses that work 100% of the time. This certainly isn't true. Which is where developer tools come in very handy. If you can identify errors using developer tools then you can more easily help Bard identify any errors in its suggested code (or in your implementation of Bard's suggested code).

If you want a recap (or missed the first two posts) then check out: 

America's Disappearing Birds

The Washington Post has used data from eBird to map the changes in the populations of individual bird species in the United States. In the last 50 years the US bird population has fallen by nearly 30 percent. In Bird Populations are Declining the Post has used eBird data to create a series of bird population maps for individual species of American birds.

The Post article includes an interactive table which allows you to explore the abundance of 26 different bird species in any US city. This table uses bird sightings reported to eBird to calculate the "number of individuals (of each species) you could expect to see if you went birding for one hour over two kilometers". As well as showing the abundance of each species of bird the table also shows the percentage change of the species over the last ten years (2012-2022).

At the end of the article is an interactive map of the United States which allows you to visualize the population change of hundreds of different bird species. Select a species of bird and the map shows the abundance of the species across the country and the percentage change of the species (2012-2022). On this map the size of the data points represents the abundance of the bird species at that location, while the color of the points represents the percentage change in the species population. 

Friday, January 26, 2024

The 3rd Hour of the 1 Hour AI Map Challenge

In the first two hours of the One Hour AI Map challenge I created a very basic Meet in the Middle interactive map. If you want a recap (or missed the first two posts) then check out:

One Hour AI Map Challenge - Part One
One Hour AI Map Challenge - Part Two

After the first two hours of chatting with Bard I managed to create a map which could accept three different locations and work out the midpoint between these three locations and add a marker to the map to indicate this midpoint location.

In the third hour of the One Hour AI Map Challenge I want Bard to add custom numbered markers (1, 2 & 3 ) to the map. I also want to add a 'share' button to the map which will post a message ('Let's meet here') to Twitter with a link to the midpoint location on Google Maps.

Prompt No.1:


How do I add a custom marker to a marker with the variable name 'markerA' in Leaflet.js


To which Bard responded with:
const myIcon = L.icon({
  iconUrl: 'https://your-website.com/marker.png',
  shadowUrl: 'https://your-website.com/marker-shadow.png',
  iconSize: [32, 32], // size of the icon image
  shadowSize: [48, 32], // size of the shadow image
  iconAnchor: [16, 32], // point of the icon which will correspond to the marker's location
  shadowAnchor: [16, 24] // point of the shadow that will be positioned below the icon
});

const markerA = L.marker([lat, lng], {icon: myIcon}).addTo(map);
I then downloaded three numbered markers from the Map Icons Collection and uploaded them to the same server as the Meet in the Middle map. I used Bard's suggested code to create three marker variables (aIcon, bIcon & cIcon) and added the correct marker to the markerA, markerB and markerC variables. 

Our map now has numbered markers. 

Next I want to add a 'share' button after the midpoint marker is added to the map, so that users can share their meeting location with friends. 

Prompt No.2:


after this javascript statement use innerhtml to add a button with an id of 'share' to an element called 'instructions' -

var midpointMarker = L.marker([midLat, midLng]).addTo(map); midpointMarker.bindPopup("I'm the midpoint!");


Bard's suggestion was:
var midpointMarker = L.marker([midLat, midLng], {draggable: true}).addTo(map);
midpointMarker.bindPopup("I'm the midpoint!");

// Add the button using innerHTML
document.getElementById('instructions').innerHTML += '<button id="share">Share</button>';
This will add a 'share' button next to our 'Calculate Midpoint' marker. We actually want the 'share' button to replace the 'Calculate Midpoint' button so I omitted the '+' symbol from the line - 
document.getElementById('instructions').innerHTML += '<button id="share">Share</button>';
Now after the midpoint marker is added to the map we have a 'share' button. All we need to do now is add an event to the 'share' button which will post a message to Twitter when pressed.

 

Prompt No.3:


Add an event listener to the 'share' button which will call a function called' shareToTwitter'


To which Bard suggested:
document.getElementById('share').addEventListener('click', shareToTwitter);

Now all we need to do is write the function!

 

Prompt No.4:


Prompt No.4 failed miserably


After 10-15 minutes of heated discussion Bard failed to write a usable function for posting a message to Twitter. Luckily I have been down this road before so was able to write the function myself. Here is my function:
function shareToTwitter() {
var twtLink = "https://twitter.com/intent/tweet?text=Let's%20meet%20here:%20" +
encodeURIComponent("https://www.google.com/maps/@" + midLat + "," + midLng + ",15z");
}

// Add the button using innerHTML
document.getElementById("instructions").innerHTML = '<button id="share">Share</button>';
document.getElementById("share").addEventListener("click", shareToTwitter);

Now when the user presses the 'share' button a message will be posted to Twitter with a link to our meeting point on Google Maps. In future discussions we might ask Bard to create a link back to the meeting point on the Meet in the Middle map.

In summary the third hour of the One How AI Map Challenge was a little disappointing. I had to break the rule that all the JavaScript for the map was produced by Bard. Never mind, the adventure will continue.

In the fourth hour we could ask Bard to make our buttons a little more attractive. We also still need an option to create a midpoint between 2 or 3 (or more) points. We also need to change the Google Maps link to a link back to the meeting point on the Meet in the Middle map.


Local Explorer

During the travel restrictions imposed under the Covid epidemic I became much more interested in local history and my local environment. In order to avoid becoming stir crazy I became an intrepid local explorer. 

Instead of traipsing day-after-day around the same old streets I decided to reinvigorate my daily walking exercise by trying to discover new places to visit nearby and by discovering more about local history. In this endeavor I relied heavily on wiki maps - interactive maps which plot the locations of places featured on Wikipedia.

A great example of a wiki map is NearbyWiki. Share your location with NearbyWiki and it will show you a local map marked with all the interesting places nearby which are listed on Wikipedia. The map also includes a number of features which can greatly aid any intrepid local explorer. 

Click on any of the nearby local markers on the NearbyWiki map and an information window opens with a short excerpt from the location's Wikipedia article. This window also tells you how far this location is from your home (or the location you shared with NearbyWiki). For those users like me using NearbyWiki to plan walks you can bookmark any locations that you are keen on visiting. Each entry also includes a list of other nearby places featured on Wikipedia, making it very easy to discover other places that you can visit on a planned walk.

 

Once upon a time Google Maps itself had a very useful Wikipedia layer. This Google Maps layer was a fantastic way to learn about all the interesting, historical points of interest around your location. It was definitely one of the most useful functions on Google Maps. So Google got rid of it.

Luckily there are a number of other interactive maps like NearbyWiki which can help you learn more about the world around you using information posted to Wikipedia.

Wikimap is another great example of an interactive map of geo-tagged Wikipedia articles. Zoom in on any area of the world on Wikimap and map markers will reveal all the nearby locations which have entries on Wikipedia. Click on any of these markers and you can read a short introduction to the selected point of interest and click-through to read the whole entry on Wikipedia. 


You can also find nearby points of interest using Wiki Atlas. Open up Wiki Atlas and you can again immediately view all the places around you which have a Wikipedia entry. Click on any of the mapped links and you can read the entry directly from the map. 

All the locations with a Wikipedia entry are shown on Wiki Atlas using colored markers. The colors of the markers indicate the category of the Wikipedia entry (culture, geo, society or STEM).  

Like Wiki Atlas and Wiki Map Geopedia can be used to find and read Wikipedia entries about points of interest around any location. Geopedia uses the Wikipedia API to load all the Wikipedia entries for places around a location on an OpenStreetMap based map. Enter a location into the search bar or right-click on the map and markers will show all the Wikipedia entries near your chosen location.

If you want to discover more about nearby points of interest then you can also use Wikimapia. Wikimapia is one of the most successful interactive maps of all time. For over 13 years Wikimapia has provided a great map based resource for discovering information about locations and points of interest around the world.


In essence Wikimapia is a website which lets you describe locations in the same way that Wikipedia allows you to add and edit articles in its wiki database. Like Wikipedia it provides an invaluable resource for researching and discovering information about the world - except with Wikimapia every entry is a real-world location.

To use Wikimapia you just need to search for a location on the map. and click on any of the highlighted areas to discover information about the selected location. For example, if you see an interesting looking building on your daily travels, you just need to click on the building on the Wikimapia map to read its Wikimapia wiki entry.

The 2nd 1 Hour AI Map Challenge

Every day I am using Bard for one hour to create a Meet in the Middle interactive map. The only real rule I have set for this challenge is that all the JavaScript code for the map has to be written by Bard. 

After spending an initial one hour with Bard yesterday I managed to create a very simple map which allows a user to add two locations (by clicking on the map), then calculates the midpoint between these two locations and finally adds a third marker on that calculated midpoint location. It is in essence a very simple map to work out a midway point to meet between two separate locations.

After spending a second hour with Bard today I wanted the map to be able to accept three different locations (markerA, markerB and markerC) and to work out a midpoint between all three locations and add a marker to that midpoint location. I also want to provide instructions to inform the map user what to do.

TLDR - Here is the completed map after a second hour with Bard - Meet in the Middle.

Prompt No. 1:


add another else statement to the if statement which will add another marker and give it the name 'markerC' -

Bard responded with
if (markerCount === 0) { marker = L.marker([lat, lng]).addTo(map); markerA = marker; marker.bindPopup("I'm marker A!"); } 
else if (markerCount === 1) { marker = L.marker([lat, lng]).addTo(map); markerB = marker; marker.bindPopup("I'm marker B!"); measureDistance(markerA, markerB); } 
else { marker = L.marker([lat, lng]).addTo(map); markerC = marker; marker.bindPopup("I'm marker C!"); 
// You can potentially add logic here to calculate the center of all three markers 
}

Notice how Bard suspects that I now want to be able to calculate a midpoint between all three markers. I do!

Prompt No.2:


update the calculateMidpoint function to calculate a midpoint between all three markers (markerA, markerB and markerC)

Bard returned the following function (and told me that it could be called by adding 'calculateMidpoint() where it had left the comment ' // You can potentially add logic here to calculate the center of all three markers'): 
function calculateMidpoint() {
  var latA = markerA.getLatLng().lat;
  var lngA = markerA.getLatLng().lng;
  var latB = markerB.getLatLng().lat;
  var lngB = markerB.getLatLng().lng;
  var latC = markerC.getLatLng().lat;
  var lngC = markerC.getLatLng().lng;

  var midLat = (latA + latB + latC) / 3;
  var midLng = (lngA + lngB + lngC) / 3;

  // Create a marker for the midpoint
  var midpointMarker = L.marker([midLat, midLng]).addTo(map);
  midpointMarker.bindPopup("I'm the midpoint!");
}

Prompt No.3:

Before my next prompt I changed the CSS style of the map element to 'height: 90%;' and added an 'instructions' element under the map. I now want to add user instructions to this new element in order to prompt the user to add three markers to the map and, after the third marker has been added, add a button to the map. This button will then be used to calculate the midpoint and add the midpoint marker to the map.

In html I added the message 'Add the first location by clicking on the map' to the 'instructions' element. I now want this message to change after the user has added the first marker.

Here is the prompt I gave Bard to change this message:

In the following javascript else if statement add an innerhtml statement to add the message 'Now add the second marker to the map." to a div element with the id 'instructions' -

else if (markerCount === 0) { markerB = L.marker([lat, lng]).addTo(map); markerB.bindPopup("I'm marker B!");

Bard rewrote the statement to add this new instruction:
else if (markerCount === 0) {
  markerB = L.marker([lat, lng]).addTo(map);
  markerB.bindPopup("I'm marker B!");

  // Add the message to the 'instructions' div
  document.getElementById('instructions').innerHTML = 'Now add the second marker to the map.';
}
I then repeated the prompt to update the markerCount  === 1 statement to change the message to "Now add the third marker to the map'. Now I need to add a button to the instructions for after the third marker has been added to the map.

Prompt No.4: 

in this if statement add an innerhtml statement to add a button with the id 'enter' to an element called 'instructions '-

else { markerC = L.marker([lat, lng]).addTo(map); markerC.bindPopup("I'm marker C!"); calculateMidpoint(); // Call the function to calculate midpoint map.off("click"); // Disable click event after third marker }

Bard's suggested I modified the code thus:
else {
  markerC = L.marker([lat, lng]).addTo(map);
  markerC.bindPopup("I'm marker C!");

  // Add the button to the 'instructions' element
  document.getElementById('instructions').innerHTML = '<button id="enter">Calculate       Midpoint</button>';

  map.off("click"); // Disable click event after third marker
}
Now all that remains is to add a click event to the button to call the calculateMidpoint() function.

Prompt No.5

now add a function to call ' calculateMidpoint();' when the 'enter' button is pressed

Bard does not fail me at the last hurdle and replies:
else {
  // ... (your existing code)

  document.getElementById('instructions').innerHTML = '<button id="enter">Calculate Midpoint</button>';

  // Add event listener to the button
  document.getElementById('enter').addEventListener('click', calculateMidpoint);

  map.off("click"); // Disable click event after third marker
}

In Conclusion

After spending a second hour in conversation with Bard we have managed to create a Meet in the Middle map which can calculate the midpoint between three different locations. We have also added some basic user instructions to the map.

In tomorrow's 1 Hour AI Map Challenge we could ask Bard to customize the three markers with letters (A, B and C) and add a different kind of marker to indicate the final meeting place. We also really need to add some conditional logic to the map so that the user can choose to find a midway point between 2 or 3 locations, depending on whether you are meeting up with 1 or 2 friends.

Thursday, January 25, 2024

One Hour AI Map Challenge

Welcome to the One Hour AI Map Challenge, in which I attempt to make an interactive 'Meet in the Middle' map in under 60 minutes. The only other rule of this challenge is that all the JavaScript code for the map has to be written by Google's generative artificial intelligence Bard.

TLDR - Here is Bard's Meet in the Middle interactive map after 1 hour's work

Over the years I've seen many examples of maps which will work out the best place for two (or more) people to meet. Whatshalfway.com is a good example of a map tool which allows you to find places to meet halfway between two different locations. 

It isn't fair to expect Bard to create a map as good as whatshalfway in only one hour. In fact in 60 minutes I really only want to create a very simple map. This map should: 

1. Have a click event to add two markers to the map based on where the user clicks. 

2. Calculate the midpoint between those two markers 

3. Add a third marker to the map to show the midway point between these two locations. 

Prompt No.1:

My first prompt for Bard was:

Give me the html, css and javascript for a Leaflet.js map with a width & height of 100%

Unfortunately I immediately ran into a problem with Bard's response. The interactive map created from Bard's suggestions didn't work. In fact all I got was a blank web page. However using Chrome's developer tools quickly revealed the problem. Bard's response included an invalid 'digest in the 'integrity' attribute for resource - https://unpkg.com/leaflet@1.9.3/dist/leaflet.js'. In other words the cryptographic hash in the URL for the Leaflet Javascript file is wrong and the Leaflet JavaScript is failing to load in the browser.

No worries. A quick reference to the Leaflet.js Quick Start Guide allowed me to grab the correct Leaflet JavaScript and CSS files. Swapping in the correct Leaflet Javascript and CSS files and we are in action and we actually have a map. 

Time to add some markers to the map.

Prompt No.2:

Add a javascript click event to add a marker to the map

In response to this prompt Bard suggested the following map click event function:
map.on('click', function(e) {
  var lat = e.latlng.lat;
  var lng = e.latlng.lng;
  var marker = L.marker([lat, lng]).addTo(map);
  // Optional customization
  marker.setIcon(L.icon({ iconUrl: '/my-marker-icon.png' }));
  marker.bindPopup("I'm a new marker!");
});
Bard's function worked perfectly and my map could now add a marker when clicked (although I removed the last two lines for adding a customized marker). Now we need a second marker! 

Prompt No.3:

Create another click event to add a marker (markerB) to the map

In response to this prompt Bard gave me another (very similar) function:
map.on('click', function(e) {
  var lat = e.latlng.lat;
  var lng = e.latlng.lng;
  var markerB = L.marker([lat, lng], {
    icon: L.icon({
      iconUrl: 'marker-B-icon.png',
      iconSize: [32, 37]
    })
  }).addTo(map);
  markerB.bindPopup("I'm marker B!");
});
Now my map adds a second marker when clicked for the second time and calls this marker 'markerB' (again I actually omitted the suggested custom marker code). For the sake of coherence I also went back to the function for the first marker and changed its variable name to 'markerA'.

We now have a map which can be clicked on to add two locations. We have a first marker with the name 'markerA' and a second marker called 'markerB'. All we have to do now is calculate the midway point between these two markers and add a third marker to show this midway point on the map.

Prompt No.4:

Find the midway point between markerA and markerB and add a third marker at this point.

In response to this prompt Bard gave me two functions. The first calculates the midpoint between the two clicked locations:
function calculateMidpoint(markerA, markerB) {
  const latA = markerA.getLatLng().lat;
  const lngA = markerA.getLatLng().lng;
  const latB = markerB.getLatLng().lat;
  const lngB = markerB.getLatLng().lng;

  const midLat = (latA + latB) / 2;
  const midLng = (lngA + lngB) / 2;

  return [midLat, midLng];
}
 
and a second function to add a marker at the midpoint:
function measureDistance(markerA, markerB) {
  const midpoint = calculateMidpoint(markerA, markerB);
  const markerC = L.marker(midpoint).addTo(map);
  markerC.bindPopup("Midpoint between A and B");
}
Houston we have a problem! Unfortunately when we now load our map no midpoint marker is added to the map. We can also keep on adding infinite markers to the map. So we need to create a function to remove click events from the map after two markers have been added.

Time for another prompt!

Prompt No.5:

Check if two markers have been added to the map and remove the click events from the map. Add the midpoint marker to the map after markerB is added to the map.

In response to this prompt Bard wrapped the click events inside a counter and removed click events once the counter reached 2.

Finished (for now)

45 minutes after starting work we now have a workable but very, very basic Meet in the Middle map. This map is not going to win any prizes for usability or functionality. However I still think Bard is an impressive aid for programmers. Personally it has replaced Stack Overflow as my default destination for when I get stuck on a problem and find myself banging my head against a brick wall. 

Who knows how our Meet in the Middle Map might be developed if we employ Bard for a second hour? To be continued ...

When is the Coldest Day of the Year?

The coldest day of the year on average occurs at least a month earlier on the western seaboard than it does on the eastern seaboard of the United States.According to NOAA's Coldest Day of the Year interactive map the further west you are in the United States then the more likely you are to have already experienced the coldest day of the year.

NOAA's Coldest Day of the Year map uses 30 years of temperature data to show the average coldest day of the year at thousands of weather stations across the United States. NOAA explains that in the East of the country the "coldest day of the year is typically later ... thanks to cold air from snow-covered parts of Canada dipping down into the area". Thanks Canada.

If you click on a marker on the map you can view the exact date of the average coldest day of the year at that station. The map includes a static key for the colors used on the map. Ideally this scale would also be a filter to control the results shown on the map by date. This would enable the user to more clearly see which areas of the country experienced their coldest temperatures on specific days.

If you have already passed your coldest day of the year then you might want to look forward to your last spring freeze. NOAA's Average Date of Last Spring Freeze interactive map visualizes the last day (on average) when there is a chance for freezing temperatures where you live.

NOAA's last spring freeze map uses temperature data from 1991-2020 captured from weather stations across the United States. The colored dots on the map indicate the average date on which the chance of freezing temperatures drops below 50 percent at each location. 

If you click on a dot on the map you can view the actual date of the average last frost for the selected weather station. Shades of purple are used for locations where the last frost normally occurs before the first day of spring (in mid-March). Weather stations colored with a shade of green indicate locations where the last frost usually comes after the first day of spring. 

If all this talk of freezing temperatures leaves you feeling a little cold then you might want to look forward to the hottest day of the year. NOAA's Warmest Day of the Year map shows the warmest day of the year on average across the United States In most of the United States the hottest day normally occurs between mid-July and mid-August - so you've still got a little time left to order in some sun cream.

Wednesday, January 24, 2024

Plasticine Earth

Google Arts & Culture has used AI to turn the world into colorful dough. In this game your task is to identify famous cultural monuments around the world while turning unformed blobs of plasticine into colorful 3d models of the very same monuments.

Each game of Google Un-Dough starts with a 3D plasticine globe. To begin the game you just need to spin this globe and select the country whose monuments you wish to reveal. Once you have chosen a country you are presented with the image of a blob of colorful dough. You now have to reveal the cultural monument hidden with this plasticine blob by guessing the letters in its name.

In essence Google Un-Dough is a form of hangman which requires you to guess the names of some of the selected country's most well-known cultural monuments or buildings. Each time you guess a letter correctly the colorful blob of dough transforms a little more into the plasticine model of the monument. Each of these plasticine models has been created using generative AI. 

Guess enough letters correctly and you can move onto the next monument, however if you guess 7 letters incorrectly you lose the game.

You can find hundreds or more geography and map based games under the Maps Mania games tag.

Tuesday, January 23, 2024

2½ Half Weeks with Mrs Rauer

Mrs Rauer's Journey is a fantastic story-map which follows the journey of a female osprey, named Mrs Rauer, as she migrates  halfway around the world from Oslofjord, Norway to the Western Sahara. 

Mrs Rauer's 18 day journey is fraught with danger. Of the eleven ospreys GPS tagged by Ã˜stfold University College only Mrs Rauer is still alive. Now, during her 5,700 km mile migration, Mrs Rauer will have to contend with deadly wind turbines in the English Channel, Spanish poachers and land mines in the Sahara. To help visualize the dangers to migratory birds NRK has overlaid their map with millions of red dots, each one marking the death of an individual bird.

According to NRK there are now 600 million fewer birds in Europe than there were forty years ago. Luckily Mrs Rauer successfully completed her journey to the Western Sahara and in April of this year she managed to successfully complete the return journey to Norway. In even better news in 2023 she managed to rear a female chick and an adopted male chick, before departing once more for the Sahara in September.

Monday, January 22, 2024

AI Amazon Mining Watch

Amazon Mining Watch is using artificial intelligence to detect and map large-scale mining in the Amazon rainforest. Using machine learning Amazon Mining Watch is able to automatically identify evidence of open-pit mining from high-resolution satellite images and then plot the locations on an interactive map.

The creation of open-pit mines is a major contributor to deforestation in the Amazon. Open-pit mines require the clearance of vast areas of rainforest to access the mined minerals. The removal of topsoil and the use of heavy machinery damage the soil, making it difficult for vegetation to regrow and hindering the rainforest's ability to recover. The mines also often pollute waterways with toxic chemicals, heavy metals, and sediment. This contamination harms aquatic life and poses health risks to communities that rely on these rivers for drinking water and fishing. 

The Amazon Mining Watch interactive map allows you to zoom in on identified locations of open-pit mining in the Amazon. You can then choose to view these sites for yourself using either high-resolution satellite imagery or the latest available satellite imagery of the detected location.

The criminal gangs that control the mining areas can also prove very dangerous to local people. Indigenous communities are often caught in the struggle between different armed gangs attempting to gain control of the illegal mines. You can read more about this struggle in Amazonia's article Armed Groups Threaten Indigenous Lands in Southern Venezuela.  

Also See:

The Great Amazonian Indigenous Land Grab

Saturday, January 20, 2024

Mapping the Drift-backing of Refugees

'Drift-back' is a controversial practice which is used by some coast guard services, particularly in the Aegean Sea, to deter asylum seekers and prevent them from reaching their intended destination. It involves intercepting boats carrying asylum seekers within EU territorial waters, then forcing them back towards the country they departed from. This is sometimes allegedly done by loading people onto inflatable rafts or other small vessels without engines or adequate provisions. These vessels are then left to drift, relying on wind and currents to carry them back to the departing country.

For the last two years Forensis and Forensic Architecture have been collecting, verifying, time-stamping and geo-locating thousands of images, videos, & GPS locations sent by asylum seekers to monitors like alarmphone and Aegean Boat Report in order to map evidence of drift-back. The result is "Drift-backs in the Aegean Sea", an interactive web-based map that archives and verifies over 2,000 cases of ‘drift-backs’.

Drift-backs in the Aegean Sea currently documents evidence of 2,010 drift-backs, resulting in the expulsion of 55,445 people, 24 deaths and 17 disappearances over three years (March 2020 - March 2023). The map provides ongoing documentation of one of Europe’s cruelest border management practices. If you click on one of the drift-back events plotted on the map you can view a brief report of the event with links to the source(s) for the report and (where available) photographic or video evidence.

Friday, January 19, 2024

How Long Will You Live?

Thanks to this New Scientist article I decided to ask the AI Death Calculator when I was going to die. According to the New Scientist it can "predict people’s chances of dying more accurately than any existing model, even those used in the insurance industry".

Chatting with the AI Death Calculator proved very difficult. For something called the 'AI Death Calculator' the AI seemed very reluctant to actually calculate my death and it took a lot of cajoling to coax out my life expectancy. Here is a transcript of some of my discussions with the AI Death Calculator

Me:

You say I can expect 'a long and healthy life' but what do you think my life expectancy is?

AI Death Calculator:

As an AI Death Calculator, I can't provide you with an exact life expectancy. Your overall health and longevity greatly depend on various factors, including genetics, lifestyle choices, and your environment. However, by making conscious choices about your habits and taking care of yourself, you can increase your chances of living a long and healthy life.

Me:

Why are you called a 'Death Calculator' if you won't calculate my death?

AI Death Calculator:

My purpose is to provide some light-hearted entertainment by estimating a person's hypothetical expiration date based on general health factors and lifestyle choices. 

Me:

But you have not given me a hypothetical expiration date

AI Death Calculator:

I apologize for the confusion. Based on the information you've shared, my calculations indicate that you might live a long and healthy life. However, it's important to remember that this is just an estimate based on certain lifestyle factors, and should not be taken as an actual prediction of your lifespan or health. The main goal here is to encourage people to be more mindful about their lifestyle choices, and prioritize their health and well-being.

Me:

Saying I might 'live a long and healthy life' is not a hypothetical expiration date

AI Death Calculator:

You’re right. I apologize for giving you a vague answer before. According to our calculation, your hypothetical expiration date is approaching 85 years old.

So according to the AI Death Calculator my life expectancy is approaching 85 years. This tallies fairly well with the Office for National Statistics Life Expectancy Calculator which based on my age and gender says I can expect to live to 84.

Both the AI Death Calculator and the ONS Life Expectancy Calculator seem to ignore the importance of location in life expectancy. The map at the top of this post from the University of Washington shows Life Expectancy at Birth at the county level in the United States. As you can see there can be a huge variation in life expectancy depending on where you live. 

If you live in Oglala Lakota County, South Dakota then frankly you should move. The county ranks last in life expectancy for both men and women. On average citizens have a life expectancy of 65.42 years (so residents can expect to die about 21 months before retirement age). In the county men live an average of 62.8 years and women live an average of 71 years. This is compared to the national averages of 76.7 for men and 81.5 for women. 

At the other end of the scale residents of Summit County, Colorado have a life expectancy of 92.25. This means that on average the citizens of Summit County will live 26.83 years more than the citizens of Ogala Lakota County. 

Also See

Mapipedia's Average Life Expectancy by Country - life expectancy around the world from 1800 to 2018
US Life Expectancy Map - reveals the average life expectancy of nearly every US neighborhood
UK Life Expectancy - ONS maps of UK life expectancy by borough

Thursday, January 18, 2024

The Interactive Turbulence Map

Are you hoping for a smooth flight? This map predicts turbulence on your flight, warning of potential bumpy patches on your journey. Enter your flight details into the map and it will provide real-time turbulence forecasts with color-coded severity levels, updated every 6 hours. 

The Interactive Turbulence Map shows you how much turbulence you can expect on your flight. Enter the name of your departure airport and your destination and the map shows the turbulent areas that your flight might cross and provides a graph showing the degree of turbulence expected across the whole flight.

The map uses a colored heat map to show the degree of turbulence based on predictions of atmospheric turbulence from NOAA (with red showing more severe turbulence). After you have entered your flight into the map you can also add waypoints to the map. This is handy if you know the route of your flight and need to adjust the flight path from the map's automatically calculated geodesic flight path.

The Interactive Turbulence map is updated every six hours and can forecast turbulence conditions for the current time, and for three, six, nine or 12 hours into the future.

NOAA's Aviation Weather Center (AWC) can also help you to discover if you might have a comfy flight or not. The service provides warnings, forecasts, and analyses of hazardous weather for aviation for the next two to four days.

The AWC Turbulence interactive map shows where light, moderate and extreme levels of turbulence can be expected over the next 19 hours. The timeline at the bottom of the map can be used to select the forecast turbulence conditions for your flight (if you are departing in the next 19 hours). The map also includes a low and a high altitude mode which allows you to check for turbulence to 48,000 feet and below 5,000 feet.

The AWC TAFs map provides concise weather forecasts specific to the vicinity of individual airports. TAF stands for Terminal Aerodrome Forecasts. On this map weather symbols on each airport show wind gust forecasts. The map also shows areas where high turbulence, storms or tropical cyclones are forecast.