diff --git a/README.md b/README.md
index b033a30410705a742f4498310bac635e1bce73c6..9eda7ed84ee9fa60b2a95ea27f3e64945c77bddc 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,28 @@ Precompiled binaries can be found on https://www.sqlite.org/download.html. Extra
 binary in a folder and note its path. Add the path to your system environment variables. Now you can 
 manage the SQLite database.
 
+## Adding new maps
+The current server only contains the data for a single lake, Mjøsa. To add more lakes 
+go to https://overpass-turbo.eu/. Once you have navigated to Overpass API, enter
+the Overpass query below in the left field, but swap 'lakeName' out
+with the name of the lake you want to add. Once the query has been adjusted,
+press the 'Run' button.
+
+```
+[out:json];
+(
+  way["natural"="water"]["name"="lakeName"];
+  relation["natural"="water"]["name"="lakeName"];
+);
+(._;>;);
+out body;
+```
+If a text box saying "This query returned quite a lot of data (approx. x MB). Your browser may have a hard time trying to render this. Do you really want to continue?
+" appears, press 'continue anyway'. Double check that you have
+the correct lake, then press 'Export'. In the 'Export' menu, download the shape data as
+GeoJson. Once downloaded, name the file the *lakeName.json, and move the file into
+IceMap/server/lake_relations. Once you have added the file, run map division...
+
 ## Endpoints
 
 ## Bugs
diff --git a/app/lib/pages/consts.dart b/app/lib/pages/consts.dart
index 35b89973d96707fc9a2c6058069335c500b919f4..6b2e7ac3142f2661e6a473e202cfa02734e1f305 100644
--- a/app/lib/pages/consts.dart
+++ b/app/lib/pages/consts.dart
@@ -10,7 +10,7 @@ const int fetchInterval = 60; // Fetch marker data every n minutes
 
 // Map variables
 LatLng mapCenter = LatLng(60.7666, 10.8471);
-DateTime ?lastUpdate; // Last time marker data was fetched from server
+DateTime ?lastUpdate; // Last time data was fetched from server
 
 // Font variables
 const textColor = Colors.white;
diff --git a/app/lib/pages/marker_handler/get_relation.dart b/app/lib/pages/marker_handler/get_relation.dart
index 77d3297dd56438177d8327056aa7e3617c51f4a1..2a4abf5df854289596065e04fe3457657fa887a4 100644
--- a/app/lib/pages/marker_handler/get_relation.dart
+++ b/app/lib/pages/marker_handler/get_relation.dart
@@ -1,8 +1,10 @@
 import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
-import '../consts.dart';
 import 'dart:typed_data';
+import 'package:path_provider/path_provider.dart';
+
+import '../consts.dart';
 
 /// Fetch relation data from server
 Future<Uint8List> fetchRelation() async {
@@ -21,16 +23,38 @@ Future<Uint8List> fetchRelation() async {
       var responseBody = await response.transform(utf8.decoder).join();
 
       if (responseBody.isNotEmpty) {
+        Directory appDocumentsDirectory = await getApplicationDocumentsDirectory();
+        String filePath = '${appDocumentsDirectory.path}/last_relation.json';
+
+        try { // Write most recent time of update to file
+          await File(filePath).writeAsString(responseBody, mode: FileMode.write);
+          print('Relation written to file');
+        } catch (error) { print('Error in writing to file: $error');}
+
         // Return relation data from the response body
         return Uint8List.fromList(utf8.encode(responseBody));
-      } else {
-        throw Exception('Response body is empty');
       }
-    } else {
-      throw Exception('Failed to fetch relation data: Status code ${response.statusCode}');
     }
+    return loadSavedRelation();
   } catch (e) {
-    throw Exception('Failed to fetch relation data: ${e.toString()}');
+    return loadSavedRelation();
+  }
+}
+
+Future<Uint8List> loadSavedRelation() async {
+  // Get latest saved relation from file if the server does not respond
+  Directory appDocumentsDirectory = await getApplicationDocumentsDirectory();
+  String filePath = '${appDocumentsDirectory.path}/last_relation.json';
+
+  // Read file contents
+  File file = File(filePath);
+  if (await file.exists()) {
+    String contents = await file.readAsString();
+    List<dynamic> jsonData = json.decode(contents); // Parse JSON string from file
+    Uint8List relation = Uint8List.fromList(utf8.encode(jsonData.toString()));
+    return relation;
+  } else {
+    throw Exception('File does not exist');
   }
 }
 
diff --git a/app/lib/pages/widgets/cloropleth_map.dart b/app/lib/pages/widgets/cloropleth_map.dart
index 9c59c4fd33b7759eaf2883783c657c982d3aa1e4..ea33009a252ee2efb5cc34af16d580ab190035fa 100644
--- a/app/lib/pages/widgets/cloropleth_map.dart
+++ b/app/lib/pages/widgets/cloropleth_map.dart
@@ -7,10 +7,12 @@ import 'dart:convert';
 
 /// A class containing thickness data for each subdivision of the map.
 class IceThicknessModel {
-  IceThicknessModel(this.subDivID, this.thickness);
+  IceThicknessModel(this.sub_div_id, this.thickness, this.color, this.savedColor);
 
-  final String subDivID;
+  final String sub_div_id;
   final int thickness;
+  Color color;
+  final Color savedColor;
 }
 
 /// ChoroplethMap is a stateful widget that contains a choropleth map.
@@ -19,29 +21,42 @@ class IceThicknessModel {
 class ChoroplethMap extends StatefulWidget {
   const ChoroplethMap({Key? key,
     required this.relation,
-    required this.measurements
+    required this.measurements,
+    required this.onSelectionChanged,
   }) : super(key: key);
 
   final Uint8List relation;
   final List<Measurement> measurements;
+  final void Function(int selectedIndex) onSelectionChanged; // Callback function
 
   @override
   _ChoroplethMapState createState() => _ChoroplethMapState();
 }
 
 class _ChoroplethMapState extends State<ChoroplethMap> {
+  int selectedIndex = -1;
   late MapShapeSource mapShapeSource;
   late final MapZoomPanBehavior _zoomPanBehavior = MapZoomPanBehavior();
   List<IceThicknessModel> iceThicknessList = <IceThicknessModel>[];
+  List<Color> testColors = [ // NB test color
+    const Color(0xff8a003b),
+    const Color(0xff8a4300),
+    const Color(0xff8a7a00),
+    const Color(0xff538a00),
+    const Color(0xff007b8a),
+  ];
 
   @override
   void initState() {
     super.initState();
 
     final Random random = Random();
-    for (int i = 0; i <= 60; i++) {
+    for (int i = 0; i <= 120; i++) {
+      int ran = random.nextInt(5); // NB test color
+      Color randomColor = testColors[ran];
+
       int randomNumber = random.nextInt(21); // 0 -> 20, NB: temp test data
-      iceThicknessList.add(IceThicknessModel(i.toString(), randomNumber));
+      iceThicknessList.add(IceThicknessModel(i.toString(), randomNumber, randomColor, randomColor));
     }
   }
 
@@ -54,14 +69,30 @@ class _ChoroplethMapState extends State<ChoroplethMap> {
             MapShapeLayer(
               source: MapShapeSource.memory( // Map polygon
                 widget.relation, // JSON coordinates from server
-                shapeDataField: 'properties.SubDivID',
+                shapeDataField: 'sub_div_id',
                 dataCount: iceThicknessList.length,
-                primaryValueMapper: (int index) => iceThicknessList[index].subDivID,
-                shapeColorValueMapper: (int index) => iceThicknessList[index].thickness,
+                primaryValueMapper: (int index) => iceThicknessList[index].sub_div_id,
+                shapeColorValueMapper: (int index) => iceThicknessList[index].color,
               ),
-              color: Colors.blue.shade400, // Map color
+              //color: Colors.blue.shade400, // Map color
               zoomPanBehavior: _zoomPanBehavior,
               strokeColor: Colors.black,
+              // Shape selection
+              selectedIndex: selectedIndex,
+              onSelectionChanged: (int index) {
+                setState(() {
+                  selectedIndex = index;
+                  for (int i = 0; i < iceThicknessList.length; i++) {
+                    iceThicknessList[i].color = i == index ? Colors.red : iceThicknessList[i].savedColor;
+                  }
+                });
+                widget.onSelectionChanged(selectedIndex);
+              },
+              selectionSettings: MapSelectionSettings(
+                color: Colors.orange,
+                strokeColor: Colors.red[900],
+                strokeWidth: 3,
+              ),
             ),
           ],
         ),
diff --git a/app/lib/pages/widgets/map_widget.dart b/app/lib/pages/widgets/map_widget.dart
index d308527304fe415fb17550657a2f715a36f2df4d..7d824eef6f43bbdfdfd7c80fe579bee0470c81af 100644
--- a/app/lib/pages/widgets/map_widget.dart
+++ b/app/lib/pages/widgets/map_widget.dart
@@ -28,6 +28,7 @@ class MapContainerWidget extends StatefulWidget {
 class _MapContainerWidgetState extends State<MapContainerWidget> {
 
   Measurement? selectedMarker;  // Containing data for selected marker
+  int selectedMarkerIndex = 0;
   bool isMinimized = true;      // Quick view box state tacker
   bool satLayer = false;        // Satellite layer visibility tracker
   bool isTapped = false;        // Button tap state tracker
@@ -53,10 +54,17 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
     }
   }
 
+  // Tile selection handler
+  void handleSelection(int index) {
+    setState(() {
+      selectedMarkerIndex = index;
+    });
+  }
+
   @override
   Widget build(BuildContext context) {
     // Initialise selectedMarker to first element in markerList
-    selectedMarker ??= widget.markerList[0];
+    selectedMarker ??= widget.markerList[selectedMarkerIndex];
 
     checkAndSetLastUpdate();
 
@@ -154,7 +162,10 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
                     height: screenWidth * boxHeight,
                     child: Padding(
                       padding: const EdgeInsets.all(15.0), // Padding around map
-                      child: ChoroplethMap(relation: widget.relation, measurements: widget.markerList,),
+                      child: ChoroplethMap(
+                        relation: widget.relation,
+                        measurements: widget.markerList,
+                        onSelectionChanged: handleSelection,),
                     ),
                   ),
                   Positioned( // Quick view box layered over map
diff --git a/server/__pycache__/consts.cpython-311.pyc b/server/__pycache__/consts.cpython-311.pyc
index 3c60371f12da04a05b4df70c07a52110b373b16c..1712cb5077bfd090a3e860cc1dca4556d993186a 100644
Binary files a/server/__pycache__/consts.cpython-311.pyc and b/server/__pycache__/consts.cpython-311.pyc differ
diff --git a/server/consts.py b/server/consts.py
index 5653feea29bda21aae6d6ea43c0365f22b8a73c3..6be29cfbf4d5c8d8470413ecead84c6ade7f37b9 100644
--- a/server/consts.py
+++ b/server/consts.py
@@ -10,4 +10,4 @@ SSL_KEY_PATH = CERT_DIR + "testKey.key"
 SSL_CERT_PATH = CERT_DIR + "testCert.crt"
 
 # Measurement specs
-AREA_SIZE = 20
\ No newline at end of file
+AREA_SIZE = 20
diff --git a/server/data_processing/__pycache__/area_processing.cpython-311.pyc b/server/data_processing/__pycache__/area_processing.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..633c3ea85b6c7a9ba12a981f1f16c33fb08d67d6
Binary files /dev/null and b/server/data_processing/__pycache__/area_processing.cpython-311.pyc differ
diff --git a/server/lake_relations/overpass_query.txt b/server/lake_relations/overpass_query.txt
index 4d011e2037b088d1bd4259f5ca7630fcf3318f13..1539aa9503a5f52bac64f8c81ad5584880c51a38 100644
--- a/server/lake_relations/overpass_query.txt
+++ b/server/lake_relations/overpass_query.txt
@@ -1,11 +1,3 @@
-The following query is used to retrieve the relation(shape) of a lake.
-Go to https://overpass-turbo.eu/#, enter the query in the left field, add
-the name of the lake you want to add, and press 'run'.
-If a text box saying "" appears, press 'continue anyways'. Double check that you have
-the correct lake, then press 'Export'. In the 'Export' menu, download the shape data as
-GeoJson. Once downloaded, name the file the *lakeName.json, and move the file into
-IceMap/server/lake_relations. Once you have added the file, run map division...
-
 [out:json];
 (
   way["natural"="water"]["name"="lakeName"];
diff --git a/server/main.py b/server/main.py
index fd50247f515865ff71fe1c231b5db2ca17b82a5b..18f682438103ab78b592778b6d81b30a99658849 100644
--- a/server/main.py
+++ b/server/main.py
@@ -6,7 +6,6 @@ from map.get_relation import get_relation
 from APIs.get_weather import get_weather
 from map.input_new_data import input_new_Lidar_data
 import ssl
-import keyboard
 import sqlite3
 
 app = Flask(__name__)
diff --git a/server/map/__pycache__/get_relation.cpython-311.pyc b/server/map/__pycache__/get_relation.cpython-311.pyc
index e67dc914c928bb26ee9ec375d748ec7eb89d4c7c..1fa84cb826efde8bac6448f030d6da17d236c79f 100644
Binary files a/server/map/__pycache__/get_relation.cpython-311.pyc and b/server/map/__pycache__/get_relation.cpython-311.pyc differ
diff --git a/server/map/get_relation.py b/server/map/get_relation.py
index ab52cfcf269e442ccc99c5e47b834cca16af9605..9f175ee845665081bfa35be119597a11bd3ec0ee 100644
--- a/server/map/get_relation.py
+++ b/server/map/get_relation.py
@@ -1,14 +1,11 @@
 import geopandas as gpd
-from shapely.geometry import Polygon, LineString
+from shapely.geometry import Polygon, LineString, MultiLineString
 from shapely.ops import linemerge, unary_union, polygonize
 import matplotlib.pyplot as plt
 import random
 import json
 import os
 
-polygon_min_x = None  # The left most point of the entire polygon
-
-
 # Read a json file with relation data and send to response object
 def get_relation(self, body_of_water: str):  # NB: implement body_of_water
     # Read relation from GeoJson file and extract all polygons
@@ -17,8 +14,7 @@ def get_relation(self, body_of_water: str):  # NB: implement body_of_water
     polygons = [Polygon(polygon.exterior) for polygon in polygon_data['geometry']]
 
     if len(polygons) <= 1:
-        print("Failed to convert to polygons")
-        return
+        raise Exception("Failed to convert JSON object to Shapely Polygons")
 
     divided_map = []
 
@@ -32,31 +28,60 @@ def get_relation(self, body_of_water: str):  # NB: implement body_of_water
 
         divided_map.extend(combine_grid_with_poly(polygon, lines))
 
+    '''
+    ####################### PLOTTING ############################
     tiles = [gpd.GeoDataFrame(geometry=[tile]) for tile in divided_map]
 
-    sub_div_id = 0
-    for tile in tiles:
-        tile['sub_div_id'] = sub_div_id
-        tile['sub_div_center'] = tile['geometry'].centroid.apply(lambda x: [x.x, x.y])
-        sub_div_id += 1
+    print("Plotting... This may take some time...")
+    # NB test plot
+    fig, ax = plt.subplots()
+    ax.set_aspect(1.5)
+
+    # Plot each tile
+    for tile in tiles:  # NB temporarily limited to 5 tiles
+        random_color = "#{:06x}".format(random.randint(0, 0xFFFFFF))
+        gpd.GeoSeries(tile.geometry).plot(ax=ax, facecolor=random_color, edgecolor='none')
+
 
-    tiles_json = {'type': 'FeatureCollection', 'features': []}
-    for tile in tiles:
-        feature = {
+    plt.show()
+    ##################### PLOTTIND END ###########################
+    '''
+
+    features = []
+
+    sub_div_id = 0
+    for tile in divided_map: # NB temporarily limited to 5 tiles
+
+        # Round coordinates to 4 decimals
+        center = round(tile.centroid.coords[0][0], 4), round(tile.centroid.coords[0][1], 4)
+        rounded_coordinates = []
+        if isinstance(tile, Polygon):
+            for coords in tile.exterior.coords:
+                rounded_coords = (round(coords[0], 4), round(coords[1], 4))
+                rounded_coordinates.append(rounded_coords)
+            rounded_tile = Polygon(rounded_coordinates)
+
+        tile_feature = {
             'type': 'Feature',
-            'geometry': tile.geometry.__geo_interface__,
             'properties': {
-                'sub_div_id': int(tile['sub_div_id'].iloc[0]),
-                'sub_div_center': tile['sub_div_center'].tolist()
-            }
+                'sub_div_id': str(sub_div_id),
+                'sub_div_center': center
+            },
+            'geometry': rounded_tile.__geo_interface__
         }
-        tiles_json['features'].append(feature)
+        features.append(tile_feature)
+        sub_div_id += 1
+
+    feature_collection = {
+        'type': 'FeatureCollection',
+        'features': features
+    }
 
     self.send_response(200)
     self.send_header("Content-type", "application/json")
     self.end_headers()
 
-    self.wfile.write(json.dumps(tiles_json).encode('utf-8'))
+    self.wfile.write(json.dumps(feature_collection).encode('utf-8'))
 
 
 def create_grid(poly: Polygon, cell_size):
@@ -84,17 +109,17 @@ def create_grid(poly: Polygon, cell_size):
 
 
 def combine_grid_with_poly(polygon, grid):
-    # Create an empty list to store tiles intersecting the polygon
     intersecting_tiles = []
 
-    # Iterate through each grid line
     for line in grid:
-        # Check if the line intersects with the polygon
         if line.intersects(polygon):
-            # If the line intersects, find the intersection points
             intersection = line.intersection(polygon)
-            # Add each line to the list
-            intersecting_tiles.append(intersection)
+            # Check if intersection is a MultiLineString
+            if isinstance(intersection, MultiLineString):
+                # Extend the intersecting tiles with the polygonized results
+                intersecting_tiles.extend(list(polygonize(intersection)))
+            else:
+                intersecting_tiles.append(intersection)
 
     return intersecting_tiles