Exemple #1
0
def visualize_nodes(labels: list, pca_2d: list, num_of_clusters: int,
                    features: list, albums: list, task_name: str, method: str):
    color_dic = dict()
    for i in range(-1, num_of_clusters + 1):
        color_dic[i] = random_color()

    cls = [color_dic[label] for label in labels]

    TOOLTIPS = [('title', '@title'), ('URL', '@url'), ('Cluster', '@cluster')]

    source = ColumnDataSource(
        data=dict(x=pca_2d[:, 0],
                  y=pca_2d[:, 1],
                  title=[album['title'] for album in albums],
                  url=[album['url'] for album in albums],
                  color=cls,
                  cluster=labels))

    for feature in features:
        TOOLTIPS.append((feature, "@{0}".format(feature)))
        source.add([album[feature] for album in albums], feature)

    p = figure(sizing_mode='stretch_both',
               title=method + " clustering of albums on metrics: " +
               ", ".join(features),
               tooltips=TOOLTIPS,
               output_backend='webgl')

    p.circle('x', 'y', source=source, color='color', fill_alpha=0.2, size=5)
    output_file(get_local_data_path(task_name + ".html"),
                title="PSZ | {0} clustering of Albums".format(method))
    show(p)
def ridgeplot(courses_obj):
    # first format 'courses_obj' into 'probly' DataFrame format
    # courses_obj: [{'course_name': 'Calculus...', ...}, ...]
    grades = [[100*y[2]/y[3] for y in x['assignments']] for x in courses_obj]
    # turn this list of lists into a complete NumPy array
    length = len(sorted(grades, key=len, reverse=True)[0])
    grades = np.array([xi+[None]*(length-len(xi)) for xi in grades], dtype='float')
    columns = [x['course_name'] for x in courses_obj]
    grades = grades.transpose()
    probly = pd.DataFrame(grades, columns=columns)


    cats = list(reversed(probly.keys()))


    palette = [cc.rainbow[i*15] for i in range(17)]

    x = np.linspace(-20,110, 500)

    source = ColumnDataSource(data=dict(x=x))

    p = figure(y_range=cats, plot_width=900, plot_height = 300, x_range=(-5, 120))#, toolbar_location=None)

    for i, cat in enumerate(reversed(cats)):
        adjusted = probly[cat].replace([np.inf, -np.inf], np.nan).dropna(how="all")
        if adjusted.size == 1 or pd.unique(adjusted).size == 1: # this means we can't compute
            continue
        pdf = gaussian_kde(adjusted)
        #p = figure(plot_width=400, plot_height=400)
        #p.line(x, pdf(x))
        y = ridge(cat, pdf(x), scale=2)
        #p.line(x, y, color='black')
        #show(p)
        source.add(y, cat)
        p.patch('x', cat, color=palette[i], alpha=0.6, line_color="black", source=source)

    p.outline_line_color = None
    p.background_fill_color = "#efefef"

    p.tools = [PanTool(), CrosshairTool(), HoverTool(), SaveTool(), BoxZoomTool(), WheelZoomTool(), ResetTool()]

    ticks = list(np.array([np.array([0,3,7])+i*10 for i in range(10)]).flatten()) + [100]
    p.xaxis.ticker = FixedTicker(ticks=ticks)
    p.xaxis.formatter = PrintfTickFormatter(format="%d")
    p.xaxis.axis_label = "Your Grade Distribution"

    p.yaxis.axis_label = "Your Courses"

    p.ygrid.grid_line_color = None
    p.xgrid.grid_line_color = "Grey"
    p.xgrid.ticker = p.xaxis[0].ticker

    p.axis.minor_tick_line_color = None
    p.axis.major_tick_line_color = None
    p.axis.axis_line_color = None

    p.y_range.range_padding = 0.12

    return p
Exemple #3
0
def pnl_chart(df):
    """
    Creates a chart to display P&L

    Parameters
    ----------
    df : DataFrame, with the following columns: Date, Realized, Unrealized, Total

    Returns
    -------
    Figure
    """
    source = ColumnDataSource(df)
    source.add(df.index.map(lambda d: d.strftime('%d-%b-%y')), 'DateStr')

    title = Title(text='Historical Daily P&L',
                  text_font_size='14pt',
                  align='center')

    p = figure(x_axis_type='datetime', sizing_mode='scale_height', title=title)

    p.xaxis.formatter = DatetimeTickFormatter(days=['%d-%b-%y'],
                                              months=['%d-%b-%y'],
                                              years=['%d-%b-%y'])
    p.xaxis.major_label_text_font_size = '10pt'
    p.yaxis.formatter = NumeralTickFormatter(format=',')
    p.yaxis.major_label_text_font_size = '10pt'

    for col, color in zip(['Realized', 'Unrealized', 'Total'], Spectral4):
        p.line(x='Date',
               y=col,
               source=source,
               line_width=2,
               color=color,
               alpha=0.8,
               legend_label=col)

    hover = HoverTool(tooltips=[
        ('Date', '@DateStr'),
        ('Realized', '@Realized{,}'),
        ('Unrealized', '@Unrealized{,}'),
        ('Total', '@Total{,}'),
    ],
                      formatters={
                          'Realized': 'printf',
                          'Unrealized': 'printf',
                          'Total': 'printf'
                      },
                      mode='vline',
                      renderers=[p.renderers[-1]])

    p.add_tools(hover)
    p.legend.location = "top_left"
    p.legend.click_policy = "hide"

    return p
Exemple #4
0
def _to_cds(data, unstack=None):
    """"""
    source_dict = {}

    if hasattr(data, "data_vars"):
        for v in data.data_vars:
            source_dict.update(_dict_from_da(data[v], unstack))
    else:
        source_dict.update(_dict_from_da(data, unstack))

    source = ColumnDataSource(source_dict)

    for c in data.coords:
        if c not in data.dims and data[c].ndim == 1:
            source.add(data[c].values, c)

    return source
Exemple #5
0
class PlotterBokeh(Plotter):
    def __init__(self, ds, x, y, z=None, **kwargs):
        """
        """
        # bokeh custom options / defaults
        kwargs['return_fig'] = kwargs.pop('return_fig', False)
        self._interactive = kwargs.pop('interactive', False)

        super().__init__(ds, x, y, z, **kwargs, backend='BOKEH')

    def prepare_axes(self):
        """Make the bokeh plot figure and set options.
        """
        from bokeh.plotting import figure

        if self.add_to_axes is not None:
            self._plot = self.add_to_axes

        else:
            # Currently axes scale type must be set at figure creation?
            self._plot = figure(
                # convert figsize to roughly matplotlib dimensions
                width=int(self.figsize[0] * 80 +
                          (100 if self._use_legend else 0) +
                          (20 if self._ytitle else 0) +
                          (20 if not self.yticklabels_hide else 0)),
                height=int(self.figsize[1] * 80 + (20 if self.title else 0) +
                           (20 if self._xtitle else 0) +
                           (20 if not self.xticklabels_hide else 0)),
                x_axis_type=('log' if self.xlog else 'linear'),
                y_axis_type=('log' if self.ylog else 'linear'),
                y_axis_location=('right' if self.ytitle_right else 'left'),
                title=self.title,
                toolbar_location="above",
                toolbar_sticky=False,
                active_scroll="wheel_zoom",
            )

    def set_axes_labels(self):
        """Set the labels on the axes.
        """
        if self._xtitle:
            self._plot.xaxis.axis_label = self._xtitle
        if self._ytitle:
            self._plot.yaxis.axis_label = self._ytitle

    def set_axes_range(self):
        """Set the plot ranges of the axes, and the panning limits.
        """
        from bokeh.models import DataRange1d

        self.calc_data_range()

        # plt_x_centre = (self._data_xmax + self._data_xmin) / 2
        # plt_x_range = self._data_xmax - self._data_xmin
        # xbounds = (plt_x_centre - plt_x_range, plt_x_centre + plt_x_range)
        xbounds = None
        self._plot.x_range = (DataRange1d(
            start=self._xlims[0], end=self._xlims[1], bounds=xbounds)
                              if self._xlims else DataRange1d(bounds=xbounds))

        # plt_y_centre = (self._data_ymax + self._data_ymin) / 2
        # plt_y_range = abs(self._data_ymax - self._data_ymin)
        # ybounds = (plt_y_centre - plt_y_range, plt_y_centre + plt_y_range)
        ybounds = None
        self._plot.y_range = (DataRange1d(
            start=self._ylims[0], end=self._ylims[1], bounds=ybounds)
                              if self._ylims else DataRange1d(bounds=ybounds))

    def set_spans(self):
        """Set custom horizontal and verical line spans.
        """
        from bokeh.models import Span

        span_opts = {
            'level': 'glyph',
            'line_dash': 'dashed',
            'line_color': (127, 127, 127),
            'line_width': self.span_width,
        }

        if self.hlines:
            for hl in self.hlines:
                self._plot.add_layout(
                    Span(location=hl, dimension='width', **span_opts))
        if self.vlines:
            for vl in self.vlines:
                self._plot.add_layout(
                    Span(location=vl, dimension='height', **span_opts))

    def set_gridlines(self):
        """Set whether to use gridlines or not.
        """
        if not self.gridlines:
            self._plot.xgrid.visible = False
            self._plot.ygrid.visible = False
        else:
            self._plot.xgrid.grid_line_dash = self.gridline_style
            self._plot.ygrid.grid_line_dash = self.gridline_style

    def set_tick_marks(self):
        """Set custom locations for the tick marks.
        """
        from bokeh.models import FixedTicker

        if self.xticks:
            self._plot.xaxis[0].ticker = FixedTicker(ticks=self.xticks)
        if self.yticks:
            self._plot.yaxis[0].ticker = FixedTicker(ticks=self.yticks)

        if self.xticklabels_hide:
            self._plot.xaxis.major_label_text_font_size = '0pt'
        if self.yticklabels_hide:
            self._plot.yaxis.major_label_text_font_size = '0pt'

    def set_sources_heatmap(self):
        from bokeh.plotting import ColumnDataSource

        # initialize empty source
        if not hasattr(self, '_source'):
            self._source = ColumnDataSource(data=dict())

        # remove mask from data -> not necessary soon? / convert to nan?
        var = np.ma.getdata(self._heatmap_var)

        self._source.add([var], 'image')
        self._source.add([self._data_xmin], 'x')
        self._source.add([self._data_ymin], 'y')
        self._source.add([self._data_xmax - self._data_xmin], 'dw')
        self._source.add([self._data_ymax - self._data_ymin], 'dh')

    def set_sources(self):
        """Set the source dictionaries to be used by the plotter functions.
        This is seperate to allow interactive updates of the data only.
        """
        from bokeh.plotting import ColumnDataSource

        # check if heatmap
        if hasattr(self, '_heatmap_var'):
            return self.set_sources_heatmap()

        # 'copy' the zlabels iterator into src_zlbs
        self._zlbls, src_zlbs = itertools.tee(self._zlbls)

        # Initialise with empty dicts
        if not hasattr(self, "_sources"):
            self._sources = [
                ColumnDataSource(dict()) for _ in range(len(self._z_vals))
            ]

        # range through all data and update the sources
        for i, (zlabel, data) in enumerate(zip(src_zlbs, self._gen_xy())):
            self._sources[i].add(data['x'], 'x')
            self._sources[i].add(data['y'], 'y')
            self._sources[i].add([zlabel] * len(data['x']), 'z_coo')

            # check for color for scatter plot
            if 'c' in data:
                self._sources[i].add(data['c'], 'c')

            # check if should set y_err as well
            if 'ye' in data:
                y_err_p = data['y'] + data['ye']
                y_err_m = data['y'] - data['ye']
                self._sources[i].add(list(zip(data['x'], data['x'])),
                                     'y_err_xs')
                self._sources[i].add(list(zip(y_err_p, y_err_m)), 'y_err_ys')

            # check if should set x_err as well
            if 'xe' in data:
                x_err_p = data['x'] + data['xe']
                x_err_m = data['x'] - data['xe']
                self._sources[i].add(list(zip(data['y'], data['y'])),
                                     'x_err_ys')
                self._sources[i].add(list(zip(x_err_p, x_err_m)), 'x_err_xs')

    def plot_legend(self, legend_items=None):
        """Add a legend to the plot.
        """
        if self._use_legend:
            from bokeh.models import Legend

            loc = {'best': 'top_left'}.get(self.legend_loc, self.legend_loc)
            where = {None: 'right'}.get(self.legend_where, self.legend_where)

            # might be manually specified, e.g. from multiplot
            if legend_items is None:
                legend_items = self._lgnd_items

            lg = Legend(items=legend_items)
            lg.location = loc
            lg.click_policy = 'hide'
            self._plot.add_layout(lg, where)

            # Don't repeatedly redraw legend
            self._use_legend = False

    def set_mappable(self):
        from bokeh.models import LogColorMapper, LinearColorMapper
        import matplotlib as plt

        mappr_fn = (LogColorMapper if self.colormap_log else LinearColorMapper)
        bokehpalette = [plt.colors.rgb2hex(m) for m in self.cmap(range(256))]

        self.mappable = mappr_fn(palette=bokehpalette,
                                 low=self._zmin,
                                 high=self._zmax)

    def plot_colorbar(self):
        if self._use_colorbar:

            where = {None: 'right'}.get(self.legend_where, self.legend_where)

            from bokeh.models import ColorBar, LogTicker, BasicTicker
            ticker = LogTicker if self.colormap_log else BasicTicker
            color_bar = ColorBar(color_mapper=self.mappable,
                                 location=(0, 0),
                                 ticker=ticker(desired_num_ticks=6),
                                 title=self._ctitle)
            self._plot.add_layout(color_bar, where)

    def set_tools(self):
        """Set which tools appear for the plot.
        """
        from bokeh.models import HoverTool

        self._plot.add_tools(
            HoverTool(tooltips=[("({}, {})".format(
                self.x_coo,
                self.y_coo if isinstance(self.y_coo, str) else None),
                                 "(@x, @y)"), (self.z_coo, "@z_coo")]))

    def update(self):
        from bokeh.io import push_notebook
        self.set_sources()
        push_notebook()

    def show(self, **kwargs):
        """Show the produced figure.
        """
        if self.return_fig:
            return self._plot
        bshow(self._plot, **kwargs)
        return self

    def prepare_plot(self):
        self.prepare_axes()
        self.set_axes_labels()
        self.set_axes_range()
        self.set_spans()
        self.set_gridlines()
        self.set_tick_marks()
        self.set_sources()
Exemple #6
0
from bokeh.plotting import ColumnDataSource, figure, gridplot, output_file, show
from bokeh.sampledata.autompg import autompg

output_file("panning.html")

# Load some Automobile data into a data source. Interesting columns are:
# "yr" - Year manufactured
# "mpg" - miles per gallon
# "displ" - engine displacement
# "hp" - engine horsepower
# "cyl" - number of cylinders
source = ColumnDataSource(autompg.to_dict("list"))
source.add(autompg["yr"], name="yr")

# Let's set up some plot options in a dict that we can re-use on multiple plots
plot_config = dict(plot_width=300,
                   plot_height=300,
                   tools="pan,wheel_zoom,box_zoom,select")

# First let's plot the "yr" vs "mpg" using the plot config above
# Note that we are supplying our our data source to the renderer explicitly
p1 = figure(title="MPG by Year", **plot_config)
p1.circle("yr", "mpg", color="blue", source=source)

# EXERCISE: make another figure p2 with circle renderer, for "hp" vs "displ" with
# color "green". This renderer should use the same data source as the renderer
# above, that is what will cause the plots selections to be linked
p2 = figure(title="HP vs. Displacement", **plot_config)
p2.circle("hp", "displ", color="green", source=source)

# EXERCISE: and another figure p3 with circle renderer for "mpg" vs "displ",
Exemple #7
0
from bokeh.plotting import ColumnDataSource, figure, gridplot, output_file, show
from bokeh.sampledata.autompg import autompg

output_file("brushing.html")

# Load some Automobile data into a data source. Interesting columns are:
# "yr" - Year manufactured
# "mpg" - miles per gallon
# "displ" - engine displacement
# "hp" - engine horsepower
# "cyl" - number of cylinders
source = ColumnDataSource(autompg.to_dict("list"))
source.add(autompg["yr"], name="yr")

# define some tools to add
TOOLS = "pan,wheel_zoom,box_zoom,box_select,lasso_select"# Let's set up some plot options in a dict that we can re-use on multiple plots

# Let's set up some plot options in a dict that we can re-use on multiple plots
plot_config = dict(plot_width=300, plot_height=300, tools=TOOLS)

# First let's plot the "yr" vs "mpg" using the plot config above
# Note that we are supplying our our data source to the renderer explicitly
p1 = figure(title="MPG by Year", **plot_config)
p1.circle("yr", "mpg", color="blue", source=source)

# EXERCISE: make another figure p2 with circle renderer, for "hp" vs "displ" with
# color "green". This renderer should use the same data source as the renderer
# above, that is what will cause the plots selections to be linked
p2 = figure(title="HP vs. Displacement", **plot_config)
p2.circle("hp", "displ", color="green", source=source)
    def _plot_get_source(self, conf_list, runs, X, inc_list, hp_names):
        """
        Create ColumnDataSource with all the necessary data
        Contains for each configuration evaluated on any run:

          - all parameters and values
          - origin (if conflicting, origin from best run counts)
          - type (default, incumbent or candidate)
          - # of runs
          - size
          - color

        Parameters
        ----------
        conf_list: list[Configuration]
            configurations
        runs: list[int]
            runs per configuration (same order as conf_list)
        X: np.array
            configuration-parameters as 2-dimensional array
        inc_list: list[Configuration]
            incumbents for this conf-run
        hp_names: list[str]
            names of hyperparameters

        Returns
        -------
        source: ColumnDataSource
            source with attributes as requested
        """
        # Remove all configurations without any runs
        keep = [i for i in range(len(runs)) if runs[i] > 0]
        runs = np.array(runs)[keep]
        conf_list = np.array(conf_list)[keep]
        X = X[keep]

        source = ColumnDataSource(data=dict(x=X[:, 0], y=X[:, 1]))
        for k in hp_names:  # Add parameters for each config
            source.add([c[k] if c[k] else "None" for c in conf_list],
                       escape_parameter_name(k))
        default = conf_list[0].configuration_space.get_default_configuration()
        conf_types = [
            "Default" if c == default else "Final Incumbent" if c
            == inc_list[-1] else "Incumbent" if c in inc_list else "Candidate"
            for c in conf_list
        ]
        # We group "Local Search" and "Random Search (sorted)" both into local
        origins = [self._get_config_origin(c) for c in conf_list]
        source.add(conf_types, 'type')
        source.add(origins, 'origin')
        sizes = self._get_size(runs)
        sizes = [
            s * 3 if conf_types[idx] == "Default" else s
            for idx, s in enumerate(sizes)
        ]
        source.add(sizes, 'size')
        source.add(self._get_color(source.data['type']), 'color')
        source.add(runs, 'runs')
        # To enforce zorder, we categorize all entries according to their size
        # Since we plot all different zorder-levels sequentially, we use a
        # manually defined level of influence
        num_bins = 20  # How fine-grained the size-ordering should be
        min_size, max_size = min(source.data['size']), max(source.data['size'])
        step_size = (max_size - min_size) / num_bins
        if step_size == 0:
            step_size = 1
        zorder = [
            str(int((s - min_size) / step_size)) for s in source.data['size']
        ]
        source.add(zorder, 'zorder')  # string, so we can apply group filter

        return source
    def plot_interactive_footprint(self):
        """Use bokeh to create an interactive algorithm footprint with zoom and
        hover tooltips. Should avoid problems with overplotting (since we can
        zoom) and provide better information about instances."""
        features = np.array(self.features_2d)
        instances = self.insts
        runhistory = self.rh
        algo = {v: k for k, v in self.algo_name.items()}
        incumbent = algo['incumbent']
        default = algo['default']
        source = ColumnDataSource(data=dict(x=features[:, 0], y=features[:,
                                                                         1]))
        # Add all necessary information for incumbent and default
        source.add(instances, 'instance_name')
        instance_set = [
            'train' if i in self.train_feats.keys() else 'test'
            for i in instances
        ]
        source.add(instance_set, 'instance_set')  # train or test
        for config, name in [(incumbent, 'incumbent'), (default, 'default')]:
            cost = get_cost_dict_for_config(runhistory, config)
            source.add([cost[i] for i in instances], '{}_cost'.format(name))
            # TODO should be in function
            good, bad = self._get_good_bad(config)
            color = [
                1 if idx in good else 0 for idx, i in enumerate(instances)
            ]
            # TODO end
            color = ['blue' if c else 'red' for c in color]
            self.logger.debug("%s colors: %s", name, str(color))
            source.add(color, '{}_color'.format(name))
        source.add(source.data['default_color'], 'color')

        # Define what appears in tooltips
        hover = HoverTool(tooltips=[
            ('instance name', '@instance_name'),
            ('def cost', '@default_cost'),
            ('inc_cost', '@incumbent_cost'),
            ('set', '@instance_set'),
        ])

        # Add radio-button
        def_inc_callback = CustomJS(args=dict(source=source),
                                    code="""
            var data = source.data;
            if (cb_obj.active == 0) {
                data['color'] = data['default_color'];
            } else {
                data['color'] = data['incumbent_color'];
            }
            source.change.emit();
            """)

        def_inc_radio_button = RadioButtonGroup(
            labels=["default", "incumbent"],
            active=0,
            callback=def_inc_callback)

        # Plot
        x_range = DataRange1d(bounds='auto',
                              start=min(features[:, 0]) - 1,
                              end=max(features[:, 0]) + 1)
        y_range = DataRange1d(bounds='auto',
                              start=min(features[:, 1]) - 1,
                              end=max(features[:, 1]) + 1)
        p = figure(
            plot_height=500,
            plot_width=600,
            tools=[hover, 'save', 'wheel_zoom', 'box_zoom', 'pan', 'reset'],
            active_drag='box_zoom',
            x_range=x_range,
            y_range=y_range)
        # Scatter train and test individually to toggle them
        train_view = CDSView(
            source=source,
            filters=[GroupFilter(column_name='instance_set', group='train')])
        test_view = CDSView(
            source=source,
            filters=[GroupFilter(column_name='instance_set', group='test')])
        train = p.scatter(x='x',
                          y='y',
                          source=source,
                          view=train_view,
                          color='color')
        test = p.scatter(x='x',
                         y='y',
                         source=source,
                         view=test_view,
                         color='color')
        p.xaxis.axis_label, p.yaxis.axis_label = 'principal component 1', 'principal component 2'
        p.xaxis.axis_label_text_font_size = p.yaxis.axis_label_text_font_size = "15pt"

        train_test_callback = CustomJS(args=dict(source=source,
                                                 train_view=train,
                                                 test_view=test),
                                       code="""
            var data = source.data;
            if (cb_obj.active == 0) {
                train_view.visible = true;
                test_view.visible = true;
            } else if (cb_obj.active == 1) {
                train_view.visible = true;
                test_view.visible = false;
            } else {
                train_view.visible = false;
                test_view.visible = true;
            }
            """)
        train_test_radio_button = RadioButtonGroup(
            labels=["all", "train", "test"],
            active=0,
            callback=train_test_callback)

        # Export and return
        if self.output_dir:
            path = os.path.join(self.output_dir,
                                "content/images/algorithm_footprint.png")
            export_bokeh(p, path, self.logger)

        layout = column(
            p,
            row(widgetbox(def_inc_radio_button),
                widgetbox(train_test_radio_button)))
        return layout
Exemple #10
0
from bokeh.models import HoverTool
from bokeh.models.widgets import DateRangeSlider

data = pd.read_csv('Lekagul Sensor Data.csv')
data_car_id = data['car-id'].as_matrix()
data.columns
plot_width = 1100
plot_height = 500
width = 1

hover = HoverTool()
hover.tooltips = [('index', '$index')]
all_gate_names = np.unique(data['gate-name'].as_matrix())
all_car_types = np.unique(data['car-type'].as_matrix())
source = ColumnDataSource()
source.add(all_gate_names, name='Gate Names')
legend_var = [
    '2 axle car (or motorcycle)', '2 axle Truck', 'Ranger', '3 axle Truck',
    '4 axle (and above) Truck', '2 axle Bus', '3 axle Bus'
]

start_y = '2016'
start_m = '02'
start_d = '10'
end_y = '2016'
end_m = '04'
end_d = '20'
start_mask = '2016-02-10'
end_mask = '2016-04-20'

mask = (data['Timestamp'] >= start_mask) & (data['Timestamp'] <= end_mask)
Exemple #11
0
class PlotterBokeh(Plotter):
    def __init__(self, ds, x, y, z=None, **kwargs):
        """
        """
        # bokeh custom options / defaults
        kwargs['return_fig'] = kwargs.pop('return_fig', False)
        self._interactive = kwargs.pop('interactive', False)

        super().__init__(ds, x, y, z, **kwargs, backend='BOKEH')

    def prepare_axes(self):
        """Make the bokeh plot figure and set options.
        """
        from bokeh.plotting import figure

        if self.add_to_axes is not None:
            self._plot = self.add_to_axes

        else:
            # Currently axes scale type must be set at figure creation?
            self._plot = figure(
                # convert figsize to roughly matplotlib dimensions
                width=int(self.figsize[0] * 80 +
                          (100 if self._use_legend else 0) +
                          (20 if self._ytitle else 0) +
                          (20 if not self.yticklabels_hide else 0)),
                height=int(self.figsize[1] * 80 +
                           (20 if self.title else 0) +
                           (20 if self._xtitle else 0) +
                           (20 if not self.xticklabels_hide else 0)),
                x_axis_type=('log' if self.xlog else 'linear'),
                y_axis_type=('log' if self.ylog else 'linear'),
                y_axis_location=('right' if self.ytitle_right else 'left'),
                title=self.title,
                toolbar_location="above",
                toolbar_sticky=False,
                active_scroll="wheel_zoom",
            )

    def set_axes_labels(self):
        """Set the labels on the axes.
        """
        if self._xtitle:
            self._plot.xaxis.axis_label = self._xtitle
        if self._ytitle:
            self._plot.yaxis.axis_label = self._ytitle

    def set_axes_range(self):
        """Set the plot ranges of the axes, and the panning limits.
        """
        from bokeh.models import DataRange1d

        self.calc_data_range()

        # plt_x_centre = (self._data_xmax + self._data_xmin) / 2
        # plt_x_range = self._data_xmax - self._data_xmin
        # xbounds = (plt_x_centre - plt_x_range, plt_x_centre + plt_x_range)
        xbounds = None
        self._plot.x_range = (DataRange1d(start=self._xlims[0],
                                          end=self._xlims[1],
                                          bounds=xbounds) if self._xlims else
                              DataRange1d(bounds=xbounds))

        # plt_y_centre = (self._data_ymax + self._data_ymin) / 2
        # plt_y_range = abs(self._data_ymax - self._data_ymin)
        # ybounds = (plt_y_centre - plt_y_range, plt_y_centre + plt_y_range)
        ybounds = None
        self._plot.y_range = (DataRange1d(start=self._ylims[0],
                                          end=self._ylims[1],
                                          bounds=ybounds) if self._ylims else
                              DataRange1d(bounds=ybounds))

    def set_spans(self):
        """Set custom horizontal and verical line spans.
        """
        from bokeh.models import Span

        span_opts = {
            'level': 'glyph',
            'line_dash': 'dashed',
            'line_color': (127, 127, 127),
            'line_width': self.span_width,
        }

        if self.hlines:
            for hl in self.hlines:
                self._plot.add_layout(Span(
                    location=hl, dimension='width', **span_opts))
        if self.vlines:
            for vl in self.vlines:
                self._plot.add_layout(Span(
                    location=vl, dimension='height', **span_opts))

    def set_gridlines(self):
        """Set whether to use gridlines or not.
        """
        if not self.gridlines:
            self._plot.xgrid.visible = False
            self._plot.ygrid.visible = False
        else:
            self._plot.xgrid.grid_line_dash = self.gridline_style
            self._plot.ygrid.grid_line_dash = self.gridline_style

    def set_tick_marks(self):
        """Set custom locations for the tick marks.
        """
        from bokeh.models import FixedTicker

        if self.xticks:
            self._plot.xaxis[0].ticker = FixedTicker(ticks=self.xticks)
        if self.yticks:
            self._plot.yaxis[0].ticker = FixedTicker(ticks=self.yticks)

        if self.xticklabels_hide:
            self._plot.xaxis.major_label_text_font_size = '0pt'
        if self.yticklabels_hide:
            self._plot.yaxis.major_label_text_font_size = '0pt'

    def set_sources_heatmap(self):
        from bokeh.plotting import ColumnDataSource

        # initialize empty source
        if not hasattr(self, '_source'):
            self._source = ColumnDataSource(data=dict())

        # remove mask from data -> not necessary soon? / convert to nan?
        var = np.ma.getdata(self._heatmap_var)

        self._source.add([var], 'image')
        self._source.add([self._data_xmin], 'x')
        self._source.add([self._data_ymin], 'y')
        self._source.add([self._data_xmax - self._data_xmin], 'dw')
        self._source.add([self._data_ymax - self._data_ymin], 'dh')

    def set_sources(self):
        """Set the source dictionaries to be used by the plotter functions.
        This is seperate to allow interactive updates of the data only.
        """
        from bokeh.plotting import ColumnDataSource

        # check if heatmap
        if hasattr(self, '_heatmap_var'):
            return self.set_sources_heatmap()

        # 'copy' the zlabels iterator into src_zlbs
        self._zlbls, src_zlbs = itertools.tee(self._zlbls)

        # Initialise with empty dicts
        if not hasattr(self, "_sources"):
            self._sources = [ColumnDataSource(dict())
                             for _ in range(len(self._z_vals))]

        # range through all data and update the sources
        for i, (zlabel, data) in enumerate(zip(src_zlbs, self._gen_xy())):
            self._sources[i].add(data['x'], 'x')
            self._sources[i].add(data['y'], 'y')
            self._sources[i].add([zlabel] * len(data['x']), 'z_coo')

            # check for color for scatter plot
            if 'c' in data:
                self._sources[i].add(data['c'], 'c')

            # check if should set y_err as well
            if 'ye' in data:
                y_err_p = data['y'] + data['ye']
                y_err_m = data['y'] - data['ye']
                self._sources[i].add(
                    list(zip(data['x'], data['x'])), 'y_err_xs')
                self._sources[i].add(list(zip(y_err_p, y_err_m)), 'y_err_ys')

            # check if should set x_err as well
            if 'xe' in data:
                x_err_p = data['x'] + data['xe']
                x_err_m = data['x'] - data['xe']
                self._sources[i].add(
                    list(zip(data['y'], data['y'])), 'x_err_ys')
                self._sources[i].add(list(zip(x_err_p, x_err_m)), 'x_err_xs')

    def plot_legend(self, legend_items=None):
        """Add a legend to the plot.
        """
        if self._use_legend:
            from bokeh.models import Legend

            loc = {'best': 'top_left'}.get(self.legend_loc, self.legend_loc)
            where = {None: 'right'}.get(self.legend_where, self.legend_where)

            # might be manually specified, e.g. from multiplot
            if legend_items is None:
                legend_items = self._lgnd_items

            lg = Legend(items=legend_items)
            lg.location = loc
            lg.click_policy = 'hide'
            self._plot.add_layout(lg, where)

            # Don't repeatedly redraw legend
            self._use_legend = False

    def set_mappable(self):
        from bokeh.models import LogColorMapper, LinearColorMapper
        import matplotlib as plt

        mappr_fn = (LogColorMapper if self.colormap_log else LinearColorMapper)
        bokehpalette = [plt.colors.rgb2hex(m) for m in self.cmap(range(256))]

        self.mappable = mappr_fn(palette=bokehpalette,
                                 low=self._zmin, high=self._zmax)

    def plot_colorbar(self):
        if self._use_colorbar:

            where = {None: 'right'}.get(self.legend_where, self.legend_where)

            from bokeh.models import ColorBar, LogTicker, BasicTicker
            ticker = LogTicker if self.colormap_log else BasicTicker
            color_bar = ColorBar(color_mapper=self.mappable, location=(0, 0),
                                 ticker=ticker(desired_num_ticks=6),
                                 title=self._ctitle)
            self._plot.add_layout(color_bar, where)

    def set_tools(self):
        """Set which tools appear for the plot.
        """
        from bokeh.models import HoverTool

        self._plot.add_tools(HoverTool(tooltips=[
            ("({}, {})".format(self.x_coo, self.y_coo
                               if isinstance(self.y_coo, str) else None),
             "(@x, @y)"), (self.z_coo, "@z_coo")]))

    def update(self):
        from bokeh.io import push_notebook
        self.set_sources()
        push_notebook()

    def show(self, **kwargs):
        """Show the produced figure.
        """
        if self.return_fig:
            return self._plot
        bshow(self._plot, **kwargs)
        return self

    def prepare_plot(self):
        self.prepare_axes()
        self.set_axes_labels()
        self.set_axes_range()
        self.set_spans()
        self.set_gridlines()
        self.set_tick_marks()
        self.set_sources()
Exemple #12
0
def _prepare_data(connections, stations, lines, data, radius_feature,
                  color_feature, features):
    """
    Prepares data for plotting, creates objects necessary for bokeh.

    Parameters:
    -----------
    connections, stations, lines - data from metro class
    data : pd.DataFrame()
        data prepared by metro class
    radius_feature : str
        feature name to use as radius scaling
    color_feature : str
        feature name to use as color for nodes
    features : list of strings
        list of column names to show on graph

    Returns:
    -------
    source : ColumnDataSource with data
    TOOLTIPS : Tooltips for plot
    graph : networkx graph
    locations : dictionary of stations and normalized coordinates
    """
    # create graph
    stations['node_name'] = stations['name'] + '_' + stations['line'].astype(
        str)
    connections['time'] = 1
    graph = nx.Graph()

    for connection_id, connection in connections.iterrows():
        ind1 = connection['station1'] - 1
        ind2 = connection['station2'] - 1
        station1_name = stations.iloc[ind1]['node_name']
        station2_name = stations.iloc[ind2]['node_name']
        graph.add_edge(station1_name, station2_name, time=connection['time'])

    normed = stations[['longitude', 'latitude']]
    normed = normed - normed.min()
    normed = normed / normed.max()
    locations = dict(
        zip(stations['node_name'], normed[['longitude', 'latitude']].values))

    x = []
    y = []
    name = []
    radius = []
    fill_color = []
    line_l = []
    d = {i: [] for i in features}

    for node in graph.nodes():
        # main values
        x.append(locations[node][0])
        y.append(locations[node][1])
        name.append(node.split('_')[0])
        radius.append(
            np.clip(
                .01 * data.loc[(data['display_name'] == node.split('_')[0]) &
                               (data['line'] == int(node.split('_')[1])),
                               radius_feature].values[0], 0.003, 1))
        colour = _pseudocolor(
            data.loc[(data['display_name'] == node.split('_')[0]) &
                     (data['line'] == int(node.split('_')[1])),
                     color_feature].values[0])
        fill_color.append(_rgb2hex(tuple([int(np.round(i)) for i in colour])))
        line_l.append(lines.loc[lines.line == int(node.split('_')[1]),
                                'name'].values[0])

        # user defined values
        for k in d.keys():
            d[k].append(
                str(
                    np.round(
                        data.loc[(data['display_name'] == node.split('_')[0]) &
                                 (data['line'] == int(node.split('_')[1])),
                                 'total_traffic'].values[0], 2)))

    source = ColumnDataSource(data=dict(x=x,
                                        y=y,
                                        radius=radius,
                                        fill_color=fill_color,
                                        name=name,
                                        line_l=line_l))
    for k, v in d.items():
        source.add(v, k)

    TOOLTIPS = []
    for i in features:
        TOOLTIPS.append((i, f'@{i}'))

    return source, TOOLTIPS, graph, locations
Exemple #13
0
def stack_lines(datas,  index_to_string, ylabel = "MW"):
    keys = sorted(datas.keys())
    nb_max_values = max([ len(datas[key]) for key in keys])
    indices = range(nb_max_values)
    #palette= brewer["Spectral"][nb_max_values]
    palette = bokeh.palettes.viridis(len(keys))
    colors = {key : palette[i] for i,key in enumerate(keys)}

    xrange = [index_to_string(i) for i in range(nb_max_values+1)]
    lines = {}

    columns = {}
    for key in keys :
        columns[key]  = [ datas[key][i] for i in indices ]

    ds = ColumnDataSource(columns)
    ds.add([index_to_string(i) for i in range(nb_max_values)], "left")
    ds.add([index_to_string(i+1) for i in range(nb_max_values)], "right")




    p=figure(x_range = xrange,
                 height = defaults.height,
                 width = defaults.width
             )


    #print(ds.data)
    partial_sum = [ 0. for i in range(nb_max_values)]
    legend_items={}
    for key in keys:
        ds.add( partial_sum , "bottom"+str(key))
        ds.add([ partial_sum[i] + datas[key][i] for i in range(nb_max_values)], "top"+str(key))


        quad = p.quad(
                top = "top"+str(key) ,
                bottom = "bottom"+str(key),
                left = "left",
                right = "right",
                color = colors[key],
                source = ds,
                fill_alpha = 0.7,
                hover_fill_alpha = 0.99,
                hover_fill_color=colors[key],
                hover_line_color=colors[key],
                )
        legend_items[key] = [quad]
        partial_sum = ds.data["top"+str(key)]


    legend = Legend(items=[
            (key, legend_items[key])
            for key in legend_items.keys()
], location=(0, 0), orientation="horizontal")
    p.add_layout(legend, "below")

    p.yaxis.axis_label = ylabel

    #if there is two many lines, we do not put the hover tool
    if len(keys) > 10:
        return p

    hover = HoverTool(
        tooltips=
       [("time", "@left")]
        + [ (key, "@"+key+ " "+ylabel) for key in keys]
        , attachment="horizontal"
        , show_arrow=True


    )
    p.add_tools(hover)



    return p
Exemple #14
0
def plot_lines(datas_, index_to_string, ylabel = "MW"):
    datas = { str(key).replace(" ", "_") : value for  key, value in  datas_.items()}
    keys = sorted(datas.keys())
    nb_max_values = max([ len(datas[key]) for key in  keys])
    indices = range(nb_max_values)

    palette = bokeh.palettes.viridis(len(keys))
    colors = {key : palette[i] for i,key in enumerate(keys)}

    xrange = [index_to_string(i) for i in range(nb_max_values+1)]


    columns = {}
    for key in keys :
        columns[key]  = [ datas[key][i] for i in indices ]




    lines = {}
    lines["time"] = []
    for i in indices:
        lines["time"]+= [index_to_string(i), index_to_string(i+1)]
    for key in keys:
        lines[key] = []
        for i in indices :
            v = datas[key][i]
            lines[key] += [v, v]

    ds = ColumnDataSource(lines)

    #print(xrange)

    p=figure(x_range = xrange
                 , height = defaults.height,
                 width = defaults.width
             )


    legend_items={}
    lines = []
    for key in keys:
        line = p.line( "time", key,
                color = colors[key],
                source = ds,
                line_width = 4,
                alpha = 0.7
                )
        legend_items[key] = [line]
        lines += [line]


    legend = Legend(
            items=[ (key, legend_items[key])
                    for key in sorted(legend_items.keys()) ]
            , location=(0, 0)
            , orientation="horizontal"
            )
    p.add_layout(legend, "below")

    p.yaxis.axis_label = ylabel

    #if there is two many lines, we do not put the hover tool
    if len(keys) > 20:
        return p


    columns = {}
    for key in keys :
        columns[key]  = [ datas[key][i] for i in indices ]


    hover_ds = ColumnDataSource(columns)
    hover_ds.add([index_to_string(i) for i in range(nb_max_values)], "time")
    hover_ds.add([index_to_string(i) for i in range(nb_max_values)], "left")
    hover_ds.add([index_to_string(i+1) for i in range(nb_max_values)], "right")

    max_val = -math.inf
    min_val = math.inf
    for key in keys :
        for i in indices :
            v = datas[key][i]
            if math.isfinite(v):
                max_val = max(max_val, v)
                min_val = min(min_val, v)

    hover_ds.add([max_val for i in range(nb_max_values)], "top")
    hover_ds.add([min_val for i in range(nb_max_values)], "bottom")



    hover_glyphs = []
    #for key in keys:
    glyph = p.quad(top="top", bottom="bottom",
                   left="left", right="right",
                   alpha = 0,
                   source = hover_ds,
                   color = "white",
                   hover_alpha=0.1,
                   hover_color = "black")
    hover_glyphs += [glyph]

    hover = HoverTool(
            tooltips = [("time", "@time")]
                          + [ (key, "@"+key + " " + ylabel ) for key in keys ]
           , attachment="horizontal"
           #, mode = "vline"
           , renderers = hover_glyphs
    )
    p.add_tools(hover)





    return p
Exemple #15
0
def commonPlot(r, ldict, y1lim, dset, height=None, width=None, y2=None):
    """
    """
    tools = "pan, wheel_zoom, box_zoom, crosshair, reset, save"

    title = ldict['title']
    xlabel = ldict['xlabel']
    y1label = ldict['y1label']

    p = figure(title=title,
               x_axis_type='datetime',
               x_axis_label=xlabel,
               y_axis_label=y1label,
               tools=tools,
               output_backend="webgl")

    if height is not None:
        p.plot_height = height

    if width is not None:
        p.plot_width = width

    if y2 is not None:
        p.extra_y_ranges = y2
        p.add_layout(
            LinearAxis(y_range_name="y2", axis_label=ldict['y2label']),
            'right')

        # Annoyingly, the main y-axis still autoscales if there is a
        #   second y-axis. Setting these means that the axis WON'T
        #   autoscale until they're set back to None
        p.y_range = DataRange1d(start=y1lim[0], end=y1lim[1])

    p.x_range.follow = "end"
    p.x_range.range_padding = 0.1
    p.x_range.range_padding_units = 'percent'

    # Hack! But it works. Need to do this *before* you create cds below!
    #   Includes a special flag (first=True) to pad the beginning so all
    #   the columns in the final ColumnDataSource are the same length
    pix, piy = makePatches(r.index, y1lim, first=True)

    # The "master" data source to be used for plotting.
    #   Generate it via the column names in the now-merged 'r' DataFrame
    #   Start with the 'index' 'pix' and 'piy' since they're always those names
    mds = dict(index=r.index, pix=pix, piy=piy)

    # Start our plot source
    cds = ColumnDataSource(mds)

    # Now loop over the rest of our columns to fill it out, plotting as we go
    cols = r.columns
    lineSet = []
    legendItems = []
    for i, col in enumerate(cols):
        # Add our data to the cds
        cds.add(getattr(r, col), name=col)

        # Make the actual line plot object
        # TODO: Make this search in a given "y2" axis list
        if col.lower() == "humidity":
            lineObj, _ = plotLineWithPoints(p, cds, col, dset[i], yrname="y2")
        else:
            lineObj, _ = plotLineWithPoints(p, cds, col, dset[i])

        lineSet.append(lineObj)

        # Now make it's corresponding legend item
        legendObj = LegendItem(label=col, renderers=[lineObj])
        legendItems.append(legendObj)

    legend = Legend(items=legendItems,
                    location="bottom_center",
                    orientation='horizontal',
                    spacing=15)
    p.add_layout(legend, 'below')

    # Customize the active tools
    p.toolbar.autohide = True

    # HACK HACK HACK HACK HACK
    #   Apply the patches to carry the tooltips
    #
    # Shouldn't I just stream this instead of pix/nix and piy/niy ???
    #
    simg = p.patches('pix',
                     'piy',
                     source=cds,
                     fill_color=None,
                     fill_alpha=0.0,
                     line_color=None)

    # This will also create the tooltips for each of the entries in cols
    ht = createHoverTool(simg, cols)
    p.add_tools(ht)

    return p, cds, cols