def _create_week_area(
    plot: plt.Subplot,
    week: models.PotentialWeek,
    pattern: models.PricePatterns,
) -> None:
    """Add the price par chart for a specific potential week."""

    min_prices: List[int] = list()
    max_prices: List[int] = list()

    for prices in week.prices:
        min_prices.append(prices.min)
        max_prices.append(prices.max)

    # We need to double up the first and last point so areas for the first and last
    # period hit the edge of the graph
    min_prices.insert(0, min_prices[0])
    max_prices.insert(0, max_prices[0])

    min_prices.append(min_prices[-1])
    max_prices.append(max_prices[-1])

    # the x locations for the bars
    price_color = colors.PATTERN_COLORS[pattern]
    price_color = colors.color(*price_color,
                               alpha=utils.chance_alpha(week.chance))
    plot.fill_between(
        PRICE_PERIODS_EXTENDED,
        min_prices,
        max_prices,
        step="mid",
        facecolor=price_color,
        linewidth=0,
        edgecolor="none",
    )
def _create_weekday_grid(weekday_labels: plt.Subplot, ) -> None:
    weekday_labels.grid(
        axis="x",
        linestyle="-",
        linewidth=2,
        color=colors.DAY_GRID_COLOR,
        alpha=colors.DAY_GRID_ALPHA,
        zorder=1,
    )
def _plot_current_prices(plot_prices: plt.Subplot,
                         ticker: models.Ticker) -> int:
    current_period = -1
    prices: List[Optional[int]] = [
        None for _ in range(0, PRICE_PERIOD_COUNT + 2)
    ]
    if ticker.purchase_price != 0:
        prices[0] = ticker.purchase_price

    for i in range(0, PRICE_PERIOD_COUNT):
        try:
            this_price = ticker.prices[i]
        except IndexError:
            continue

        if this_price != 0:
            prices[i + 1] = this_price

            current_period = i

    if ticker.current_period > current_period:
        current_period = ticker.current_period

    plot_prices.step(
        [i for i in range(-1, PRICE_PERIOD_COUNT + 1)],
        prices,
        where="mid",
        linestyle="--",
        linewidth=4,
        dash_capstyle="projecting",
        color=colors.CURRENT_PRICE_COLOR,
    )

    # Annotate the prices
    for i, this_price in enumerate(ticker.prices):
        # Zero means unknown, skip it.
        if this_price == 0:
            continue

        plot_prices.annotate(
            str(this_price),
            (i, this_price),
            textcoords="offset points",
            xytext=(0, 10),
            ha="center",
            va="bottom",
            fontsize=LABEL_SIZE * 1.2,
            color=colors.CURRENT_PRICE_COLOR,
        )

    return current_period
Exemple #4
0
def _create_price_watermark(
    plot: plt.Subplot,
    name: str,
    price: int,
    va_top: bool,
    pattern: Optional["models.PricePatterns"],
) -> None:
    y_text_offset = 5

    if va_top:
        vertical_alignment = "top"
        y_text_offset *= -1
    else:
        vertical_alignment = "bottom"

    if pattern is None:
        pattern_color = colors.CURRENT_PRICE_COLOR
    else:
        pattern_color = colors.PATTERN_COLORS[pattern]

    # Create a dotted line line at the break-even point that matches the price
    # progression
    price_line = mlines.Line2D(
        [0, 4],
        [price, price],
        color=pattern_color,
        linewidth=2,
        linestyle="--",
    )
    plot.add_line(price_line)

    plot.annotate(
        f"{name}: {price}",
        (2, price),
        textcoords="offset points",
        xytext=(0, y_text_offset),
        horizontalalignment="center",
        verticalalignment=vertical_alignment,
        color=pattern_color,
        fontsize=LABEL_SIZE,
        bbox={
            "boxstyle": "Square,pad=0.3",
            "facecolor": colors.color(0, 0, 0, alpha=0.08),
            "edgecolor": "none",
            "linewidth": 0,
        },
    )
Exemple #5
0
def _set_legend(labels: np.ndarray, cmap: colors.ListedColormap, ax: plt.Subplot):
    unique_labels = np.unique(labels)
    legend_elements = [Patch(facecolor=cmap.colors[i], label=unique_label)
                       for i, unique_label in enumerate(unique_labels)]
    legend = ax.legend(handles=legend_elements, title='Clusters', fontsize=14,
                       title_fontsize=14, loc="lower left")
    legend.get_frame().set_alpha(None)
    legend.get_frame().set_facecolor((1, 1, 1, 0.25))
Exemple #6
0
def show_image(img: np.array, ax: plt.Subplot = None, title: str = ''):
    if ax:
        ax.set_title(title)
        ax.set_yticklabels([])
        ax.set_xticklabels([])
        ax.axes.get_xaxis().set_visible(False)
        ax.axes.get_yaxis().set_visible(False)
        ax.imshow(img)
    else:
        plt.imshow(img)
def _add_cursor(plot_prices: plt.Subplot, current_period: int) -> None:
    # Create a shaded region for the current period
    rect = patches.Rectangle(
        (current_period - 0.5, 0),
        1,
        701,
        linewidth=0,
        color=colors.CURRENT_PRICE_COLOR,
        alpha=0.1,
    )

    # Add the patch to the Axes
    plot_prices.add_patch(rect)

    # Create a line at the head of the current price period
    current_period_line = mlines.Line2D(
        [current_period - 0.5, current_period - 0.5],
        [0, 700],
        color=colors.CURRENT_PRICE_COLOR,
    )
    plot_prices.add_line(current_period_line)
    def draw(self, ax: plt.Subplot, c: str = 'k', lw: int = 1, **kwargs):
        """
        draw this rect

        Parameters
        ----------
        ax
            subplot object to use for the plotting
        c
            color argument passed to plot
        lw
            linewidth argument passed to plot
        """

        ax.plot([
            self.west_edge, self.east_edge, self.east_edge, self.west_edge,
            self.west_edge
        ], [
            self.north_edge, self.north_edge, self.south_edge, self.south_edge,
            self.north_edge
        ],
                c=c,
                lw=lw,
                **kwargs)
Exemple #9
0
def add_proportion(ax1: plt.Subplot, ax2: plt.Subplot, series: pd.Series,
                   name: str) -> list:

    for key in series.keys():
        if series[key] < .05 * sum(series):
            if 'other' not in series.keys():
                series['other'] = 0

            series['other'] += series.pop(key)

    wedges, _, autotexts = ax2.pie(series.values,
                                   autopct='%1.1f%%',
                                   startangle=90,
                                   colors=COLORS,
                                   counterclock=False)

    ax1.legend(wedges, series.keys(), title=name, loc="center")

    ax2.axis('equal')
    ax1.axis('off')

    return autotexts
def plot_price_periods(
    plot_prices: plt.Subplot,
    options: ForecastOptions,
) -> None:

    # set bg color for all graphs
    for plot in [plot_prices]:
        plot.set_facecolor(options.bg_color)
        # Remove all spines
        for spine in plot.spines.values():
            spine.set_visible(False)

    plot_prices.set_facecolor(options.bg_color)
    plot_prices.set_ylim(PRICE_Y_LIM)
    plot_prices.set_xlim([-1, 12])
    plot_prices.axes.set_yticks(np.arange(0, 701, 100))

    plot_prices.grid(
        axis="y",
        linestyle="-",
        linewidth=0.5,
        color=colors.PRICE_GRID_COLOR,
        alpha=colors.PRICE_GRID_ALPHA,
    )

    forecast = options.forecast
    for pattern in forecast.patterns:
        for week in pattern.potential_weeks:
            _create_week_area(plot_prices, week, pattern.pattern)

    big_pattern = utils.get_pattern(forecast, models.PricePatterns.BIGSPIKE)
    if big_pattern.chance > 0:
        _create_pattern_line(
            plot_prices,
            spike_breakdown=[x for x in forecast.spikes.big.breakdown],
            spike_pattern=big_pattern,
            spike_color=colors.BIG_SPIKE_COLOR,
        )

    small_pattern = utils.get_pattern(forecast,
                                      models.PricePatterns.SMALLSPIKE)
    if small_pattern.chance > 0:
        _create_pattern_line(
            plot_prices,
            spike_breakdown=[x for x in forecast.spikes.small.breakdown],
            spike_pattern=small_pattern,
            spike_color=colors.SMALL_SPIKE_COLOR,
        )

    bottom_axis = plot_prices.axes
    # the x locations for the bars
    indTods = np.arange(PRICE_PERIOD_COUNT)
    # Add the time of day labels for each bar
    bottom_axis.axes.set_xlim(plot_prices.get_xlim())
    bottom_axis.axes.set_xticks(indTods)
    bottom_axis.axes.set_xticklabels(PRICE_TODS)
    bottom_axis.spines["bottom"].set_position(("axes", -0.01))

    # Create weekday labels
    weekday_labels = bottom_axis.twiny()
    # We need to make sure the limits match to line up with the bars
    weekday_labels.set_xlim(plot_prices.get_xlim())
    # Place the weekdays between the AM / PM values
    weekday_labels.set_xticks([0.5, 2.5, 4.5, 6.5, 8.5, 10.5])
    # Set the labels
    weekday_labels.set_xticklabels(PRICE_DAYS)
    # Move the weekday labels down a littls
    weekday_labels.spines["bottom"].set_position(("axes", -0.06))
    _create_weekday_grid(weekday_labels)

    # style price axes
    plot_prices.tick_params(
        axis="y",
        labelcolor=colors.PRICE_LABEL_COLOR,
        labelsize=LABEL_SIZE,
        labeltop=False,
        labelbottom=False,
        labelright=True,
        labelleft=True,
        bottom=False,
        top=False,
        left=False,
    )

    # style TOD labels
    bottom_axis.tick_params(
        axis="x",
        labelcolor=colors.DAY_LABEL_COLOR,
        labelsize=LABEL_SIZE,
        labeltop=False,
        labelbottom=True,
        labelright=False,
        labelleft=False,
        bottom=False,
        top=False,
        left=False,
    )

    # style weekday labels
    weekday_labels.tick_params(
        axis="both",
        labelcolor=colors.DAY_LABEL_COLOR,
        labelsize=LABEL_SIZE,
        labelbottom=True,
        labeltop=False,
        bottom=False,
        top=False,
        left=False,
    )

    # Style tod and day label for current price period
    current_period = _plot_current_prices(plot_prices, options.ticker)
    if current_period != -1:
        bbox = dict(
            boxstyle="round,pad=0.5",
            color=colors.DAY_LABEL_COLOR,
        )
        current_tod_label = bottom_axis.xaxis.get_ticklabels()[current_period]
        current_tod_label.set_color("white")
        current_tod_label.set_bbox(bbox)

    _add_cursor(plot_prices, current_period)

    all_spines = itertools.chain(
        plot_prices.spines.values(),
        weekday_labels.spines.values(),
    )
    for spine in all_spines:
        spine.set_visible(False)
def plot_pattern_chances(plot: plt.Subplot, forecast: models.Forecast) -> None:
    total = 0.0

    valid_patterns = sorted(
        (x for x in forecast.patterns if x.chance != 0),
        key=lambda x: x.chance,
        reverse=True,
    )

    for i, potential_pattern in enumerate(valid_patterns):
        if i > 0:
            # Add a little bit of space between sections
            total += 0.01

        chance = potential_pattern.chance
        # If the chance gets below 2.5%, the bar disappears, so we need to have a
        # minimum visual value for it.
        adjusted_chance = max(potential_pattern.chance, 0.015)

        pattern_color = colors.PATTERN_COLORS[potential_pattern.pattern]

        plot.barh(
            0.5,
            height=0.8,
            width=adjusted_chance,
            left=total,
            color=colors.color(*pattern_color, alpha=chance),
            linewidth=0,
        )

        patten_name = PATTERN_NAMES[potential_pattern.pattern]
        plot.annotate(
            f"{patten_name}: {utils.format_chance(chance)}",
            (total + (adjusted_chance / 2), 0.5),
            color="white",
            alpha=0.75,
            fontsize=LABEL_SIZE * chance**0.9 + LABEL_SIZE / 2,
            fontweight="bold",
            ha="center",
            va="center",
        )
        total += adjusted_chance

    plot.set_xlim((0, total))
    plot.set_ylim((0, 1))

    # remove axis labels
    plot.tick_params(
        axis="both",
        labeltop=False,
        labelbottom=False,
        labelright=False,
        labelleft=False,
        top=False,
        bottom=False,
        left=False,
        right=False,
    )

    plot.patch.set_visible(False)
    for spine in plot.spines.values():
        spine.set_visible(False)
Exemple #12
0
def plot_prices_range(
    plot: plt.Subplot,
    ticker: models.Ticker,
    forecast: models.Forecast,
) -> None:
    max_pattern = models.PricePatterns.UNKNOWN
    guaranteed_pattern = models.PricePatterns.UNKNOWN
    min_pattern = models.PricePatterns.UNKNOWN

    break_even = ticker.purchase_price

    plot.axes.set_ylim(PRICE_Y_LIM)
    plot.axes.set_xlim([0, 4])

    bar_anchors = np.arange(4)

    for i, potential_pattern in enumerate(forecast.patterns):
        bar_position = bar_anchors[i]

        if len(potential_pattern.potential_weeks) == 0:
            continue

        min_price = potential_pattern.prices_future.min
        max_price = potential_pattern.prices_future.max

        pattern_color = colors.PATTERN_COLORS[potential_pattern.pattern]
        bar_color = colors.color(*pattern_color,
                                 alpha=potential_pattern.chance)

        plot.bar(
            [bar_position],
            [max_price - min_price],
            bottom=min_price,
            width=0.4,
            align="edge",
            color=bar_color,
        )

        if potential_pattern.prices_future.max == forecast.prices_future.max:
            max_pattern = potential_pattern.pattern

        if (potential_pattern.prices_future.guaranteed ==
                forecast.prices_future.guaranteed):
            guaranteed_pattern = potential_pattern.pattern

        if potential_pattern.prices_future.min == forecast.prices_future.min:
            min_pattern = potential_pattern.pattern

    # Create a price grid that matches the price progression
    plot.grid(
        axis="y",
        linestyle="-",
        linewidth=0.5,
        color=colors.PRICE_GRID_COLOR,
        alpha=colors.PRICE_GRID_ALPHA,
    )

    # Create a dotted line line at the breakeven point that matches the price
    # progression
    if break_even != 0:
        _create_price_watermark(plot,
                                "break-even",
                                break_even,
                                va_top=False,
                                pattern=None)

    # Create a dotted line line at the max profit point
    _create_price_watermark(
        plot,
        "potential",
        forecast.prices_future.max,
        va_top=False,
        pattern=max_pattern,
    )

    # Create a dotted line line at the max guaranteed point
    _create_price_watermark(
        plot,
        "guaranteed",
        forecast.prices_future.guaranteed,
        va_top=True,
        pattern=guaranteed_pattern,
    )

    if forecast.prices_summary.min != forecast.prices_summary.guaranteed:
        # Create a dotted line line at the min price
        _create_price_watermark(
            plot,
            "minimum",
            forecast.prices_future.min,
            va_top=True,
            pattern=min_pattern,
        )

    # remove axis labels
    plot.tick_params(
        axis="both",
        labeltop=False,
        labelbottom=False,
        labelright=False,
        labelleft=False,
        top=False,
        bottom=False,
        left=False,
        right=False,
    )

    plot.patch.set_visible(False)
    for position, spine in plot.spines.items():
        spine.set_visible(False)
Exemple #13
0
            try:
                results.append(all_results[hyp][metric_index])  # choose index based on 'returns', 'action_entropy_trajectory', etc.
            except:
                print('missing')
                results.append(np.zeros([50, 100]))

    results = np.array(results)
    results = results.transpose([1, 0, 2])
    data_ent = results

    N = 20

    # Valentin's plots
    from matplotlib.pyplot import Subplot
    fig = plt.figure(figsize = (9, 6.5))
    ax = Subplot(fig, 111)
    fig.add_subplot(ax)
    # ax.axis["right"].set_visible(False)
    # ax.axis["top"].set_visible(False)
    save_freq = 5
    vec = np.arange(data_ent.mean(0).T[:, 0].shape[0]) * save_freq

    # vec =
    # vec = np.logspace(0, np.log10(50000), data_ent.mean(0).T[:, 0].shape[0])
    # T = 10
    # fig_names = ['return', '']
    # colors = [u'b', u'g', u'r', u'c', u'm', u'y'] #['blue', 'dodgerblue', 'black', 'orange', 'red']
    ylabels = ['returns', 'discounted returns', 'Action entropy trajectory', 'Online state visitation entropy', 'Offline state visitation entropy']
    ylabels = ['Returns', 'discounted returns', 'Action Entropy', 'State Entropy', 'Offline State Entropy']

    # colors = plt.cm.seismic(np.linspace(0, 1, n))
Exemple #14
0
def plot_stop_accessibility_hist(subplot: Subplot,
                                 result: CrossStopRemovalResult):
    """Plot the accessibility difference in ``result`` as a subplot onto ``subplot``."""
    # ----- Plot histogram
    # https://datavizpyr.com/overlapping-histograms-with-matplotlib-in-python/

    # Configure plot
    subplot.set_xlabel("Distance to stop (km)", size=14)
    subplot.set_ylabel("Agent count", size=14)
    subplot.set_title(
        f"Distance to stop between before and after removing {result.stop_removed.cross_name}"
    )

    # Plot histograms
    subplot.hist(result.metrics_before.data,
                 bins=20,
                 alpha=0.5,
                 label="Before")
    subplot.hist(result.metrics_after.data, bins=20, alpha=0.5, label="After")

    # Post-configure the plot
    subplot.legend(loc="upper right")
Exemple #15
0
def _remove_axes(ax: plt.Subplot):
    ax.set(yticklabels=[], xticklabels=[])
    ax.tick_params(left=False, bottom=False)
    plt.tight_layout()
def _create_pattern_line(
    price_plot: plt.Subplot,
    spike_breakdown: List[float],
    spike_pattern: models.PotentialPattern,
    spike_color: List[float],
) -> None:
    """Create a dashed line on the max price for periods with a potential spike"""
    # get highest possible price for each period

    first_period = spike_pattern.spike.start
    last_period = spike_pattern.spike.end
    high_price = spike_pattern.prices_summary.max

    period_highs: List[Optional[int]] = [
        high_price for _ in range(first_period, last_period + 1)
    ]
    price_periods: List[float] = [
        p for p in range(first_period, last_period + 1)
    ]

    # Instead of using a plot, we are just going to draw the line directly.
    # Create a line at the head of the current price period
    current_period_line = mlines.Line2D(
        [first_period - 0.5, last_period + 0.5],
        [high_price, high_price],
        color=spike_color,
        linestyle="--",
        linewidth=4,
        # We want this line to be always visible so our alpha floor is going to be .1
        alpha=max(utils.chance_alpha(spike_pattern.chance), 0.1),
    )
    price_plot.add_line(current_period_line)

    y_annotation_distance = 10

    for period in price_periods:
        if period == 11.5:
            continue

        try:
            chance = spike_breakdown[int(period)]
        except TypeError:
            # If this is period '11.5', then we don't need to annotate it, that value
            # is just here for line continuation
            continue

        # We need to render the numbers ABOVE the spike patter so that they don't
        # get illegible as the spike placement becomes more certain.
        price_plot.annotate(
            utils.format_chance(chance),
            (period, high_price),
            textcoords="offset points",
            xytext=(0, y_annotation_distance),
            ha="center",
            va="bottom",
            fontsize=LABEL_SIZE,
            color=spike_color,
        )

    # Annotate the total chance of this spike
    price_plot.annotate(
        utils.format_chance(spike_pattern.chance),
        (first_period - 0.5 - 0.1, high_price),
        ha="right",
        va="center",
        fontsize=LABEL_SIZE,
        color="white",
        alpha=0.75,
        bbox={
            "boxstyle": "Circle,pad=0.6",
            "facecolor": colors.color(*spike_color),
            "edgecolor": spike_color,
            "linewidth": 0,
        },
    )

    # Add a label to the daily chances for clarity
    middle = first_period + (last_period - first_period) / 2
    middle_price = next(p for p in period_highs if p)

    price_plot.annotate(
        "daily:",
        (middle, middle_price + y_annotation_distance * 2.5),
        textcoords="offset points",
        xytext=(0, y_annotation_distance),
        ha="center",
        va="bottom",
        fontsize=LABEL_SIZE * 1.1,
        color=spike_color,
    )
Exemple #17
0
def plot_stop_accessibility_cdf(subplot: Subplot, result: CrossStopRemovalResult):
    """Plot the accessibility difference in ``result`` as a subplot onto ``subplot``."""
    # pylint: disable=invalid-name

    # Configure plot
    subplot.set_xlabel("Distance to stop (km)", size=20)
    subplot.set_ylabel("Percentile", size=20)
    subplot.set_title(result.stop_removed.cross_name, size=24)

    # Plot CDF
    x, y = result.metrics_before.get_quantile_cdf(20)
    subplot.plot(x, y, label="Before")

    x, y = result.metrics_after.get_quantile_cdf(20)
    subplot.plot(x, y, label="After")

    # Post-configure the plot
    subplot.legend(loc="upper right")