U
    VcoW                     @   s  d Z ddlZddlZddlZddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ dd	lmZ dd	lmZ dd	lmZ dd	lmZ d
dddddZdZeejejgZeejgZdd Zdd Zdd Zdd Z dd Z!dd Z"dd Z#dd  Z$G d!d" d"ej%Z&dS )#zThe TensorBoard metrics plugin.    N)wrappers)errors)plugin_util)	http_util)provider)base_plugin)metadataz	image/bmpz	image/gifz
image/jpegz	image/pngzimage/svg+xml)ZbmpZgifZjpegZpngsvgzapplication/octet-streamc                 C   sj   t t}t t}|  D ]D\}}| D ]2\}}|j}t|r,|| | || | q,q||fS )a  Gets maps from tags to descriptions, and descriptions to runs.

    Args:
        mapping: a nested map `d` such that `d[run][tag]` is a time series
          produced by DataProvider's `list_*` methods.

    Returns:
        A tuple containing
            tag_to_descriptions: A map from tag strings to a set of description
                strings.
            description_to_runs: A map from description strings to a set of run
                strings.
    )collectionsdefaultdictsetitemsdescriptionlenadd)mappingtag_to_descriptionsdescription_to_runsruntag_to_contenttag	metadatumr    r   N/tmp/pip-unpacked-wheel-g8kmtpbc/tensorboard/plugins/metrics/metrics_plugin.py_get_tag_description_info4   s    

r   c           	      C   sl   g }| D ]P}t || }t|dkr(dnd}d| d d| }|d | }|| qd}|d| S )	a  Creates a single description from a set of descriptions.

    Descriptions may be composites when a single tag has different descriptions
    across multiple runs.

    Args:
        descriptions: A list of description strings.
        description_to_runs: A map from description strings to a set of run
            strings.

    Returns:
        The combined description string.
       runsr   z## For z: z, 
z# Multiple descriptions
)sortedr   joinappend)	descriptionsr   Zprefixed_descriptionsr   r   Zrun_or_runsZ
run_headerZdescription_htmlheaderr   r   r   _build_combined_descriptionN   s    r#   c                 C   sX   t | \}}i }|D ]>}t|| }t|dkr:|d }n
t||}t|||< q|S )a  Returns a map of tags to descriptions.

    Args:
        mapping: a nested map `d` such that `d[run][tag]` is a time series
          produced by DataProvider's `list_*` methods.

    Returns:
        A map from tag strings to description HTML strings. E.g.
        {
            "loss": "<h1>Multiple descriptions</h1><h2>For runs: test, train
            </h2><p>...</p>",
            "loss2": "<p>The lossy details</p>",
        }
    r   r   )r   r   r   r#   r   Zmarkdown_to_safe_html)r   r   r   resultr   r!   r   r   r   r   _get_tag_to_descriptionh   s    
 r%   c                    s    fdd D S )aM  Returns a map of run names to a list of tag names.

    Args:
        mapping: a nested map `d` such that `d[run][tag]` is a time series
          produced by DataProvider's `list_*` methods.

    Returns:
        A map from run strings to a list of tag strings. E.g.
            {"loss001a": ["actor/loss", "critic/loss"], ...}
    c                    s   i | ]}|t  | qS r   )r   .0r   r   r   r   
<dictcomp>   s      z%_get_run_tag_info.<locals>.<dictcomp>r   r(   r   r(   r   _get_run_tag_info   s    r*   c                 C   s   t | t| dS )a  Prepares a scalar or histogram mapping for client consumption.

    Args:
        mapping: a nested map `d` such that `d[run][tag]` is a time series
          produced by DataProvider's `list_*` methods.

    Returns:
        A dict with the following fields:
            runTagInfo: the return type of `_get_run_tag_info`
            tagDescriptions: the return type of `_get_tag_to_description`
    )Z
runTagInfotagDescriptions)r*   r%   r(   r   r   r   _format_basic_mapping   s    r,   c                 C   sH   |d }g }| D ]2}t |j|kr$q||j|j|j| jd q|S )a  Formats image metadata from a list of BlobSequenceDatum's for clients.

    This expects that frontend clients need to access images based on the
    run+tag+sample.

    Args:
        sorted_datum_list: a list of DataProvider's `BlobSequenceDatum`, sorted by
            step. This can be produced via DataProvider's `read_blob_sequences`.
        sample: zero-indexed integer for the requested sample.

    Returns:
        A list of `ImageStepDatum` (see http_api.md).
       )stepwallTimeimageId)r   valuesr    r.   	wall_timeblob_key)Zsorted_datum_listsampleindexZ	step_datadatumr   r   r   !_format_image_blob_sequence_datum   s    
r7   c                 C   sL   t t}|  D ]0\}}| D ]\}}d|jd i|| |< q"qt|S )a
  Returns a map of tag names to run information.

    Args:
        mapping: the result of DataProvider's `list_blob_sequences`.

    Returns:
        A nested map from run strings to tag string to image info, where image
        info is an object of form {"maxSamplesPerStep": num}. For example,
        {
            "reshaped": {
                "test": {"maxSamplesPerStep": 1},
                "train": {"maxSamplesPerStep": 1}
            },
            "convolved": {"test": {"maxSamplesPerStep": 50}},
        }
    ZmaxSamplesPerStepr-   )r
   r   dictr   
max_length)r   Ztag_run_image_infor   r   r   r   r   r   r   _get_tag_run_image_info   s    
 r:   c                 C   s   t | t| dS )aV  Prepares an image mapping for client consumption.

    Args:
        mapping: the result of DataProvider's `list_blob_sequences`.

    Returns:
        A dict with the following fields:
            tagRunSampledInfo: the return type of `_get_tag_run_image_info`
            tagDescriptions: the return type of `_get_tag_description_info`
    )r+   ZtagRunSampledInfo)r%   r:   r(   r   r   r   _format_image_mapping   s    r;   c                   @   s   e Zd ZdZejZdd Zdd Zdd Z	dd	 Z
d
d Zejjdd Zd)ddZdd Zejjdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zejjd%d& Zd'd( ZdS )*MetricsPluginzMetrics Plugin for TensorBoard.c                 C   sr   |j | _|jpi }|tjd|tjd|tjdd| _t	j
ddd| _t	j
ddd| _t	j
d	dd| _d
S )zInstantiates MetricsPlugin.

        Args:
            context: A base_plugin.TBContext instance. MetricsLoader checks that
                it contains a valid `data_provider`.
        i  3   
   )scalars
histogramsimageszscalar time seriesr   )Z	data_kindZlatest_known_versionzhistogram time serieszimage time seriesN)Zdata_provider_data_providersampling_hintsgetscalar_metadataPLUGIN_NAMEhistogram_metadataimage_metadata_plugin_downsamplingr   Z_MetadataVersionChecker_scalar_version_checker_histogram_version_checker_image_version_checker)selfcontextrC   r   r   r   __init__   s*    
 zMetricsPlugin.__init__c                 C   s   t jdddS )NTzTime Series)Zis_ng_componentZtab_name)r   ZFrontendMetadatarM   r   r   r   frontend_metadata  s     zMetricsPlugin.frontend_metadatac                 C   s   | j | j| jdS )N)z/tagsz/timeSeriesz
/imageData)_serve_tags_serve_time_series_serve_image_datarP   r   r   r   get_plugin_apps  s    zMetricsPlugin.get_plugin_appsc                 C   s   t jtjtjfS )N)rE   rF   rG   rH   rP   r   r   r   data_plugin_names&  s    zMetricsPlugin.data_plugin_namesc                 C   s   dS )NFr   rP   r   r   r   	is_active-  s    zMetricsPlugin.is_activec                 C   s4   t |j}t |j}| j||d}t||dS )N)
experimentapplication/json)r   rN   environexperiment_id
_tags_implr   Respond)rM   requestctxrX   r5   r   r   r   rR   0  s    zMetricsPlugin._serve_tagsNc                 C   s   | j j||tjd}| |tj| j}| j j||tjd}|dkrFi }| |tj| j	}| j j
||tjd}|dkrxi }| |tj| j}i }t||d< t||d< t||d< |S )a  Returns tag metadata for a given experiment's logged metrics.

        Args:
            ctx: A `tensorboard.context.RequestContext` value.
            experiment: optional string ID of the request's experiment.

        Returns:
            A nested dict 'd' with keys in ("scalars", "histograms", "images")
                and values being the return type of _format_*mapping.
        )r[   plugin_nameNr?   r@   rA   )rB   Zlist_scalarsrE   rF   _filter_by_versionZparse_plugin_metadatarJ   Zlist_tensorsrG   rK   Zlist_blob_sequencesrH   rL   r,   r;   )rM   r_   rX   Zscalar_mappingZhistogram_mappingZimage_mappingr$   r   r   r   r\   7  sN    zMetricsPlugin._tags_implc           
      C   s^   dd |D }|  D ]B\}}|  D ]0\}}||j}	||	j||sJq&||| |< q&q|S )z@Filter `DataProvider.list_*` output by summary metadata version.c                 S   s   i | ]
}|i qS r   r   r&   r   r   r   r)   o  s      z4MetricsPlugin._filter_by_version.<locals>.<dictcomp>)r   Zplugin_contentokversion)
rM   r   Zparse_metadataZversion_checkerr$   r   r   r   r   Zmdr   r   r   ra   m  s    
z MetricsPlugin._filter_by_versionc                 C   s   t |j}t |j}|jdkr0|jd}n|jd}|sJt	dzt
|}W n tk
rv   t	dY nX | |||}t||dS )NPOSTrequestszMissing 'requests' fieldz"Unable to parse 'requests' as JSONrY   )r   rN   rZ   r[   methodformrD   argsr   InvalidArgumentErrorjsonloads
ValueError_time_series_implr   r]   )rM   r^   r_   rX   Zseries_requests_stringseries_requestsresponser   r   r   rS   x  s    


z MetricsPlugin._serve_time_seriesc                    s    fdd|D }|S )a~  Constructs a list of responses from a list of series requests.

        Args:
            ctx: A `tensorboard.context.RequestContext` value.
            experiment: string ID of the request's experiment.
            series_requests: a list of `TimeSeriesRequest` dicts (see http_api.md).

        Returns:
            A list of `TimeSeriesResponse` dicts (see http_api.md).
        c                    s   g | ]}  |qS r   )_get_time_series)r'   r^   r_   rX   rM   r   r   
<listcomp>  s   z3MetricsPlugin._time_series_impl.<locals>.<listcomp>r   )rM   r_   rX   rn   	responsesr   rq   r   rm     s    zMetricsPlugin._time_series_implc                 C   sZ   | d}| d}| d}| d}||d}t|trD||d< t|trV||d< |S )Nr   r   pluginr4   )rt   r   )rD   
isinstancestrint)rM   series_requestr   r   rt   r4   ro   r   r   r   _create_base_response  s    






z#MetricsPlugin._create_base_responsec                 C   s   | d}| d}| d}| d}t|ts6dS |tjkrX|tjkrX|tjkrXdS |tkrnt|tsndS |tkrt|t	sdS d S )	Nr   rt   r   r4   zMissing tagzInvalid pluginzMissing runzMissing sample)
rD   ru   rv   rE   rF   rG   rH   _SINGLE_RUN_PLUGINS_SAMPLED_PLUGINSrw   )rM   rx   r   rt   r   r4   r   r   r   _get_invalid_request_error  s$    




z(MetricsPlugin._get_invalid_request_errorc                 C   s   | d}| d}| d}| d}| |}| |}	|	rL|	|d< |S |rV|gnd}
d}|tjkrx| ||||
}|tjkr| ||||
}|tjkr| 	|||||
}||d< |S )aY  Returns time series data for a given tag, plugin.

        Args:
            ctx: A `tensorboard.context.RequestContext` value.
            experiment: string ID of the request's experiment.
            series_request: a `TimeSeriesRequest` (see http_api.md).

        Returns:
            A `TimeSeriesResponse` dict (see http_api.md).
        r   r   rt   r4   errorNZrunToSeries)
rD   ry   r|   rE   rF   _get_run_to_scalar_seriesrG   _get_run_to_histogram_seriesrH   _get_run_to_image_series)rM   r_   rX   rx   r   r   rt   r4   ro   Zrequest_errorr   run_to_seriesr   r   r   rp     sF    






   
   
    zMetricsPlugin._get_time_seriesc           
   	   C   sh   | j j||tj| jd tj||gdd}i }| D ],\}}||krHq6dd || D }	|	||< q6|S )a  Builds a run-to-scalar-series dict for client consumption.

        Args:
            ctx: A `tensorboard.context.RequestContext` value.
            experiment: a string experiment id.
            tag: string of the requested tag.
            runs: optional list of run names as strings.

        Returns:
            A map from string run names to `ScalarStepDatum` (see http_api.md).
        r?   r   tagsr[   r`   Z
downsampleZrun_tag_filterc                 S   s   g | ]}|j |j|jd qS ))r/   r.   value)r2   r.   r   r'   r6   r   r   r   rr     s
   z;MetricsPlugin._get_run_to_scalar_series.<locals>.<listcomp>)rB   Zread_scalarsrE   rF   rI   r   RunTagFilterr   
rM   r_   rX   r   r   r   r   
result_runtag_datar1   r   r   r   r~     s     
z'MetricsPlugin._get_run_to_scalar_seriesc                 C   s   |j  }dd |D }|S )zFormats a histogram datum's bins for client consumption.

        Args:
            datum: a DataProvider's TensorDatum.

        Returns:
            A list of `HistogramBin`s (see http_api.md).
        c                 S   s$   g | ]}|d  |d |d dqS )r   r   r-   )minmaxcountr   )r'   xr   r   r   rr     s     z>MetricsPlugin._format_histogram_datum_bins.<locals>.<listcomp>)Znumpytolist)rM   r6   Z
numpy_listbinsr   r   r   _format_histogram_datum_bins  s    	
z*MetricsPlugin._format_histogram_datum_binsc           
   	      sl    j j||tj jd tj||gdd}i }| D ]0\}}||krHq6 fdd|| D }	|	||< q6|S )a  Builds a run-to-histogram-series dict for client consumption.

        Args:
            ctx: A `tensorboard.context.RequestContext` value.
            experiment: a string experiment id.
            tag: string of the requested tag.
            runs: optional list of run names as strings.

        Returns:
            A map from string run names to `HistogramStepDatum` (see http_api.md).
        r@   r   r   c                    s"   g | ]}|j |j |d qS ))r/   r.   r   )r2   r.   r   r   rP   r   r   rr   4  s
   z>MetricsPlugin._get_run_to_histogram_series.<locals>.<listcomp>)rB   Zread_tensorsrG   rF   rI   r   r   r   r   r   rP   r   r     s     

z*MetricsPlugin._get_run_to_histogram_seriesc              	   C   sl   | j j||tj| jd tj||gdd}i }| D ]0\}}	||	krHq6|	| }
t|
|}|r6|||< q6|S )a  Builds a run-to-image-series dict for client consumption.

        Args:
            ctx: A `tensorboard.context.RequestContext` value.
            experiment: a string experiment id.
            tag: string of the requested tag.
            sample: zero-indexed integer for the requested sample.
            runs: optional list of run names as strings.

        Returns:
            A `RunToSeries` dict (see http_api.md).
        rA   )r   r   )	rB   Zread_blob_sequencesrH   rF   rI   r   r   r   r7   )rM   r_   rX   r   r4   r   r   r   r   r   Zblob_sequence_datum_listZseriesr   r   r   r   @  s&     
z&MetricsPlugin._get_run_to_image_seriesc                 C   sB   t |j}|jd }|s$td| ||\}}t|||S )zServes an individual image.r0   zMissing 'imageId' field)	r   rN   rZ   rh   r   ri   _image_data_implr   r]   )rM   r^   r_   r3   datacontent_typer   r   r   rT   b  s    

zMetricsPlugin._serve_image_datac                 C   s0   | j j||d}td|}t|t}||fS )ao  Gets the image data for a blob key.

        Args:
            ctx: A `tensorboard.context.RequestContext` value.
            blob_key: a string identifier for a DataProvider blob.

        Returns:
            A tuple containing:
              data: a raw bytestring of the requested image's contents.
              content_type: a string HTTP content type.
        )r3   N)rB   Z	read_blobimghdrwhat_IMGHDR_TO_MIMETYPErD   _DEFAULT_IMAGE_MIMETYPE)rM   r_   r3   r   Z
image_typer   r   r   r   r   m  s     zMetricsPlugin._image_data_impl)N)__name__
__module____qualname____doc__r   rF   r`   rO   rQ   rU   rV   rW   r   RequestZapplicationrR   r\   ra   rS   rm   ry   r|   rp   r~   r   r   r   rT   r   r   r   r   r   r<      s0   !

6
)$$"

r<   )'r   r
   r   rj   Zwerkzeugr   Ztensorboardr   r   Ztensorboard.backendr   Ztensorboard.datar   Ztensorboard.pluginsr   Ztensorboard.plugins.histogramr   rG   Ztensorboard.plugins.imagerH   Ztensorboard.plugins.metricsZtensorboard.plugins.scalarrE   r   r   	frozensetrF   rz   r{   r   r#   r%   r*   r,   r7   r:   r;   ZTBPluginr<   r   r   r   r   <module>   sB   
! 