MVC Pattern in the Context of Geospatial Data

Felipe Limeira
4 min readJan 6, 2024

--

In the world of software development, efficiency and clarity are key. One of the most effective methods to achieve these objectives is through the application of software design patterns. Among these, the Model-View-Controller (MVC) stands out as one of the most influential and widely used. This pattern not only promotes a clear separation of responsibilities within an application but also facilitates the maintenance and expansion of code.

In this article, we will explore the MVC pattern in detail, demonstrating its applicability and effectiveness through a practical example: a geospatial mapping project. The idea is to present a different example from the usual and to understand how this pattern works for geospatial data.

What is a Model-View-Controller (MVC)?

The Model-View-Controller (MVC) is a software architecture pattern that separates an application into three main components: Model, View, and Controller. This division offers a clear organization of code, promoting the separation of concerns and making the application more modular, comprehensible, and manageable.

source

Model

The Model is the central part of the pattern, responsible for the business logic and data manipulation. It interacts directly with the database or any other data source, performing operations such as queries, updates, and validations. The model is independent of the user interface, which means it can be reused and changed without affecting other parts of the application.

View

The View is the user interface of the application. It displays the data to the user and sends user interactions (such as button clicks, text entries) to the Controller. In MVC, the view is typically passive, meaning it does not contain business logic but only the logic to present the data to the user. This makes the user interface more flexible and easier to update or replace.

Controller

The Controller acts as an intermediary between the Model and the View. It receives user inputs through the View, processes them (possibly altering the state of the Model), and returns the appropriate output to the View. The Controller is essential to MVC as it decouples the Model and the View, managing the logic of how data is presented and manipulated.

Practical Example

This example is quite simple compared to a real application, but the idea is to understand how it works in the area of geospatial data. I am using a geojson dataset to simulate our model, and the user can specify an area length they want to see on the map.

Following the MVC pattern, the separation was carried out as follows:

MVC
├───controllers
│ ├───map_controller.py
├───models
│ └───model_geo.py
└───views
| └───view_map.py
└─main.py

Model: The GeoData class represents the model. It is responsible for managing data, business logic, and validation rules. The model deals with the loading, retrieval, and filtering of geographical data.

class GeoData:
def __init__(self, file_path):
self.file_path = file_path
self.data = None

def load_data(self):
with open(self.file_path, 'r') as file:
self.data = json.load(file)

def get_dados(self):
return self.data

def filter_per_area(self, area_min, area_max):
data_filter = [
feature
for feature in self.data['features']
if area_min <= feature['properties']['AREA_KM2'] <= area_max
]
return {'type': 'FeatureCollection', 'features': data_filter}

View: The MapGUI class represents the view. It is responsible for displaying the data (in this case, a map) and interacting with the user.

class MapGUI:
def create_map(self, geojson_data):
map_ = folium.Map(location=[-23.5489, -46.6388], zoom_start=11)
folium.GeoJson(geojson_data).add_to(map_)
map_.save('map.html')

def request_area(self):
try:
area_min = float(
input(
'Enter the value of the minimum area in km² (for example, 0.5): '
)
)

area_max = float(
input(
'Enter the value of the maximum area in km² (for example, 10.0):'
)
)

return area_min, area_max

except ValueError:
print('Please, enter a valid number.')
return None, None

Controller: The MapController class acts as the controller. It serves as an intermediary between the model and the view, controlling the flow of data between them and the updates of the interface. The controller requests data from the model and sends it to the view, in addition to managing user interaction with the interface.

from model.model_geo import GeoData
from view.view_map import MapGUI

class MapController:
def __init__(self, file_path):
self.model = GeoData(file_path)
self.view = MapGUI()

def display_map(self):
self.model.load_data()
data = self.model.get_dados()
self.view.create_map(data)

def filter_area(self):
area_min, area_max = self.view.request_area()
data_filter = self.model.filter_per_area(area_min, area_max)
self.view.create_map(data_filter)

Conclusion

By applying this design pattern, we see organization and clarity in the code, allowing for a separation between business rules and user interface. The goal is for each component to be developed and tested independently.

Thinking about larger projects, there is an advantage in working with other developers, each developing a functionality of the system.

Although patterns are essential for software development, there is an initial complexity for more novice developers, as it introduces new layers of abstraction.

If you are interested in testing or even contributing, I have left the example in this repository on GitHub.

If you enjoyed this article, follow me for more content like this.

Currently, I am helping people to get guidance in learning GIS programming, functioning as a personalized mentorship. If you are interested, please feel free to connect with me on Linktree

--

--

Felipe Limeira

I'm Software Developer, this is a place where I write about the subjects I study and my experiences. linktr.ee/felipegeocodes