U
    SZf|=                     @   s   d dl mZ d dlmZ d dlmZmZ d dlZd dl	Z
dd Zdd Zd	d
 Zdd Zd#ddZd$ddZddddddddi i ddddddddddddddfddZeeeddgdddgddddgddgdd gd!d"e_dS )%    )build_dataframe)make_docstring)choropleth_mapboxscatter_mapboxNc                 C   s0   |t j d }t t | t j d }||fS )zU
    Projects lat and lon to WGS84, used to get regular hexagons on a mapbox map
       )nppiZarctanhsin)latlonxy r   H/tmp/pip-unpacked-wheel-5ksk5baj/plotly/figure_factory/_hexbin_mapbox.py_project_latlon_to_wgs84   s    r   c                 C   s>   | d t j }dt t | t jd  d t j }||fS )zU
    Projects WGS84 to lat and lon, used to get regular hexagons on a mapbox map
    r      )r   r   Zarctanexp)r   r   r   r
   r   r   r   _project_wgs84_to_latlon   s    (r   c                 C   s   d}d| d| d}d}dd }dd }	|||| t j }
||  }|d	k rX|d
 n|d
 }|	|d |d |
}|	|d |d |}t|||S )z
    Get the mapbox zoom level given bounds and a figure dimension
    Source: https://stackoverflow.com/questions/6048975/google-maps-v3-how-to-calculate-the-zoom-level-for-a-given-bounds
    r      heightwidth   c                 S   sH   t | t j d }t d| d|  d }tt|t jt j d S )Nr      r   )r   r	   r   logmaxmin)r
   r	   ZradX2r   r   r   latRad&   s    z#_getBoundsZoomLevel.<locals>.latRadc                 S   s    dt | | |  t d S )Ngffffff?r   )r   r   )ZmapPxZworldPxfractionr   r   r   zoom+   s    z!_getBoundsZoomLevel.<locals>.zoomr   ih  r   r   )r   r   r   )Zlon_minZlon_maxZlat_minZlat_maxmapDimZscaleZ	WORLD_DIMZZOOM_MAXr   r   ZlatFractionZlngDiffZlngFractionZlatZoomZlngZoomr   r   r   _getBoundsZoomLevel   s    r!   c           /   
   C   s  |  }| }	|  }
| }d|	|  }||8 }|	|7 }	|	| }||
 }|dkrf|dkrf|| }n(|dkr|dkrtdd\}}n|| }|td }t|| t}|
|
||  | d 8 }
| | | } ||
 | }t| t}t|t}t	| t}t	|t}|d }|d }|}|}|| ||  }| | d d|| d   }| | d d d|| d d   }||k }|dkrt
||f}t
||f} d|k||k @ d|k@ ||k @ |@ }!d|k||k @ d|k@ ||k @ | @ }"tj|||! ||! fd tj| ||" ||" fd |dk	r^tj|||k < tj| | |k < t| |  g}#t|# }$nH|dkrd}tj||ftd	}t|D ]"}%t|D ]}&g ||%|&f< qqtj||ftd	} t|D ]"}%t|D ]}&g | |%|&f< qqtt| D ]}%||% rd||%   krD|k rn n>d||%   krd|k rn n|||% ||% f ||%  n^d||%   kr|k rn n>d||%   kr|k rn n| ||% ||% f ||%  qt|D ]P}%t|D ]@}&||%|&f }'t|'|kr.||'||%|&f< ntj||%|&f< qqt|D ]P}%t|D ]@}&| |%|&f }'t|'|kr||'| |%|&f< ntj| |%|&f< qXqLt|t | t f}#t|# }$|#|$ }(t
|dft})tt|||)d|| df< tt|||)d|| df< tt|d ||)|| ddf< tt||d |)|| ddf< |)dddf  |9  < |)dddf  |9  < |)dddf  |7  < |)dddf  |
7  < |)|$ })ddddd
d
g}*d
ttjd  d
ttjd  dttjd  dttjd  dttjd  d
ttjd  g}+t|)},t|*g|, | t|)dddf  }-t|+g|, | td t|)dddf  }.|-|.|)|(fS )aQ  
    Computes the aggregation at hexagonal bin level.
    Also defines the coordinates of the hexagons for plotting.
    The binning is inspired by matplotlib's implementation.

    Parameters
    ----------
    x : np.ndarray
        Array of x values (shape N)
    y : np.ndarray
        Array of y values (shape N)
    x_range : np.ndarray
        Min and max x (shape 2)
    y_range : np.ndarray
        Min and max y (shape 2)
    color : np.ndarray
        Metric to aggregate at hexagon level (shape N)
    nx : int
        Number of hexagons horizontally
    agg_func : function
        Numpy compatible aggregator, this function must take a one-dimensional
        np.ndarray as input and output a scalar
    min_count : int
        Minimum number of points in the hexagon for the hexagon to be displayed

    Returns
    -------
    np.ndarray
        X coordinates of each hexagon (shape M x 6)
    np.ndarray
        Y coordinates of each hexagon (shape M x 6)
    np.ndarray
        Centers of the hexagons (shape M x 2)
    np.ndarray
        Aggregated value in each hexagon (shape M)

    g&.>r   r      r   g      @g      ?N)Zdtypeg         ) r   r   r   r   sqrtceilastypeintroundfloorzerosaddatnanZconcatenateZravelisnanemptyobjectrangelenappendZhstackfloatrepeatarangeZtilecosr   tanarrayZvstack)/r   r   x_rangey_rangecolornxagg_func	min_countZxminZxmaxZyminZymaxpaddingZDxZDyZdx_ZdynyZix1Ziy1Zix2Ziy2Znx1Zny1Znx2Zny2nd1Zd2bdistZlattice1Zlattice2Zc1c2accumZ	good_idxsijvalsagreggated_valuecentershxZhymhxshysr   r   r   _compute_hexbin9   s    &
$
$&


@ @"""&&
*4rQ   c              	   C   s   t | |\}}	|dkr,t|  |  g}|dkrJt| | g}t ||\}
}t||	|
|||||\}}}}t||\}}|t}t	
|dddf d t	
|dddf  }||||fS )a  
    Computes the lat-lon aggregation at hexagonal bin level.
    Latitude and longitude need to be projected to WGS84 before aggregating
    in order to display regular hexagons on the map.

    Parameters
    ----------
    lat : np.ndarray
        Array of latitudes (shape N)
    lon : np.ndarray
        Array of longitudes (shape N)
    lat_range : np.ndarray
        Min and max latitudes (shape 2)
    lon_range : np.ndarray
        Min and max longitudes (shape 2)
    color : np.ndarray
        Metric to aggregate at hexagon level (shape N)
    nx : int
        Number of hexagons horizontally
    agg_func : function
        Numpy compatible aggregator, this function must take a one-dimensional
        np.ndarray as input and output a scalar
    min_count : int
        Minimum number of points in the hexagon for the hexagon to be displayed

    Returns
    -------
    np.ndarray
        Lat coordinates of each hexagon (shape M x 6)
    np.ndarray
        Lon coordinates of each hexagon (shape M x 6)
    pd.Series
        Unique id for each hexagon, to be used in the geojson data (shape M)
    np.ndarray
        Aggregated value in each hexagon (shape M)

    Nr   ,r   )r   r   r9   r   r   rQ   r   r&   strpdZSeries)r
   r   	lat_range	lon_ranger<   r=   r>   r?   r   r   r:   r;   rO   rP   rL   rK   hexagons_latshexagons_lonshexagons_idsr   r   r   _compute_wgs84_hexbin   s(    0       
0rZ   c              
   C   s~   g }|dkrt t| }t| ||D ]J\}}}t ||gj }||d  |td|td|gdd q&td|dS )	zc
    Creates a geojson of hexagonal features based on the outputs of
    _compute_wgs84_hexbin
    Nr   ZFeatureZPolygon)typeZcoordinates)r[   idZgeometryZFeatureCollection)r[   features)	r   r6   r2   zipr9   Ttolistr3   dict)rW   rX   idsr]   r
   r   idxZpointsr   r   r   _hexagons_to_geojson(  s    rd      Fc           ,      C   s  t t dd}|dkrtj}|d |d  ddgj}|d |d  ddgj}t|d |d  j|d |d  j||d|||d\}}}}t|||}|dkr0|dkr|dkrtd	d	d
} nL|dkr|dk	rtd	|d
} n.|dk	r|dkrt||d
} nt||d
} t	|d |d |d |d | }|dkrNt| | d}|d dk	rr|d 
|d j}!nd|d ji}!g }"|! D ]\}#}$|d j|$ }%t|%|d  j|%|d  j|||d r|%|d  jnd|||d\}&}&}}'|"tjtj||'f ddgd qtj|"d|! djddd}(t|(d |(d< |dkrj|(d  |(d  g}t|(|dddddd|d dk	rdnd|||	|
||||||||||d})|rt|d dk	r|d j|d dn|d |d |d |d d}*d|*jd _d|*jd _||*jd _ |)!|*jd  |d dk	rt"t#|*j$D ]d}+d|*j$|+ jd _d|*j$|+ jd _||*j$|+ jd _ |)j$|+ jd |*j$|+ jd g|)j$|+ _qL|)S )zO
    Returns a figure aggregating scattered points into connected hexagons
    N)argsconstructor
data_framer
   r   r   r   )r
   r   rU   rV   r<   r=   r>   r?   i  r   r   r   )r
   r   animation_framer<   	locations)columns)Zaxiskeys)frameindex)rn   rm   TF)r<   rj   rm   )rh   geojsonrj   r<   Z
hover_datari   color_discrete_sequencecolor_discrete_maplabelscolor_continuous_scalerange_colorcolor_continuous_midpointopacityr   centermapbox_styletitletemplater   r   )Zby)rh   r
   r   ri   skip)%r   localsr   ZmeanZaggvaluesrZ   rd   ra   r!   groupbygroupsrn   itemslocr3   rT   Z	DataFrameZc_concatrl   Zrename_axisZreset_indexZ
to_numericr   r   r   r   Zsort_valuesdataZ	hoverinfoZhovertemplatemarkerZ	add_tracer1   r2   frames),rh   r
   r   r<   
nx_hexagonr>   ri   rp   rq   rr   rs   rt   ru   rv   r   rw   rx   ry   rz   r   r   r?   show_original_dataoriginal_data_markerrf   rU   rV   rW   rX   rY   countro   r    r   Zagg_data_frame_listrm   rn   ZdfrA   Zaggregated_valueZagg_data_frameZfigZoriginal_figrH   r   r   r   create_hexbin_mapbox=  s    
    

 



r   r'   z/Number of hexagons (horizontally) to be createdfunctionz8Numpy array aggregator, it must take as input a 1D arrayzand output a scalar value.z=Minimum number of points in a hexagon for it to be displayed.z3If None and color is not set, display all hexagons.zDIf None and color is set, only display hexagons that contain points.boolzCWhether to show the original data on top of the hexbin aggregation.ra   zScattermapbox marker options.)r   r>   r?   r   r   )Zoverride_dict)NNNNNNNN)N)Zplotly.express._corer   Zplotly.express._docr   Zplotly.express._chart_typesr   r   Znumpyr   ZpandasrT   r   r   r!   rQ   rZ   rd   r   ra   __doc__r   r   r   r   <module>   s   		 *        
G

 