
    0i(                         d Z ddlZddlZddlZddlmZ ddlZddlm	Z
 ddlZddlZddlmZ ddlmZmZmZ ddlmZ dZd Zdd	Zd
efdZd Zd ZdefdZd Zd Zd Zd Z e!dk(  r e         yy)a  
Extract smooth hotspot contours from heatmap GeoTIFFs using continuous raster analysis.

Instead of merging rectilinear grid cells (which creates blocky boundaries),
this script treats the raster as continuous and uses skimage.measure.find_contours
to extract smooth contour polygons at a threshold that captures the target area.

Outputs:
 - PNG overlay showing contours on the heatmap
 - GeoJSON with smooth polygon boundaries (not blocky grid cells)
    N)Path)shapes)shapeMultiPolygonPolygon)measureHOTSPOT_TARGET_AREA_KM2c                     | | nt        j                  t              }|t        dt         d      	 t	        |      }|dk  rt        d      |S # t        $ r}t        d| d      |d}~ww xY w)z7Return the requested hotspot area in square kilometers.Nz3Hotspot area must be provided via --target-area or .zInvalid hotspot area ''.r   z'Hotspot area must be greater than zero.)osgetenvTARGET_AREA_ENV_VAR
ValueErrorfloat)explicit_value	raw_valueareaexcs       #scripts/extract_hotspot_contours.pyresolve_target_arear      s    "0"<"))L_B`IABUAVVWX
 	
JY qyBCCK  J1)B?@cIJs   A 	A/A**A/c                 ,   dg}|r|j                  |       g }|D ]"  }|j                  | j                  |             $ g }t               }t        |      D ]:  }||vs|j	                         s|j                  |       |j                  |       < |S )z6Find GeoTIFF heatmaps in the given location directory.z*road_density_*km.tif)extendglobsetsortedis_fileappendadd)location_dirextra_patternspatternsfilespatternunique_filesseen	file_paths           r   find_heatmap_rastersr(   /   s    '(H'E\&&w/0 L5DE]	D Y%6%6%8	*HHY #     raster_pathc                 $   | j                   j                  d      }|st        d| j                         |d   }|j	                  d      st        d| d      	 t        |dd       }||dz  fS # t        $ r}t        d	| d
      |d}~ww xY w)zPExtract the grid size label (e.g., '2km') and corresponding cell size in meters._z"Cannot parse grid size label from kmzGrid label 'z' does not end with 'km'.NzInvalid grid label 'r   g     @@)stemsplitr   nameendswithr   )r*   parts
size_labelcell_kmr   s        r   parse_size_labelr7   @   s    ""3'E=k>N>N=OPQQrJt$<
|3LMNNI
3B( w'''  I/
|2>?SHIs   A1 1	B:B

Bc                 h   t        |d         }t        |d         }||z  }|dz  }||z  }| t        j                  |          }t        |      dk(  rt	        d      t        j
                  |      ddd   }	t        t        |      t        |	      dz
        }
|	|
   }t        d|d	d
|d	d       |S )zHCalculate density threshold that captures approximately the target area.r      @B zNo valid data in rasterNr-      u      📊 Threshold: .1fz (captures ~u    km²))	absnpisfinitelenr   sortminintprint)data	transformtarget_area_km2pixel_widthpixel_heightpixel_area_m2pixel_area_km2target_pixels
valid_datasorted_valuesthreshold_idx	thresholds               r   #calculate_threshold_for_target_arearQ   O   s     il#Ky|$L,.M"Y.N $n4M bkk$'(J
:!233 GGJ'"-M M*C,>,BCMm,I		#l?3:Ov
VWr)   c                    t        j                  t        j                  |       | |k\  z  dd      j                  t         j                        }t        j                  |d      }|st        j                  ddgg |      S g }|D ]  }g }|D ]4  \  }	}
|d   |
|d   z  z   }|d	   |	|d
   z  z   }|j                  ||f       6 t        |      dk\  sM	 t        |      }|j                  r|j                  s|j                  |        |st        j                  ddgg |      S g }t        |d      D ])  \  }}|j                   dz  }|j                  |||d       + t        j                  |d|      S # t        $ r Y w xY w)zHExtract smooth contours from raster using skimage.measure.find_contours.r;   r   g      ?)level
cluster_idarea_km2)columnsgeometrycrs      r9      )startr:   )rT   rU   rW   rW   )rW   rX   )r>   wherer?   astypeuint8r   find_contoursgpdGeoDataFramer   r@   r   is_validis_empty	Exception	enumerater   )rE   rF   rP   rX   binary_maskcontourspolygonscontourcoordsrowcolxypolyclustersidxgeomrU   s                     r   extract_contours_from_rasterrt   j   s    ((2;;t,	0ABAqIPPQSQYQYZK $$[<Hz(BRUXYY H HC!sYq\11A!sYq\11AMM1a&!   v;!v==OOD) $ z(BRUXYY Hxq1	T99y( 
 	 2 HzsCC!  s   4E88	FFpathc                    t        j                  |       5 }|j                  d      j                  d      }|j                  }|)t        j                  ||k(  t
        j                  |      }n8t        j                  t        j                  |      |t
        j                        }|j                  }|j                  }|j                  }d d d        fS # 1 sw Y   xY w)Nr;   float32)rasterioopenreadr^   nodatar>   r]   nanr?   boundsrX   rF   )ru   srcrE   r{   r}   rX   rF   s          r   load_rasterr      s    	t	xx{!!),88DFNBFFD9D88BKK-tRVV<DggMM	 
 i'' 
	s   B4CC!c                    t        j                  d      \  }}|j                  |j                  |j                  |j
                  f}|j                  |d|dd       |j                  s9|j                  |k7  r|j                  |      }	n|}	|	j                  |ddd	d
       |j                  | j                   d|dddd       |j                  |j                  |j                         |j                  |j                  |j
                         |j                  d       t        j                           | j#                  | j                   d      }
|j%                  |
dd       t        j&                  |       |
S )z4Plot smooth contour hotspots overlay on the heatmap.)
      )figsizehotupperauto)cmapextentoriginaspectcyanwhiteg333333?rY   )ax	facecolor	edgecoloralpha	linewidthu	    — Top gu    km² (smooth contours)   r   )fontsizepadoffz_hotspots.pngi,  tight)dpibbox_inches)pltsubplotsleftrightbottomtopimshowemptyrX   to_crsplot	set_titler0   set_xlimset_ylimaxistight_layout	with_namesavefigclose)r*   rE   r}   
raster_crshotspots_gdfrG   figr   r   hotspots_plotout_paths              r   plot_hotspotsr      sO   ll7+GC kk6<<

CFIIdvgfIM z)(//
;M(MbFg #q 	 	2 LL
Ioa%88OP  
 KKV\\*KKvzz*GGEN$$(8(8'9%GHHKKcwK7IIcNOr)   c                     |j                  |j                   dt        |       d      }| j                  r/| j                  j	                         dk7  r| j                  d      } | j                  |d       |S )N
_hotspots_zkm2.geojsoni  )epsgGeoJSON)driver)r   r0   rC   rX   to_epsgr   to_file)r   r*   r5   rG   r   s        r   save_geojsonr      s{    $$
Js?';&<KHH L,,446$>#***5)4Or)   c                      t        j                  d      } | j                  dd       | j                  dddt         d	
       | j                  dddd       | j	                         S )NzWExtract smooth hotspot contours from density GeoTIFFs using continuous raster analysis.)descriptionlocationz/Location name (e.g., alabama, egypt, thailand).)helpz--target-areatarget_areaz>Target hotspot area in square kilometers. Defaults to env var r   )destr   z--extra-patternr   r!   z1Additional glob pattern(s) for locating GeoTIFFs.)actionr   r   )argparseArgumentParseradd_argumentr   
parse_args)parsers    r   r   r      s    $$mF 
)Z[
##6"7q:	   @	   r)   c            	         t               } | j                  j                         }	 t        | j                        }t        d      |z  }|j                         st        d|       t        || j                        }|st        d|       t        dt        |       d|j                          d       t        d       |D ]  }t        d	|j                          	 t        |      \  }}}	}
	 t#        ||
|      }	 t%        ||
||	      }|j&                  rt        d       at        dt        |       d       |d   j)                         }t        d|dd       	 t+        |      \  }}t-        ||||	||      }t/        ||||      }t        d|j                          t        d|j                           t        d       y # t
        $ r}t        d|       |d }~ww xY w# t         $ r}t        d
|        Y d }~Dd }~ww xY w# t
        $ r}t        d|        Y d }~id }~ww xY w# t         $ r}t        d|        Y d }~d }~ww xY w# t
        $ r d}Y w xY w)Nu   ❌ outputu"   ❌ Location directory not found: u$   ⚠️ No heatmap GeoTIFFs found in u   🎯 Processing z heatmaps for z...u:   🔬 Using continuous raster analysis with smooth contoursu	   
🗺️ u!      ⚠️ Could not load raster: u
      ⚠️ u&      ⚠️ Could not extract contours: u!      ⚠️ No hotspots identified.u      ✅ Found z hotspot region(s)rU   u      📍 Total area: r<   u    km²unknownu      💾 Saved overlay: u      💾 Saved contours: u(   
✅ Smooth contour extraction complete.)r   r   lowerr   r   r   
SystemExitr   existsr(   r!   rD   r@   
capitalizer2   r   re   rQ   rt   r   sumr7   r   r   )argsr   rG   errr    heatmap_rastersr*   rE   r}   r   rF   rP   hotspots
total_arear5   r,   png_pathgeojson_paths                     r   mainr      s   <D}}""$H0-d.>.>? >H,L =l^LMM*<9L9LMO?~NOO	S12.ATATAV@WWZ
[\	FH&
;++,-.	2=k2J/D&*i	;D)_]I	3D)YPZ[H
 >>56c(m_,>?@j)--/
$Z$4I>?	#,[9MJ !dFJRab#Hk:W'78():):(;<=S 'V 

56s  04u&C/0(  	5cU;<	  	Jse$%	  	:3%@A	  	#"J	#sq   G
 G*0H>H4 I
	G'G""G'*	H3HH	H1H,,H14	I=III'&I'__main__)N)"__doc__r   mathr   pathlibr   	geopandasra   matplotlib.pyplotpyplotr   numpyr>   rx   rasterio.featuresr   shapely.geometryr   r   r   skimager   r   r   r(   r7   rQ   rt   r   r   r   r   r   __name__ r)   r   <module>r      s   
   	      $ 9 9 / ""($ (6,D^(d (B,>7B zF r)   