diff --git a/seshat/apps/core/static/core/js/map_functions.js b/seshat/apps/core/static/core/js/map_functions.js
index 0d33d000e..0db043ffc 100644
--- a/seshat/apps/core/static/core/js/map_functions.js
+++ b/seshat/apps/core/static/core/js/map_functions.js
@@ -410,6 +410,39 @@ function updateLegend() {
legendDiv.appendChild(polityContainer);
}
+ } else if (hierarchicalComplexityVariablesFull.includes(variable)) {
+
+ var legendTitle = document.createElement('h3');
+ legendTitle.textContent = variable;
+ legendDiv.appendChild(legendTitle);
+
+ let variable_underscore = variable.toLowerCase().replace(' ', '_');
+ // Get the maximum value of the hierarchical complexity variable
+ let hierarchicalVariableMaxValue = highestComplexityValues[variable_underscore];
+
+ for (var key in hierarchicalComplexityColourMapping) {
+
+ var legendItem = document.createElement('p');
+
+ var colorBox = document.createElement('span');
+ colorBox.style.display = 'inline-block';
+ colorBox.style.width = '20px';
+ colorBox.style.height = '20px';
+ colorBox.style.backgroundColor = hierarchicalComplexityColourMapping[key];
+ colorBox.style.marginRight = '10px';
+ legendItem.appendChild(colorBox);
+
+ if (key === 'min') {
+ legendItem.appendChild(document.createTextNode(0));
+ } else if (key === 'max') {
+ legendItem.appendChild(document.createTextNode(hierarchicalVariableMaxValue));
+ } else {
+ legendItem.appendChild(document.createTextNode(`${key}`));
+ }
+
+ legendDiv.appendChild(legendItem);
+ };
+
} else if (variable in categorical_variables) {
var legendTitle = document.createElement('h3');
@@ -601,6 +634,9 @@ function clearSelection() {
});
document.getElementById('hideUnselected').checked = false;
plotPolities();
+ if (document.getElementById('chooseVariable').value != 'polity') {
+ legendDiv.style.display = 'block';
+ };
}
function selectAllCheckbox() {
@@ -704,9 +740,14 @@ function populateVariableDropdown(variables) {
Object.entries(vars).forEach(([variable, details]) => {
const option = document.createElement('option');
option.value = details.formatted;
- option.textContent = details.full_name;
+ if (hierarchicalComplexityVariables.includes(variable)) {
+ option.textContent = "Hierarchical Complexity: " + details.full_name;
+ } else {
+ option.textContent = details.full_name;
+ }
optgroup.appendChild(option);
});
+ optgroup.innerHTML = [...optgroup.children].sort((a, b) => a.textContent.localeCompare(b.textContent)).map(e => e.outerHTML).join('');
chooseVariableDropdown.appendChild(optgroup);
}
});
@@ -827,4 +868,40 @@ function closeHelp() {
if (popup !== null) {
popup.style.display = 'block';
}
+}
+
+function hierarchicalComplexityColour(maxValue, value) {
+ // If the value is null, return silver (Uncoded)
+ if (value == null) {
+ return 'silver';
+ }
+ // If the value is 0, return the min color
+ if (value == 0) {
+ return hierarchicalComplexityColourMapping['min'];
+ }
+ // If the value is greater than the maximum value, return the max color
+ if (value > maxValue) {
+ return hierarchicalComplexityColourMapping['max'];
+ }
+ // Calculate the colour based on the value and the maximum value
+ let ratio = value / maxValue;
+
+ // Convert hex to RGB
+ function hexToRgb(hex) {
+ let bigint = parseInt(hex.slice(1), 16);
+ return {
+ r: (bigint >> 16) & 255,
+ g: (bigint >> 8) & 255,
+ b: bigint & 255
+ };
+ }
+
+ let startColor = hexToRgb(hierarchicalComplexityColourMapping['min']);
+ let endColor = hexToRgb(hierarchicalComplexityColourMapping['max']);
+
+ let r = Math.round(startColor.r + ratio * (endColor.r - startColor.r));
+ let g = Math.round(startColor.g + ratio * (endColor.g - startColor.g));
+ let b = Math.round(startColor.b + ratio * (endColor.b - startColor.b));
+
+ return `rgb(${r}, ${g}, ${b})`;
}
\ No newline at end of file
diff --git a/seshat/apps/core/templates/core/world_map.html b/seshat/apps/core/templates/core/world_map.html
index e951d944a..52614d940 100644
--- a/seshat/apps/core/templates/core/world_map.html
+++ b/seshat/apps/core/templates/core/world_map.html
@@ -614,6 +614,9 @@
How to use the Seshat World Map
updateCategoricalVariableSelection(localStorage.getItem('variable'));
};
}
+
+ var hierarchicalComplexityVariablesFull = ['Military Level', 'Administrative Level', 'Religious Level', 'Settlement Hierarchy'];
+ var hierarchicalComplexityVariables = ['military_level', 'administrative_level', 'religious_level', 'settlement_hierarchy'];
var displayedShapes = [];
var polityBorderWeight = 0;
@@ -667,6 +670,18 @@ How to use the Seshat World Map
if (shape.alternate_religion) {
shape.alternate_religion = JSON.parse(shape.alternate_religion.replace(/'/g, '"'));
}
+ if (shape.settlement_hierarchy) {
+ shape.settlement_hierarchy = JSON.parse(shape.settlement_hierarchy.replace(/'/g, '"'));
+ }
+ if (shape.religious_level) {
+ shape.religious_level = JSON.parse(shape.religious_level.replace(/'/g, '"'));
+ }
+ if (shape.military_level) {
+ shape.military_level = JSON.parse(shape.military_level.replace(/'/g, '"'));
+ }
+ if (shape.administrative_level) {
+ shape.administrative_level = JSON.parse(shape.administrative_level.replace(/'/g, '"'));
+ }
// Any fields that end _dict should be converted to a dictionary from a string
for (const [key, value] of Object.entries(shape)) {
if (key.endsWith('_dict')) {
@@ -702,6 +717,11 @@ How to use the Seshat World Map
var tick_years = {{ tick_years }};
setSliderTicks(tick_years);
+ var highestSettlementHierarchy;
+ var highestReligiousLevel;
+ var highestMilitaryLevel;
+ var highestAdministrativeLevel;
+
// Load all polity shapes and modern province/country shapes in background
window.addEventListener('load', function () {
function fetchData(url, displayYear) {
@@ -751,6 +771,9 @@ How to use the Seshat World Map
plotPolities();
document.getElementById('variablesLoadingIndicator').style.display = 'none';
+ // Get the highest values of the hierarchical complexity variables
+ highestComplexityValues = data.highest_complexity_values;
+
return fetch('/core/provinces_and_countries');
})
.then(response => response.json())
@@ -814,6 +837,12 @@ How to use the Seshat World Map
'No Seshat page': 'silver'
};
+ let hierarchicalComplexityColourMapping = {
+ 'min': '#0000FF', // blue
+ 'max': '#FF0000', // red
+ 'Uncoded': 'silver'
+ };
+
function switchBaseMapWorldMap() {
switchBaseMap();
if (document.getElementById('chooseVariable').value != 'polity') {
@@ -922,6 +951,18 @@ How to use the Seshat World Map
shapeWeight = shape.weight;
shapeColour = shape.colour;
+ // Hierarchical complexity variables
+ } else if (hierarchicalComplexityVariablesFull.includes(variable)) {
+ shapeWeight = polityBorderWeightSelected;
+ let variable_underscore = variable.toLowerCase().replace(' ', '_');
+ // Get the maximum value of the hierarchical complexity variable
+ let hierarchicalVariableMaxValue = highestComplexityValues[variable_underscore];
+ // Calculate the colour based highest of the from and to values
+ if (shape[variable_underscore][1] != 'None' && shape[variable_underscore][1] != null) { // If the to value is not None, use it since it is the highest
+ shapeColour = hierarchicalComplexityColour(hierarchicalVariableMaxValue, shape[variable_underscore][1]);
+ } else { // If the to value is None, use the from value (even if it is None)
+ shapeColour = hierarchicalComplexityColour(hierarchicalVariableMaxValue, shape[variable_underscore][0]);
+ }
} else if (variable in categorical_variables){
shapeWeight = polityBorderWeightSelected;
// If the shape has a dictionary for the variable the key of the dict is the variable value and the value is a list of start and end years.
@@ -1095,7 +1136,7 @@ How to use the Seshat World Map
`;
// Absent/present variables
- if (variable != 'polity' && !categorical_variables.hasOwnProperty(variable)) {
+ if (variable != 'polity' && !categorical_variables.hasOwnProperty(variable) && !hierarchicalComplexityVariablesFull.includes(variable)) {
if (shape[variable + '_dict']) {
// Iterate through key/values in the dictionary
var counter = 0;
@@ -1158,60 +1199,156 @@ How to use the Seshat World Map
// this will need to be updated to use shape[variable + '_dict'] as done above for absent/present variables
// Note: the actual colouring of the shapes is done in the style function above and this is already set up to handle the dictionaries
popupContent = popupContent + `
-
- Languages |
- ${shape.language.join(', ')} |
-
-
- Language Genus |
- ${shape.language_genus.join(', ')} |
-
-
- Linguistic Family |
- ${shape.linguistic_family.join(', ')} |
-
- `;
- }
- if (variable == 'religious_tradition' || variable == 'religion' || variable == 'religion_family' || variable == 'religion_genus' || variable == 'alternate_religion' || variable == 'alternate_religion_family' || variable == 'alternate_religion_genus') {
- popupContent = popupContent + `
-
- Religious Traditions |
- ${shape.religious_tradition} |
-
-
- Religions |
- ${shape.religion.join(', ')} |
-
-
- Religion Genus |
- ${shape.religion_genus.join(', ')} |
-
-
- Religion Family |
- ${shape.religion_family.join(', ')} |
-
-
- Alternate Religions |
- ${shape.alternate_religion.join(', ')} |
-
-
- Alternate Religion Genus |
- ${shape.alternate_religion_genus.join(', ')} |
-
-
- Alternate Religion Family |
- ${shape.alternate_religion_family.join(', ')} |
-
- `;
- }
- if (allCapitalsInfo[shape.seshat_id]) {
- if (allCapitalsInfo[shape.seshat_id]['year_from'] <= selectedYearInt && allCapitalsInfo[shape.seshat_id]['year_to'] >= selectedYearInt) {
- popupContent = popupContent + `
-
- Capital: |
- ${allCapitalsInfo[shape.seshat_id].map(capital => capital.capital).join(', ')} |
-
- `;
+
+ Languages |
+ ${shape.language.join(', ')} |
+
+
+ Language Genus |
+ ${shape.language_genus.join(', ')} |
+
+
+ Linguistic Family |
+ ${shape.linguistic_family.join(', ')} |
+
+ `;
+ }
+ if (variable == 'religious_tradition' || variable == 'religion' || variable == 'religion_family' || variable == 'religion_genus' || variable == 'alternate_religion' || variable == 'alternate_religion_family' || variable == 'alternate_religion_genus') {
+ popupContent = popupContent + `
+
+ Religious Traditions |
+ ${shape.religious_tradition} |
+
+
+ Religions |
+ ${shape.religion.join(', ')} |
+
+
+ Religion Genus |
+ ${shape.religion_genus.join(', ')} |
+
+
+ Religion Family |
+ ${shape.religion_family.join(', ')} |
+
+
+ Alternate Religions |
+ ${shape.alternate_religion.join(', ')} |
+
+
+ Alternate Religion Genus |
+ ${shape.alternate_religion_genus.join(', ')} |
+
+
+ Alternate Religion Family |
+ ${shape.alternate_religion_family.join(', ')} |
+
+ `;
+ }
+ if (variable == 'Settlement Hierarchy') {
+ if (shape.settlement_hierarchy.length == 0 || ((shape.settlement_hierarchy[0] == 'None' || shape.settlement_hierarchy[0] == null) && (shape.settlement_hierarchy[1] == 'None' || shape.settlement_hierarchy[1] == null))) {
+ popupContent = popupContent + `
+
+ Settlement Hierarchy |
+ Uncoded |
+
+ `;
+ } else if (shape.settlement_hierarchy[0] == shape.settlement_hierarchy[1] || shape.settlement_hierarchy[1] == 'None' || shape.settlement_hierarchy[1] == null) {
+ popupContent = popupContent + `
+
+ Settlement Hierarchy |
+ ${shape.settlement_hierarchy[0]} |
+
+ `;
+ } else {
+ popupContent = popupContent + `
+
+ Settlement Hierarchy |
+ ${shape.settlement_hierarchy[0]} to ${shape.settlement_hierarchy[1]} |
+
+ `;
+ }
+ }
+ if (variable == 'Religious Level') {
+ if (shape.religious_level.length == 0 || ((shape.religious_level[0] == 'None' || shape.religious_level[0] == null) && (shape.religious_level[1] == 'None' || shape.religious_level[1] == null))) {
+ popupContent = popupContent + `
+
+ Religious Level |
+ Uncoded |
+
+ `;
+ } else if (shape.religious_level[0] == shape.religious_level[1] || shape.religious_level[1] == 'None' || shape.religious_level[1] == null) {
+ popupContent = popupContent + `
+
+ Religious Level |
+ ${shape.religious_level[0]} |
+
+ `;
+ } else {
+ popupContent = popupContent + `
+
+ Religious Level |
+ ${shape.religious_level[0]} to ${shape.religious_level[1]} |
+
+ `;
+ }
+ }
+ if (variable == 'Military Level') {
+ if (shape.military_level.length == 0 || ((shape.military_level[0] == 'None' || shape.military_level[0] == null) && (shape.military_level[1] == 'None' || shape.military_level[1] == null))) {
+ popupContent = popupContent + `
+
+ Military Level |
+ Uncoded |
+
+ `;
+ } else if (shape.military_level[0] == shape.military_level[1] || shape.military_level[1] == 'None' || shape.military_level[1] == null) {
+ popupContent = popupContent + `
+
+ Military Level |
+ ${shape.military_level[0]} |
+
+ `;
+ } else {
+ popupContent = popupContent + `
+
+ Military Level |
+ ${shape.military_level[0]} to ${shape.military_level[1]} |
+
+ `;
+ }
+ }
+ if (variable == 'Administrative Level') {
+ if (shape.administrative_level.length == 0 || ((shape.administrative_level[0] == 'None' || shape.administrative_level[0] == null) && (shape.administrative_level[1] == 'None' || shape.administrative_level[1] == null))) {
+ popupContent = popupContent + `
+
+ Administrative Level |
+ Uncoded |
+
+ `;
+ } else if (shape.administrative_level[0] == shape.administrative_level[1] || shape.administrative_level[1] == 'None' || shape.administrative_level[1] == null) {
+ popupContent = popupContent + `
+
+ Administrative Level |
+ ${shape.administrative_level[0]} |
+
+ `;
+ } else {
+ popupContent = popupContent + `
+
+ Administrative Level |
+ ${shape.administrative_level[0]} to ${shape.administrative_level[1]} |
+
+ `;
+ }
+ }
+ if (allCapitalsInfo[shape.seshat_id]) {
+ if (allCapitalsInfo[shape.seshat_id]['year_from'] <= selectedYearInt && allCapitalsInfo[shape.seshat_id]['year_to'] >= selectedYearInt) {
+ popupContent = popupContent + `
+
+ Capital: |
+ ${allCapitalsInfo[shape.seshat_id].map(capital => capital.capital).join(', ')} |
+
+ `;
popupContent = popupContent + `
diff --git a/seshat/apps/core/tests/tests.py b/seshat/apps/core/tests/tests.py
index deeece1bc..3e57586c4 100644
--- a/seshat/apps/core/tests/tests.py
+++ b/seshat/apps/core/tests/tests.py
@@ -4,7 +4,7 @@
from django.urls import reverse
from ..models import Cliopatria, GADMShapefile, GADMCountries, GADMProvinces, Polity, Capital
from ...general.models import Polity_capital, Polity_peak_years, Polity_language, Polity_religious_tradition
-from ...sc.models import Judge
+from ...sc.models import Judge, Settlement_hierarchy, Religious_level, Military_level, Administrative_level
from ...wf.models import Copper
from ...rt.models import Gov_res_pub_pros
from ..views import get_provinces, get_polity_shape_content, get_all_polity_capitals, assign_variables_to_shapes, assign_categorical_variables_to_shapes
@@ -176,6 +176,30 @@ def setUp(self):
religious_tradition='Islam',
polity_id=2
)
+ Settlement_hierarchy.objects.create(
+ name='settlement_hierarchy',
+ settlement_hierarchy_from=6,
+ settlement_hierarchy_to=7,
+ polity_id=2
+ )
+ Religious_level.objects.create(
+ name='religious_level',
+ religious_level_from=9,
+ religious_level_to=10,
+ polity_id=2
+ )
+ Military_level.objects.create(
+ name='military_level',
+ military_level_from=13,
+ military_level_to=14,
+ polity_id=2
+ )
+ Administrative_level.objects.create(
+ name='administrative_level',
+ administrative_level_from=5,
+ administrative_level_to=6,
+ polity_id=2
+ )
# Model tests
@@ -586,4 +610,8 @@ def test_assign_categorical_variables_to_shapes(self):
self.assertEqual(result_shapes[0]['language'], ['English', 'French'])
self.assertEqual(result_shapes[0]['language_dict']['English'], [1998, 2000])
self.assertEqual(result_shapes[0]['language_dict']['French'], [1999, 2007])
- self.assertEqual(result_shapes[0]['religious_tradition'], ['Christianity', 'Islam'])
\ No newline at end of file
+ self.assertEqual(result_shapes[0]['religious_tradition'], ['Christianity', 'Islam'])
+ self.assertEqual(result_shapes[0]['settlement_hierarchy'], [6, 7])
+ self.assertEqual(result_shapes[0]['religious_level'], [9, 10])
+ self.assertEqual(result_shapes[0]['military_level'], [13, 14])
+ self.assertEqual(result_shapes[0]['administrative_level'], [5, 6])
\ No newline at end of file
diff --git a/seshat/apps/core/views.py b/seshat/apps/core/views.py
index 22d630b2c..3ee58ca5a 100644
--- a/seshat/apps/core/views.py
+++ b/seshat/apps/core/views.py
@@ -71,6 +71,7 @@
from django.contrib.messages.views import SuccessMessageMixin
from ..general.models import Polity_research_assistant, Polity_duration, Polity_linguistic_family, Polity_language_genus, Polity_language, POLITY_LINGUISTIC_FAMILY_CHOICES, POLITY_LANGUAGE_GENUS_CHOICES, POLITY_LANGUAGE_CHOICES, Polity_religious_tradition, Polity_religion_genus, Polity_religion_family, Polity_religion, Polity_alternate_religion_genus, Polity_alternate_religion_family, Polity_alternate_religion, POLITY_RELIGION_GENUS_CHOICES, POLITY_RELIGION_FAMILY_CHOICES, POLITY_RELIGION_CHOICES
+from ..sc.models import Settlement_hierarchy, Religious_level, Military_level, Administrative_level
from ..crisisdb.models import Power_transition
@@ -4259,7 +4260,7 @@ def assign_categorical_variables_to_shapes(shapes, variables):
Assign the categorical variables to the shapes.
Note:
- Currently only language and religion variables are implemented.
+ Extend this function to add more of the variables.
Args:
shapes (list): The shapes to assign the variables to.
@@ -4268,7 +4269,7 @@ def assign_categorical_variables_to_shapes(shapes, variables):
Returns:
tuple: A tuple containing the shapes and the variables.
"""
- # Add categorical variables to the variables dictionary
+ # Add categorical variables from General Variables to the variables dictionary
variables['General Variables'] = {
'polity_linguistic_family': {'formatted': 'linguistic_family', 'full_name': 'Linguistic Family'},
'polity_language_genus': {'formatted': 'language_genus', 'full_name': 'Language Genus'},
@@ -4282,10 +4283,18 @@ def assign_categorical_variables_to_shapes(shapes, variables):
'polity_alternate_religion': {'formatted': 'alternate_religion', 'full_name': 'Alternate Religion'},
}
+ # Add categorical variables from Social Complexity Variables to the variables dictionary
+ if 'Social Complexity Variables' not in variables:
+ variables['Social Complexity Variables'] = {}
+ variables['Social Complexity Variables']['settlement_hierarchy'] = {'formatted': 'Settlement Hierarchy', 'full_name': 'Settlement Hierarchy'}
+ variables['Social Complexity Variables']['religious_level'] = {'formatted': 'Religious Level', 'full_name': 'Religious Level'}
+ variables['Social Complexity Variables']['military_level'] = {'formatted': 'Military Level', 'full_name': 'Military Level'}
+ variables['Social Complexity Variables']['administrative_level'] = {'formatted': 'Administrative Level', 'full_name': 'Administrative Level'}
+
# Fetch all polities and store them in a dictionary for quick access
polities = {polity.new_name: polity for polity in Polity.objects.all()}
- # Fetch all linguistic families, language genuses, and languages and store them in dictionaries for quick access
+ # Fetch all categorical variables and store them in dictionaries for quick access
linguistic_families = {}
for lf in Polity_linguistic_family.objects.all():
if lf.polity_id not in linguistic_families:
@@ -4346,7 +4355,7 @@ def assign_categorical_variables_to_shapes(shapes, variables):
alternate_religions[ar.polity_id] = []
alternate_religions[ar.polity_id].append(ar)
- # Add language variable info to polity shapes
+ # Add categorical variable info to polity shapes
for shape in shapes:
shape['linguistic_family'] = []
shape['linguistic_family_dict'] = {}
@@ -4368,6 +4377,10 @@ def assign_categorical_variables_to_shapes(shapes, variables):
shape['alternate_religion_family_dict'] = {}
shape['alternate_religion'] = []
shape['alternate_religion_dict'] = {}
+ shape['settlement_hierarchy'] = []
+ shape['religious_level'] = []
+ shape['military_level'] = []
+ shape['administrative_level'] = []
if shape['seshat_id'] != 'none': # Skip shapes with no seshat_id
polity = polities.get(shape['seshat_id'])
if polity:
@@ -4382,8 +4395,24 @@ def assign_categorical_variables_to_shapes(shapes, variables):
shape['alternate_religion_genus'].extend([arg.alternate_religion_genus for arg in alternate_religion_genuses.get(polity.id, [])])
shape['alternate_religion_family'].extend([arf.alternate_religion_family for arf in alternate_religion_families.get(polity.id, [])])
shape['alternate_religion'].extend([ar.alternate_religion for ar in alternate_religions.get(polity.id, [])])
-
- # Get the years for the variables for the polity
+ settlement_hierarchy = Settlement_hierarchy.objects.filter(polity_id=polity.id)
+ if settlement_hierarchy:
+ shape['settlement_hierarchy'].append(settlement_hierarchy[0].settlement_hierarchy_from)
+ shape['settlement_hierarchy'].append(settlement_hierarchy[0].settlement_hierarchy_to)
+ religious_level = Religious_level.objects.filter(polity_id=polity.id)
+ if religious_level:
+ shape['religious_level'].append(religious_level[0].religious_level_from)
+ shape['religious_level'].append(religious_level[0].religious_level_to)
+ military_level = Military_level.objects.filter(polity_id=polity.id)
+ if military_level:
+ shape['military_level'].append(military_level[0].military_level_from)
+ shape['military_level'].append(military_level[0].military_level_to)
+ administrative_level = Administrative_level.objects.filter(polity_id=polity.id)
+ if administrative_level:
+ shape['administrative_level'].append(administrative_level[0].administrative_level_from)
+ shape['administrative_level'].append(administrative_level[0].administrative_level_to)
+
+ # Get the years for the variables which have years for the polity
shape['linguistic_family_dict'].update({lf.linguistic_family: [lf.year_from, lf.year_to] for lf in linguistic_families.get(polity.id, [])})
shape['language_genus_dict'].update({lg.language_genus: [lg.year_from, lg.year_to] for lg in language_genuses.get(polity.id, [])})
shape['language_dict'].update({l.language: [l.year_from, l.year_to] for l in languages.get(polity.id, [])})
@@ -4395,7 +4424,7 @@ def assign_categorical_variables_to_shapes(shapes, variables):
shape['alternate_religion_family_dict'].update({arf.alternate_religion_family: [arf.year_from, arf.year_to] for arf in alternate_religion_families.get(polity.id, [])})
shape['alternate_religion_dict'].update({ar.alternate_religion: [ar.year_from, ar.year_to] for ar in alternate_religions.get(polity.id, [])})
- # If no linguistic family, language genus, or language was found, append 'Uncoded'
+ # If no variable was found, append 'Uncoded'
polity = polities.get(shape['seshat_id'])
if polity:
if not shape['linguistic_family']:
@@ -4617,6 +4646,13 @@ def map_view_all_with_vars(request):
# Set the last year in history we ever want to display, which will be used to determine when we should say "present"
content['last_history_year'] = content['latest_year'] # Set this to the latest year in the data or a value of choice
+ # Get the highest values of hierarchical complexity variables for the legend
+ content['highest_complexity_values'] = {}
+ content['highest_complexity_values']['settlement_hierarchy'] = max([max(filter(None, shape['settlement_hierarchy']), default=0) for shape in content['shapes'] if shape['settlement_hierarchy']], default=0)
+ content['highest_complexity_values']['religious_level'] = max([max(filter(None, shape['religious_level']), default=0) for shape in content['shapes'] if shape['religious_level']], default=0)
+ content['highest_complexity_values']['military_level'] = max([max(filter(None, shape['military_level']), default=0) for shape in content['shapes'] if shape['military_level']], default=0)
+ content['highest_complexity_values']['administrative_level'] = max([max(filter(None, shape['administrative_level']), default=0) for shape in content['shapes'] if shape['administrative_level']], default=0)
+
return JsonResponse(content)
def provinces_and_countries_view(request):