# Prepare data for visualization
first_appearance_years = []
location_labels = []
kiln_evolution_types = []
for i, result in enumerate(all_results, 1):
if result['analysis']:
analysis = result['analysis']
first_year = analysis.get('first_year', None)
first_appearance_years.append(first_year if first_year else 0)
location_labels.append(f"Loc {i}")
# Get type evolution (FCBTK → Zigzag)
year_data = analysis.get('years', [])
types_seen = [y.get('type', 'None') for y in year_data if y.get('has_kilns')]
unique_types = list(dict.fromkeys(types_seen))
kiln_evolution_types.append(' → '.join(unique_types) if unique_types else 'None')
# Create multi-panel visualization
fig = plt.figure(figsize=(16, 12))
gs = fig.add_gridspec(3, 2, hspace=0.3, wspace=0.3)
# Plot 1: First Appearance Year Distribution
ax1 = fig.add_subplot(gs[0, 0])
valid_years = [y for y in first_appearance_years if y > 0]
if valid_years:
ax1.hist(valid_years, bins=range(2014, 2024), color='steelblue', alpha=0.7, edgecolor='black')
ax1.set_xlabel('Year', fontweight='bold')
ax1.set_ylabel('Number of Locations', fontweight='bold')
ax1.set_title('Distribution: First Kiln Appearance Year', fontsize=14, fontweight='bold')
ax1.grid(True, alpha=0.3, axis='y')
# Plot 2: First Appearance by Location
ax2 = fig.add_subplot(gs[0, 1])
colors_map = {0: 'lightgray', 2014: '#e74c3c', 2016: '#e67e22', 2018: '#f39c12',
2020: '#2ecc71', 2022: '#3498db', 2024: '#9b59b6'}
bar_colors = [colors_map.get(y, 'gray') for y in first_appearance_years]
bars = ax2.barh(location_labels, first_appearance_years, color=bar_colors, edgecolor='black', linewidth=1)
ax2.set_xlabel('First Appearance Year', fontweight='bold')
ax2.set_ylabel('Location', fontweight='bold')
ax2.set_title('First Kiln Appearance by Location', fontsize=14, fontweight='bold')
ax2.set_xlim(2012, 2024)
ax2.grid(True, alpha=0.3, axis='x')
# Plot 3: Temporal Matrix - Kiln Presence Across Locations and Years
ax3 = fig.add_subplot(gs[1, :])
years = [2014, 2016, 2018, 2020, 2022]
matrix_data = []
for result in all_results:
if result['analysis']:
row = []
year_data_dict = {y['year']: y for y in result['analysis'].get('years', [])}
for year in years:
if year in year_data_dict:
has_kilns = year_data_dict[year].get('has_kilns', False)
row.append(1 if has_kilns else 0)
else:
row.append(0)
matrix_data.append(row)
else:
matrix_data.append([0] * len(years))
matrix_data = np.array(matrix_data)
im = ax3.imshow(matrix_data, cmap='RdYlGn', aspect='auto', vmin=0, vmax=1)
ax3.set_xticks(range(len(years)))
ax3.set_xticklabels(years)
ax3.set_yticks(range(len(location_labels)))
ax3.set_yticklabels(location_labels)
ax3.set_xlabel('Year', fontweight='bold')
ax3.set_ylabel('Location', fontweight='bold')
ax3.set_title('Kiln Presence Matrix (Green = Present, Red = Absent)', fontsize=14, fontweight='bold')
# Add text annotations
for i in range(len(location_labels)):
for j in range(len(years)):
text = ax3.text(j, i, '✓' if matrix_data[i, j] == 1 else '✗',
ha="center", va="center", color="white", fontweight='bold')
# Plot 4: Kiln Type Evolution
ax4 = fig.add_subplot(gs[2, :])
type_counts = {}
for evo_type in kiln_evolution_types:
type_counts[evo_type] = type_counts.get(evo_type, 0) + 1
type_labels = list(type_counts.keys())
type_values = list(type_counts.values())
colors = plt.cm.Set3(range(len(type_labels)))
bars = ax4.bar(type_labels, type_values, color=colors, edgecolor='black', linewidth=1.5, alpha=0.8)
ax4.set_xlabel('Kiln Type Evolution', fontweight='bold')
ax4.set_ylabel('Number of Locations', fontweight='bold')
ax4.set_title('Kiln Type Evolution Patterns Across Locations', fontsize=14, fontweight='bold')
ax4.grid(True, alpha=0.3, axis='y')
# Add value labels on bars
for bar in bars:
height = bar.get_height()
ax4.text(bar.get_x() + bar.get_width()/2., height,
f'{int(height)}',
ha='center', va='bottom', fontweight='bold')
plt.suptitle('Multi-Location Brick Kiln Temporal Analysis', fontsize=18, fontweight='bold', y=0.995)
plt.show()