
    9i-                         S r SSKrSSKrSSKrSSKJr  SSKrSSKr	SSK
rSSKJr  SrS rS rSS jrSS	 jrS
 r\S:X  a  \" 5         gg)a  
Extract polygons for >90th percentile road density by type.

Generates shapefiles (GeoPackage format) that outline areas where road density
exceeds the 90th percentile threshold for specific road categories:

Categories:
 - layer_nonzero: Roads on bridges/tunnels/different layers (layer != 0)
 - footway: Pedestrian footway roads
 - links: On-ramps and off-ramps (motorway_link, trunk_link, primary_link, etc.)
 - rare_types: The rarest highway types in the dataset
 - general: All roads combined (>90th percentile of total density)

Outputs:
 - {location}_90th_percentile_{category}_{size}.gpkg - Vector polygons (GeoPackage)
 - {location}_90th_percentile_{category}_{size}.shp - Vector polygons (Shapefile)
 - {location}_90th_percentile_{category}_{size}.geojson - Vector polygons (GeoJSON)
    N)Path)tqdmGRID_CELL_SIZE_METERSc                     U =(       d    [         R                  " [        5      nUc  [        S[         S35      e [	        U5      $ ! [         a  n[        SU S[         S35      UeSnAff = f)z8Resolve cell size from CLI args or environment variable.Nz8Cell size must be passed as an argument or provided via .zInvalid cell size 'z'. Provide an integer or set )osgetenvCELL_SIZE_ENV_VAR
ValueErrorint)explicit_value	raw_valueexcs      :/data2/heatmap/scripts/extract_90th_percentile_hotspots.pyresolve_cell_sizer   !   s}    >")),=">IFGXFYYZ[
 	
9~ !),IJ[I\\]^
	s   
A 
A,A''A,c                 T   [        SU S35        U" U 5      nUR                  (       a  [        SU 35        g[        S[        U5      S SU 35        UR                  5       R	                  SS	0S
9n [
        R                  " US/   US	S/   SS9nUR                  R                  US'   UR                  S	5      S   R                  5       nUS	   R                  U5      R                  S5      US'   UR                  S	/S
9n	U	$ ! [         a  n[        SU 35         SnAgSnAff = f)zDCalculate road length density per grid cell for a specific category.u%   📊 Computing density for category: ...u&      ⚠️ No roads found for category N      ✅ Found ,z roads in category indexcell_id)columnsgeometryintersection)howu+      ⚠️ Failed to compute intersections: length_mr   )printemptylenreset_indexrenamegpdoverlay	Exceptionr   lengthgroupbysummapfillnadrop)
roadsgridcategory_namefilter_funcfiltered_roads
grid_localintersectionsr   groupedgrid_results
             r   calculate_density_for_categoryr4   0   sF   	1-
DE !'N6}oFG	M#n-a00CM?
ST !!#**GY3G*HJJ<(	:./
 !. 6 6 = =M* ##I.z:>>@G (	266w?FFqIJz//9+/6K  ;C5ABs   3D 
D'D""D'c                    [        SU SU S35        X S   S:     R                  5       nUR                  (       a  [        S5        g[        R                  " US   U5      n[        SU S	US
 S35        X S   U:     R                  5       nUR                  (       a  [        SU S35        g[        S[        U5      S S35        [        S5         UR                  5       nUR                  (       d`  UR                  SS9nUR                  SS9n[        S[        U5       S35        XS'   X&S'   XFS'   UR                  R                  S-  US'   U$  g! [         a  n[        SU 35         SnAgSnAff = f)z6Extract polygons where density > percentile threshold.u   🔍 Extracting >zth percentile for r   r   r   u)      ⚠️ No non-zero density cells foundNu      📈 zth percentile threshold: z,.2fz mu      ⚠️ No cells exceed the zth percentile thresholdr   r   z cells above thresholdu.      🔗 Dissolving into contiguous polygons...F)index_partsT)r*   u      ✅ Created z polygon(s)category
percentilethreshold_mi@B area_km2u!      ⚠️ Error during dissolve: )r   copyr   npr8   r   dissolveexploder    r   arear$   )density_gridr-   r8   non_zero	thresholdhotspots	dissolvedes           r    extract_90th_percentile_polygonsrF   X   s   	j\);M?#
NO 4q89>>@H~~9; hz2J?I	HZL 9)D9I
LM 4y@AFFHH~~.zl:QRS	M#h-**@
AB 
:<%%'	 !))e)<I!--4-8IOC	N#3;?@ %2j!&0l#'0m$$-$6$6$;$;i$GIj!   	  1!56s   B E 
E8 E33E8c                     U S   R                  5       nUR                  U5      R                  R                  5       n[	        SU SU 35        [	        SUR                  U5      R                  5        35        U$ )z4Get the N rarest highway types (excluding None/NaN).highwayu   🔬 Rarest z highway types: z   Counts: )value_countstailr   tolistr   to_dict)r+   top_nhighway_counts
rare_typess       r   get_rare_typesrP      st    9%224N$$U+1188:J	L/
|
<=	K++E2::<=
>?    c            
      @	  ^ [         R                  " SS9n U R                  SSS9  U R                  S[        S[         S3S	9  U R                  S
[        SSS9  U R                  S[        SSS9  U R                  5       nUR                  R                  5       nUR                  nUR                  n [        UR                  5      nWS-  n[!        S5      U-  nX S3-  n	X SUS S3-  n
U	R#                  5       (       d2  [        SU	 35        [        SU 35        [        R                  " S5        U
R#                  5       (       d5  [        SU
 35        [        SU SU 35        [        R                  " S5        [        SU	 35        [$        R&                  " U	5      n[        S[)        U5      S  S!35        [        S"U
 35        [$        R&                  " U
5      n[        S[)        U5      S  S#35        UR*                  UR*                  :w  a&  [        S$5        UR-                  UR*                  5      n0 nS% nS&U4US&'   S' nS(U4US('   S) nS*U4US*'   [/        XS+9mU4S, jnS-U4US-'   S.S/ 4US.'   / n[1        UR3                  5       S0S19 GHR  u  nu  nn[        S2S3 35        [        S4U 35        [        S3 5        [5        XUU5      nUc  [        S5U S635        MS  [7        UUU5      nUc  [        S5U S735        Mt  X S8U S9U S8US S:3-  nUR9                  S;5      nUR;                  US<S=9  [        S>U 35        UR9                  S?5      nUR;                  US@S=9  [        S>U 35        UR9                  SA5      nUR;                  USBS=9  [        S>U 35        UR=                  U[)        U5      USC   R?                  5       USD   R@                  SE   SF.5        GMU     U(       ak  [        S2S3 35        [        SG5        [        S3 5        [B        RD                  " U5      n[        URG                  SHSI95        [        SJ[)        U5       35        g [        SK5        g ! [         a/  n[        SU 35        [        R                  " S5         S nAGNS nAff = f)LNz?Extract >90th percentile density polygons by road type category)descriptionlocationz-Location name (e.g., 'belgium', 'california'))helpz--cell-sizez(Grid cell size in meters (default: env $))typerU   z--percentileZ   z"Percentile threshold (default: 90))rW   defaultrU   z--rare-count   z.Number of rarest types to analyze (default: 5)u   ❌    i  outputz_roads_projected.gpkg_grid_z.0fzkm.gpkgu   ❌ Roads file not found: u*   💡 Run: python -m scripts.extract_roads u   ❌ Grid file not found: u    💡 Run: GRID_CELL_SIZE_METERS=z python -m scripts.create_grid u   📂 Loading roads from: u      ✅ Loaded r   z road segmentsu   📂 Loading grid from: z grid cellsu+   ⚠️ Reprojecting roads to match grid CRSc                    SU R                   ;   a'  X S   R                  5       U S   S:g  -  U S   S:g  -     $ [        S5        SU R                   ;   a  U S   R                  5       U S   S:g  -  OSnSU R                   ;   a  U S   R                  5       U S   S:g  -  OSn[        U[        5      (       a/  [        U[        5      (       a  [        S	5        U R
                  S
S $ XU-     $ )zRFilter roads with layer != 0.
If layer column missing, use bridge/tunnel as proxy.layer0r   uM      ℹ️  No 'layer' column - using bridge/tunnel as proxy for layer_nonzerobridgenoFtunneluH      ❌ Cannot compute layer_nonzero: no layer, bridge, or tunnel columnsN)r   notnar   
isinstancebooliloc)r+   
has_bridge
has_tunnels      r   filter_layer_nonzero"main.<locals>.filter_layer_nonzero   s     emm#...0U7^s5JKuU\~abObcdd acPX\a\i\iPix..0E(Ot4KLotJPX\a\i\iPix..0E(Ot4KLotJ*d++
:t0L0L`bzz"1~%455rQ   layer_nonzeroc                     X S   S:H     $ )NrH   footway r+   s    r   filter_footwaymain.<locals>.filter_footway   s    9%233rQ   rn   c                 @    X S   R                   R                  SSS9   $ )NrH   _linkF)na)strcontainsrp   s    r   filter_linksmain.<locals>.filter_links   s&    9%))227u2EFFrQ   links)rM   c                 0   > X S   R                  T5         $ )NrH   )isin)r+   rO   s    r   filter_raremain.<locals>.filter_rare   s    9%**:677rQ   rO   generalc                     U $ )Nro   rp   s    r   <lambda>main.<locals>.<lambda>   s    erQ   zProcessing categories)desc
z<============================================================zProcessing: u   ⏭️ Skipping z
 (no data)z (no hotspots)_th_percentile_kmz.gpkgGPKG)driveru   ✅ Saved: z.shpzESRI Shapefilez.geojsonGeoJSONr:   r9   r   )r7   polygon_counttotal_area_km2r9   u   ✅ SUMMARYF)r   u"   
📊 Total categories processed: u.   
⚠️ No hotspots extracted for any category)$argparseArgumentParseradd_argumentr   r
   
parse_argsrT   lowerr8   
rare_countr   	cell_sizer   r   sysexitr   existsr"   	read_filer   crsto_crsrP   r   itemsr4   rF   with_suffixto_fileappendr'   rg   pd	DataFrame	to_string)parserargsrT   r8   r   cell_size_mrE   cell_size_kmlocation_dir
roads_path	grid_pathr+   r,   
categoriesrj   rq   rx   r}   all_resultscategory_keyr-   r.   r@   hotspot_polygonsoutput_base	gpkg_pathshp_pathgeojson_path
summary_dfrO   s                                @r   mainr      s    $$UF 
)XY
78I7J!L  
 1	   =	   D}}""$HJJ'7
 %L >H,L*,A BBJ6,s1C7KKI *:,78:8*EF))560=\]e\fgh 
%j\
23MM*%E	N3u:a.
78	$YK
01==#D	N3t9Q-{
34 yyDHH;=TXX& J6" $34H"IJ4&7JyG"L1Jw  8J8 ,k:J| '(;<Jy K6::;K;K;MTk6l22}k6(m]O,- 6e=R]^$]O:>? <L-Ycd#$]O>BC #z:,n]O[\]ijm\nnp%qq  ++G4	  6 :I;'( **62  2B CH:&' #..z:  i @L>*+% !12.z:>>@+M:??B	
 	K 7mZ 6(m\\+.
j"""/03C4D3EFG?@M  QCjs   2Q$ $
R.$RR__main__)rX   )rZ   )__doc__r   r   r   pathlibr   	geopandasr"   pandasr   numpyr<   r   r
   r   r4   rF   rP   r   __name__ro   rQ   r   <module>r      s\   &  	 
     + %P.beAP zF rQ   