U
    fA                     @   s  d Z ddlmZmZ ddlZddlZddlZddlZddlZddl	m
Z
mZ ddlmZ ddlZddlZddlZddlZejd dkrddlmZ n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m Z m!Z!m"Z"m#Z# d
dl$m%Z% d1ddZ&G dd dZ'G dd de'Z(dZ)dd Z*dd Z+dej,ej- fddZ.d d! Z/d"d# Z0d2d$d%Z1zDe Z2e2j3j4d& Z5e56e'd'd(  e56e7Z8d)d* Z9e56e7e9 W n   Y nX G d+d, d,Z:G d-d. d.Z;G d/d0 d0Z<dS )3z> Visualize the SHAP values with additive force style layouts.
    )divisionunicode_literalsN)displayHTML)get_ipython   )Sequence   )labels   )convert_to_linkInstanceModelData	DenseDataLinkhclust_ordering)draw_additive_plotidentityRdBuFT   r   c                 C   s  t | tjkr"t| dkr"| d } t | tjks<t | tkr`t |tksXt|t| kr`tdt |tkrttdt|}t |tjkrt|S t	t |dkr|dkrt|j
}|j}ntt	t |dkr|dkrt|j}|j}nJt|tr|dkr|}d}n,|dk	r0t|jdkr0|dkr0|}d}t|jdkrTt|dt|f}|dkrfdg}nt |t	krz|g}|jd dkr|dkrd	d
 t|jd D }|dkrdd
 tt|D }t |tjkr| }t||jd kr$d}t||jd d kr|d7 }t|ttdt|f|}t| t|dddf |  |dddf d||td|ttdt|ft|}t||||	||dS |rtd|jd dkrtd g }t|jd D ]}|dkrdd
 t|jd D }|dkr(dd
 tt|D }n||ddf }ttdt|f|}t| t||ddf |  ||ddf d||td|ttdt|ft|}|| qt|||
||dS dS )a)   Visualize the given SHAP values with an additive force layout.
    
    Parameters
    ----------
    base_value : float
        This is the reference value that the feature contributions start from. For SHAP values it should
        be the value of explainer.expected_value.

    shap_values : numpy.array
        Matrix of SHAP values (# features) or (# samples x # features). If this is a 1D array then a single
        force plot will be drawn, if it is a 2D array then a stacked force plot will be drawn.

    features : numpy.array
        Matrix of feature values (# features) or (# samples x # features). This provides the values of all the
        features, and should be the same shape as the shap_values argument.

    feature_names : list
        List of feature names (# features).

    out_names : str
        The name of the outout of the model (plural to support multi-output plotting in the future).
    
    link : "identity" or "logit"
        The transformation used when drawing the tick mark labels. Using logit will change log-odds numbers
        into probabilities. 

    matplotlib : bool
        Whether to use the default Javascript output, or the (less developed) matplotlib output. Using matplotlib
        can be helpful in scenarios where rendering Javascript/HTML is inconvenient. 

    r	   r   zIn v0.20 force_plot now requires the base value as the first parameter! Try shap.force_plot(explainer.expected_value, shap_values) or for multi-output models try shap.force_plot(explainer.expected_value[0], shap_values[0]).zAThe shap_values arg looks looks multi output, try shap_values[i].z%<class 'pandas.core.frame.DataFrame'>Nz#<class 'pandas.core.series.Series'>zoutput valuec                 S   s   g | ]}t d  t| qS ZFEATUREr
   str.0i r   7/tmp/pip-target-lpfmz8o1/lib/python/shap/plots/force.py
<listcomp>l   s     zforce_plot.<locals>.<listcomp>c                 S   s   g | ]}d qS  r   r   _r   r   r   r    n   s     z=Length of features is not equal to the length of shap_values!z You might be using an old format shap_values array with the base value as the last column. In this case just pass the array without the last column.figsizeshowtext_rotationzMmatplotlib = True is not yet supported for force plots with multiple samples!i  zNshap.force_plot is slow for many thousands of rows, try subsampling your data.c                 S   s   g | ]}t d  t| qS r   r   r   r   r   r   r       s     c                 S   s   g | ]}d qS r!   r   r   r   r   r   r       s     )	plot_cmapordering_keysordering_keys_time_formatr(   )typenpZndarraylenlist	ExceptionAssertionErrorr   	visualizer   columnsvaluesindex
isinstanceshapeZreshaperangeflattenr   ZzerosAdditiveExplanationsumr   r   warningswarnZonesappend)
base_valueZshap_valuesfeaturesZfeature_names	out_nameslinkr)   
matplotlibr'   r&   r*   r+   r(   msginstanceeZexpsr   Zdisplay_featuresr   r   r   
force_plot   s    $

$






rG   c                   @   s   e Zd Zdd ZdS )Explanationc                 C   s   d S Nr   selfr   r   r   __init__   s    zExplanation.__init__N__name__
__module____qualname__rL   r   r   r   r   rH      s   rH   c                   @   s   e Zd Zdd ZdS )r:   c	           	      C   sl   || _ || _|| _|| _t|ts&t|| _t|ts:t|| _	t|t
sNt|| _t|tsbt|| _d S rI   )r?   	out_valueeffectseffects_varr6   r   r1   rE   r   rB   r   modelr   data)	rK   r?   rQ   rR   rS   rE   rB   rT   rU   r   r   r   rL      s    zAdditiveExplanation.__init__NrM   r   r   r   r   r:      s   r:   a  
<div style='color: #900; text-align: center;'>
  <b>Visualization omitted, Javascript library not loaded!</b><br>
  Have you run `initjs()` in this notebook? If this notebook was from another
  user you must also trust this notebook (File -> Trust notebook). If you are viewing
  this notebook on github the Javascript has been stripped for security. If you are using
  JupyterLab this error is because a JupyterLab extension has not yet been written.
</div>c               	   C   s   t jt jtd dd} tj| dd}| }W 5 Q R X t jt jtd dd}t|d}| }W 5 Q R X t	|
d}ttdj|d	d
j|d  d S )Nr   	resources	bundle.jsutf-8encodingzlogoSmallGray.pngrbzI<div align='center'><img src='data:image/png;base64,{logo_data}' /></div>)	logo_dataz<script>{bundle_data}</script>)bundle_data)ospathjoinsplit__file__ioopenreadbase64	b64encodedecoder   r   format)bundle_pathfr]   Z	logo_pathr\   r   r   r   initjs   s    

rl   c              	   C   s   d}t | tkrt| d} d}| d tjtjtd dd}t	j|dd	}|
 }W 5 Q R X | | | d
 | |j | d |r|   dS )z( Save html plots to an output file.
    FwTz<html><head><script>
r   rV   rW   rX   rY   z</script></head><body>
z</body></html>
N)r,   r   rd   writer^   r_   r`   ra   rb   rc   re   rU   close)out_fileZ	plot_htmlZinternal_openrj   rk   r]   r   r   r   	save_html   s    




rq   r   c                    s    dd  fddt| D  S )Nr   r"   c                 3   s   | ]}t  V  qd S rI   )randomchoicer#   charsr   r   	<genexpr>   s     zid_generator.<locals>.<genexpr>)r`   r8   )sizeru   r   rt   r   id_generator   s    rx   c                 C   sF   t | tr|  S t | tjr&t| S t | tjr>t|  S | S d S rI   )r6   bytesrh   r-   r   Zgenericfloatitemxr   r   r   ensure_not_numpy   s    
r~   c                 C   s   t | ts:t | ts:tt| ds:tdtt|  t | trt| dksXtdtd}| D ]}t	|
|sftdqf| S )Nz	unicode'>z,Plot color map must be string or list! not: r	   z&Color map must be at least two colors.z#[a-fA-F0-9]{6}$zInvalid color found in CMAP.)r6   r   r/   r,   endswithr1   r.   recompileboolmatch)ZcmapZ
_rgbstringcolorr   r   r   verify_valid_cmap   s    (

r   c                 C   s   t |}t| tr@|r.t| |dj|||dS t| |d S nt| trj|r\dshtdqt|  S nXt| t	rt
| dkrt| d tr|rdstdqt| |||d S ndstdd S )N)r)   r%   Fz;Matplotlib plot is only supported for additive explanationsr   )r)   r*   r+   zEvisualize() can only display Explanation objects (or arrays of them)!)r   r6   r:   AdditiveForceVisualizerrC   htmlrH   r1   SimpleListVisualizerr   r.   AdditiveForceArrayVisualizer)rF   r)   rC   r&   r'   r*   r+   r(   r   r   r   r2     s    

$r2   z	text/htmlc                 C   s
   t | jS rI   )r2   rU   r|   r   r   r   <lambda>#      r   c                 C   sJ   t | tr.t| dkr.t | d tr.t| jS td kr>t| S t| S d S Nr   )r6   r   r.   r:   r2   rU   old_list_formatterr   rF   r   r   r   try_list_display%  s    $
r   c                   @   s   e Zd Zdd Zdd ZdS )r   c                    s   t  tstdi }t fddtt jjD ] } j|  j	j
| d||< q4 jj jt j jj| jjd| _d S )Nz<SimpleListVisualizer can only visualize Explanation objects!c                    s    j |  dkS r   rR   jr   r   r   r   4  r   z/SimpleListVisualizer.__init__.<locals>.<lambda>Zeffectvalue)outNamesr?   rB   featureNamesr@   r)   )r6   rH   r1   filterr8   r.   rU   group_namesrR   rE   group_display_valuesrT   rA   r?   r   rB   r)   )rK   rF   r@   r   r   r   r   rL   /  s    "
zSimpleListVisualizer.__init__c                 C   s   t djtt| jt dS )Nz
<div id='{id}'>{err_msg}</div>
 <script>
   if (window.SHAP) SHAP.ReactDom.render(
    SHAP.React.createElement(SHAP.SimpleListVisualizer, {data}),
    document.getElementById('{id}')
  );
</script>err_msgrU   idr   ri   r   jsondumpsrU   rx   rJ   r   r   r   r   B  s
     
 zSimpleListVisualizer.htmlNrN   rO   rP   rL   r   r   r   r   r   r   .  s   r   c                   @   s(   e Zd Zd
ddZdddZdd Zd	S )r   r   c                    s   t  tstdi }t fddtt jjD ](}t j	| t j
j| d||< q4 jjt jt jt j jj||d| _d S )NzGAdditiveForceVisualizer can only visualize AdditiveExplanation objects!c                    s    j |  dkS r   r   r   r   r   r   r   T  r   z2AdditiveForceVisualizer.__init__.<locals>.<lambda>r   )r   	baseValueoutValuerB   r   r@   r)   )r6   r:   r1   r   r8   r.   rU   r   r~   rR   rE   r   rT   rA   r?   rQ   r   rB   )rK   rF   r)   r@   r   r   r   r   rL   N  s     "z AdditiveForceVisualizer.__init__r   c                 C   s(   || j d< tdjtt| j t dS )NZlabelMarginz
<div id='{id}'>{err_msg}</div>
 <script>
   if (window.SHAP) SHAP.ReactDom.render(
    SHAP.React.createElement(SHAP.AdditiveForceVisualizer, {data}),
    document.getElementById('{id}')
  );
</script>r   )rU   r   ri   r   r   r   rx   )rK   Zlabel_marginr   r   r   r   c  s    
 
 zAdditiveForceVisualizer.htmlc                 C   s   t | j|||d}|S )Nr%   )r   rU   )rK   r&   r'   r(   Zfigr   r   r   rC   n  s    z"AdditiveForceVisualizer.matplotlibN)r   )r   )rN   rO   rP   rL   r   rC   r   r   r   r   r   M  s   

r   c                   @   s   e Zd ZdddZdd ZdS )r   r   Nc              	      sp  t  d tstdt fdd D rFttdd  D }ndsRtdt |d  jt |d  jk rt	| t
|} d jjt d j d j  d jjg |t|d	rt|nd |d
| _t D ]\}| jd tjt|| d i d tfddttjjD ]8}tj| tjj| d| jd d d |< q0qd S )Nr   zVAdditiveForceArrayVisualizer can only visualize arrays of AdditiveExplanation objects!c                    s    g | ]}|j j d  j jkqS )r	   )rT   rk   r   rF   )arrr   r   r    z  s     z9AdditiveForceArrayVisualizer.__init__.<locals>.<listcomp>c                 S   s   g | ]
}|j qS r   r   r   r   r   r   r    {  s     FzBTried to visualize an array of explanations from different models!__iter__)r   r   rB   r   explanationsr)   r*   r+   r   r	   )r   ZsimIndexr@   c                    s"    j |  dkp  jjd| f dkS r   )rR   rE   r}   r   r   r   r   r     r   z7AdditiveForceArrayVisualizer.__init__.<locals>.<lambda>r   r@   )r6   r:   r1   allr   r-   Zvstackr;   rR   ZflipudZargsortrT   rA   r~   r?   rB   __str__rU   r   hasattrr/   	enumerater>   rQ   r   r8   r.   rE   r   )rK   r   r)   r*   r+   Z
clustOrderindr   r   )r   rF   r   rL   u  s8    $





"z%AdditiveForceArrayVisualizer.__init__c                 C   s   t djtt| jt dS )Nz
<div id='{id}'>{err_msg}</div>
 <script>
   if (window.SHAP) SHAP.ReactDom.render(
    SHAP.React.createElement(SHAP.AdditiveForceArrayVisualizer, {data}),
    document.getElementById('{id}')
  );
</script>r   r   rJ   r   r   r   r     s
     
 z!AdditiveForceArrayVisualizer.html)r   NNr   r   r   r   r   r   t  s   
&r   )NNNr   r   FTr   NNr   )r   Fr   TNNr   )=__doc__
__future__r   r   r^   rc   stringr   rr   ZIPython.core.displayr   r   ZIPythonr   rf   numpyr-   Zscipy.clusterZscipysysversion_infocollections.abcr   collectionsr<   r   r"   r
   commonr   r   r   r   r   r   r   Zplots.force_matplotlibr   rG   rH   r:   r   rl   rq   ascii_uppercasedigitsrx   r~   r   r2   ipdisplay_formatter
formattersZsvg_formatterZfor_typer/   r   r   r   r   r   r   r   r   r   <module>   sf   $             
 



'