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)