def plotQC(df, value, title, size=10, jitter=0.35, factor_reduce=0.5):
    df_i = df.dropna(subset=[value])
    df_i = df_i.reset_index(drop=True)
    key_dimensions = [(value, title)]
    value_dimensions = [('Gene', 'Gene'), ('Metadata_X', 'Position')]
    macro = hv.Table(df_i, key_dimensions, value_dimensions)
    options = dict(color_index='Position',
                   legend_position='left',
                   jitter=jitter,
                   width=1000,
                   height=600,
                   scaling_method='width',
                   scaling_factor=2,
                   size_index=2,
                   show_grid=True,
                   tools=['hover', 'box_select', 'lasso_select'],
                   line_color='k',
                   cmap='Category20',
                   size=size,
                   nonselection_color='lightskyblue')
    quality_scatter = macro.to.scatter('Gene', [title]).options(**options)
    sel = streams.Selection1D(source=quality_scatter)

    image_name = df_i.loc[0, "img_name_raw"]
    img = cv2.imread(image_name, 0)
    h, w = img.shape
    w = int(factor_reduce * w)
    h = int(factor_reduce * h)
    pad = int(2.2 * w)

    def selection_callback(index):
        if not index:
            return hv.Div("")
        divtext = f'<table width={pad}  border=1 cellpadding=10 align=center valign=center>'
        for i, j in grouped(index, 2):
            value_s = '{:f}'.format(df_i[value][i])
            value_s2 = '{:f}'.format(df_i[value][j])
            divtext += '<tr>'
            divtext += f'<td align=center valign=center><br> {i} Value: {value_s}</br></td>' + "\n"
            divtext += f'<td align=center valign=center><br> {j} Value: {value_s2}</br></td>' + "\n"
            divtext += '</tr><tr>'
            divtext += f'<td align=center valign=center><img src={df_i.loc[i, "img_name_raw"]} width={w} height={h}></td>'
            divtext += f'<td align=center valign=center><img src={df_i.loc[j, "img_name_raw"]} width={w} height={h}></td>'
            divtext += '</tr>'
        if len(index) % 2 == 1:
            value_s = '{:f}'.format(df_i[value][index[-1]])
            divtext += '<tr>'
            divtext += f'<td align=center valign=center><br> {index[-1]} Value: {value_s}</br></td>' + "\n"
            divtext += f'<td align=center valign=center><br> </br></td>' + "\n"
            divtext += '</tr><tr>'
            divtext += f'<td align=center valign=center><img src={df_i.loc[index[-1], "img_name_raw"]} width={w} height={h}></td>'
            divtext += f'<td align=center valign=center></td>'
            divtext += '</tr>'
        divtext += '</table>'
        return hv.Div(str(divtext))

    div = hv.DynamicMap(selection_callback, streams=[sel])
    hv.streams.PlotReset(source=quality_scatter,
                         subscribers=[lambda reset: sel.event(index=[])])
    return hv.Layout(quality_scatter + div).cols(1), sel
def plotNselect_tSNE(df_feat, features, size=10, perplexity=80, ncomp=2):
    df_i = df_feat.dropna()
    df_i = df_i.reset_index(drop=True)

    Y = TSNE(perplexity=perplexity,
             n_components=ncomp).fit_transform(df_i[features])

    options = dict(legend_position='left',
                   width=1000,
                   height=600,
                   scaling_method='width',
                   scaling_factor=2,
                   size_index=2,
                   show_grid=True,
                   tools=['hover', 'box_select', 'lasso_select'],
                   line_color='k',
                   cmap='Accent',
                   size=size,
                   nonselection_color='lightskyblue')
    quality_scatter = hv.Scatter(Y).options(**options)
    sel = streams.Selection1D(source=quality_scatter)

    image_name = df_i.loc[0, "img_name_raw"]
    img = cv2.imread(image_name, 0)
    h, w = img.shape
    w = int(0.8 * w)
    h = int(0.8 * h)
    pad = int(2.2 * w)

    def selection_callback(index):
        if not index:
            return hv.Div("")
        divtext = f'<table width={pad}  border=1 cellpadding=10 align=center valign=center>'
        for i, j in grouped(index, 2):
            value_s = '{:f}'.format(df_i[value][i])
            value_s2 = '{:f}'.format(df_i[value][j])
            divtext += '<tr>'
            divtext += f'<td align=center valign=center><br> {i} Value: {value_s}</br></td>' + "\n"
            divtext += f'<td align=center valign=center><br> {j} Value: {value_s2}</br></td>' + "\n"
            divtext += '</tr><tr>'
            divtext += f'<td align=center valign=center><img src={df_i.loc[i, "img_name_raw"]} width={w} height={h}></td>'
            divtext += f'<td align=center valign=center><img src={df_i.loc[j, "img_name_raw"]} width={w} height={h}></td>'
            divtext += '</tr>'
        if len(index) % 2 == 1:
            value_s = '{:f}'.format(df_i[value][index[-1]])
            divtext += '<tr>'
            divtext += f'<td align=center valign=center><br> {index[-1]} Value: {value_s}</br></td>' + "\n"
            divtext += f'<td align=center valign=center><br> </br></td>' + "\n"
            divtext += '</tr><tr>'
            divtext += f'<td align=center valign=center><img src={df_i.loc[index[-1], "img_name_raw"]} width={w} height={h}></td>'
            divtext += f'<td align=center valign=center></td>'
            divtext += '</tr>'
        divtext += '</table>'
        return hv.Div(str(divtext))

    div = hv.DynamicMap(selection_callback, streams=[sel])
    hv.streams.PlotReset(source=quality_scatter,
                         subscribers=[lambda reset: sel.event(index=[])])
    return hv.Layout(quality_scatter + div).cols(1), sel
import dash_html_components as html

import numpy as np
import holoviews as hv
from holoviews import opts, streams
from holoviews.plotting.plotly.dash import to_dash

# Declare two sets of points generated from multivariate distribution
np.random.seed(0)  # no-display
points = hv.Points(
    np.random.multivariate_normal((0, 0), [[1, 0.1], [0.1, 1]], (1000, )))
points2 = hv.Points(
    np.random.multivariate_normal((3, 3), [[1, 0.1], [0.1, 1]], (1000, )))

# Declare two selection streams and set points and points2 as the source of each
sel1 = streams.Selection1D(source=points)
sel2 = streams.Selection1D(source=points2)

# Declare DynamicMaps to show mean y-value of selection as HLine
hline1 = hv.DynamicMap(lambda index: hv.HLine(points['y'][index].mean()
                                              if index else -10),
                       streams=[sel1])
hline2 = hv.DynamicMap(lambda index: hv.HLine(points2['y'][index].mean()
                                              if index else -10),
                       streams=[sel2])

# Combine points and dynamic HLines
layout = (points * points2 * hline1 * hline2).opts(
    opts.Points(height=400, width=400))

# Create App
# -*- coding: utf-8 -*-
import dash
import dash_html_components as html

import numpy as np
import holoviews as hv
from holoviews import streams
from holoviews.plotting.plotly.dash import to_dash

# Declare some points
np.random.seed(0)  # no-display
points = hv.Points(np.random.randn(1000, 2))

# Declare points as source of selection stream
selection = streams.Selection1D(source=points)


# Write function that uses the selection indices to slice points and compute stats
def selected_info(index):
    selected = points.iloc[index]
    if index:
        label = 'Mean x, y: %.3f, %.3f' % tuple(selected.array().mean(axis=0))
    else:
        label = 'No selection'
    return selected.relabel(label).opts(color='red')


# Combine points and DynamicMap
layout = points + hv.DynamicMap(selected_info, streams=[selection])

# Create App
    def crossplot(self, dataframe, x_column, y_column, scale_select_value):
        """
        NAME
        ----
            crossplot.
            
        DESCRIPTION
        -----------
            Plots crossplots using AVO attributes and statistic parameters as axis/legends and a map. 

            The map will show whatever gets selected in the crossplot using the available tools for
            selection. Both plots are made by using Holoviews and bokeh as backend.
            
        ARGUMENTS
        ---------
            dataframe : (Pandas)DataFrame
                Matrix compounded by AVO attributes and statistic parameters.

            x_column : str
                X axis name of the crossplot. The name must coincide with one of the DataFrames's 
                columns. Can be given manually or by Panel's selector. Map's x axis is utmx by 
                default.

            y_column : str
                Y axis name of the crossplot. The name must coincide with one of the DataFrames's 
                columns. Can be given manually or by Panel's selector. Map's y axis is utmy by 
                default.

            scale_select_value : str
                Color bar of the crossplot. The name must coincide with one of the DataFrames's
                columns. Can be given manually or by Panel's selector.
            
        RETURN
        ------
            layout : Holviews element [NdLayout]
                Crossplot and map of the points selected in the crossplot.
        
        FUNCTIONS
        ---------
            selected_info(**kwargs)
                Plots a location map based on the selected points in the crossplot. Empty by
                default.

        """

        # Scale for the crossplot
        levels = np.linspace(dataframe[scale_select_value].min(),
                             dataframe[scale_select_value].max(),
                             100,
                             endpoint=True).tolist()

        # Preparing the data's plot
        data = hv.Points(dataframe, [x_column, y_column],
                         vdims=scale_select_value)
        data.opts(title=f"{x_column} vs {y_column}",
                  color=scale_select_value,
                  color_levels=levels,
                  cmap="fire",
                  colorbar=True)

        # Axis of plot
        x_axis = hv.Curve([(0, dataframe[y_column].min()),
                           (0, dataframe[y_column].max())])
        x_axis.opts(color="black", line_width=0.5)
        y_axis = hv.Curve([(dataframe[x_column].min(), 0),
                           (dataframe[x_column].max(), 0)])
        y_axis.opts(color="black", line_width=0.5)

        # Declare points as source of selection stream
        selection = streams.Selection1D(source=data)

        # Write function that uses the selection indices to slice points and compute stats
        def selected_info(index):
            """
            NAME
            ----
                selected_info.
                
            DESCRIPTION
            -----------
                Plots a location map based on the selected samples in the crossplot. Empty by default.
                
            ARGUMENTS
            ---------
                hc : (Pandas)DataFrame
                    DataFrame made by converting selected samples of the crossplot.
            
            RETURN
            ------
                plot : Holviews element [Scatter]
                        Map of the selected samples in the crossplot.
                
            """

            hc = dataframe.iloc[index]
            plot = hv.Scatter(hc, ["utmx", "utmy"])
            plot.opts(
                color="red",
                size=5,
                fontsize={
                    "title": 16,
                    "labels": 14,
                    "xticks": 7,
                    "yticks": 7
                },
                title=f"Position of the selected traces",
                tools=[
                    HoverTool(tooltips=[(
                        'Trace [I/X]',
                        f"@inline/@crossline"), ('Time [ms]', f"@time_slice")])
                ])

            return plot

        dynamic_map = hv.DynamicMap(selected_info, streams=[selection])

        # Combine points and DynamicMap
        layout = ((data * x_axis * y_axis) +
                  dynamic_map).opts(merge_tools=False)

        return (layout)
    def holoview_plot(self, ):
        """
        """
        import datashader as ds
        from holoviews.operation.datashader import aggregate, shade, datashade, dynspread
        from holoviews.streams import RangeXY

        self.ds_points = self.datashade(
            "Value" if len(self._data.data_dims) > 0 else None)
        self.ds_points = self.ds_points.opts(plot=dict(width=600, height=600))

        # Hover and zoom grid tool.
        self._hover_grid = hv.util.Dynamic(
            aggregate(self._points,
                      aggregator=ds.mean("Value"),
                      width=15,
                      height=15,
                      streams=[RangeXY(source=self.ds_points)]),
            operation=hv.QuadMesh).opts(plot=dict(tools=["hover"]),
                                        style=dict(alpha=0, hover_alpha=0.2))

        # Get the points in tapped rectangle
        self._posxy = DataShaderSelect(source=self._hover_grid,
                                       dataset=self._data.embedding)

        #self._posxy = hv.streams.Tap(source=self._hover_grid)

        def _dss_logger(**kwargs):
            import logging as log
            log.info("Handling event from datashader select: %s", str(kwargs))

        self._posxy.add_subscriber(_dss_logger)

        # Make layout
        self.tap_indicators = hv.DynamicMap(self.tap_points,
                                            kdims=[],
                                            streams=[self._posxy])
        self.selected_table = hv.DynamicMap(self.tap_table,
                                            streams=[self._posxy])

        self.tap_zoom = hv.DynamicMap(
            self.focus_plot, streams=[self._posxy],
            kdims=["Counts"]).opts(norm=dict(framewise=True)).redim.values(
                Counts=self._data.data_dims)

        def _h(Counts, index, fine_index, **kwargs):
            #print index, kwargs
            from holoviews.operation import histogram

            m = {
                Counts: "Value",
                "{}_frequency": "frequency",
            }
            if len(index) > 0:
                d = self._data.embedding.iloc[index]
                if len(fine_index) > 0:
                    d = d.iloc[fine_index]
                #print "Trying", Counts
                label = "{} {} points".format(Counts, len(d))
                r = histogram(
                    hv.Points(d),
                    #self.selected_table,
                    dimension=Counts,
                    dynamic=False).redim(**m)
            else:
                label = "{} {} points".format(Counts,
                                              len(self._data.embedding))
                #print "Alt", Counts
                r = histogram(self._points[Counts],
                              dimension="Value",
                              dynamic=False).redim(Value_frequency="frequency")

            #print(r)
            return r.relabel(label)

        from holoviews import streams
        self.zoom_selection = streams.Selection1D(source=self.tap_zoom)

        self.p = hv.DynamicMap(
            _h,
            kdims=["Counts"],
            streams=[
                self.zoom_selection.rename(index="fine_index"), self._posxy
            ]).redim.values(Counts=self._data.data_dims).opts(norm=dict(
                framewise=True))


        self._layout = self.ds_points * self._hover_grid * self.tap_indicators \
                       + self.selected_table + self.tap_zoom + self.p

        self._layout = self._layout.cols(2).opts(plot={"shared_axes": False})

        return self._layout