async def extreme(self, ctx, *args: str): """Plots pairs of lowest rated unsolved problem and highest rated solved problem for every contest that was rated for the given user. """ (solved, unsolved, nolegend), args = cf_common.filter_flags( args, ['+solved', '+unsolved', '+nolegend']) legend, = cf_common.negate_flags(nolegend) if not solved and not unsolved: solved = unsolved = True handles = args or ('!' + str(ctx.author), ) handle, = await cf_common.resolve_handles(ctx, self.converter, handles) ratingchanges = await cf.user.rating(handle=handle) if not ratingchanges: raise GraphCogError(f'User {handle} is not rated') contest_ids = [change.contestId for change in ratingchanges] subs_by_contest_id = {contest_id: [] for contest_id in contest_ids} for sub in await cf.user.status(handle=handle): if sub.contestId in subs_by_contest_id: subs_by_contest_id[sub.contestId].append(sub) packed_contest_subs_problemset = [ (cf_common.cache2.contest_cache.get_contest(contest_id), cf_common.cache2.problemset_cache.get_problemset(contest_id), subs_by_contest_id[contest_id]) for contest_id in contest_ids ] rating = max( ratingchanges, key=lambda change: change.ratingUpdateTimeSeconds).newRating _plot_extreme(handle, rating, packed_contest_subs_problemset, solved, unsolved, legend) discord_file = gc.get_current_figure_as_file() embed = discord_common.cf_color_embed( title='Codeforces extremes graph') discord_common.attach_image(embed, discord_file) discord_common.set_author_footer(embed, ctx.author) await ctx.send(embed=embed, file=discord_file)
async def scatter(self, ctx, *args): """Plot Codeforces rating overlaid on a scatter plot of problems solved. Also plots a running average of ratings of problems solved in practice.""" (nolegend, ), args = cf_common.filter_flags(args, ['+nolegend']) legend, = cf_common.negate_flags(nolegend) filt = cf_common.SubFilter() args = filt.parse(args) handle, bin_size, point_size = None, 10, 3 for arg in args: if arg[0:2] == 'b=': bin_size = int(arg[2:]) elif arg[0:2] == 's=': point_size = int(arg[2:]) else: if handle: raise GraphCogError('Only one handle allowed.') handle = arg if bin_size < 1 or point_size < 1 or point_size > 100: raise GraphCogError('Invalid parameters') handle = handle or '!' + str(ctx.author) handle, = await cf_common.resolve_handles(ctx, self.converter, (handle, )) rating_resp = [await cf.user.rating(handle=handle)] rating_resp = [ filt.filter_rating_changes(rating_changes) for rating_changes in rating_resp ] submissions = filt.filter_subs(await cf.user.status(handle=handle)) def extract_time_and_rating(submissions): return [(dt.datetime.fromtimestamp(sub.creationTimeSeconds), sub.problem.rating) for sub in submissions] if not any(submissions): raise GraphCogError(f'No submissions for user `{handle}`') solved_by_type = _classify_submissions(submissions) regular = extract_time_and_rating(solved_by_type['CONTESTANT'] + solved_by_type['OUT_OF_COMPETITION']) practice = extract_time_and_rating(solved_by_type['PRACTICE']) virtual = extract_time_and_rating(solved_by_type['VIRTUAL']) plt.clf() _plot_scatter(regular, practice, virtual, point_size) labels = [] if practice: labels.append('Practice') if regular: labels.append('Regular') if virtual: labels.append('Virtual') if legend: plt.legend(labels, loc='upper left') _plot_average(practice, bin_size) _plot_rating(rating_resp, mark='') # zoom ymin, ymax = plt.gca().get_ylim() plt.ylim(max(ymin, filt.rlo - 100), min(ymax, filt.rhi + 100)) discord_file = gc.get_current_figure_as_file() embed = discord_common.cf_color_embed( title=f'Rating vs solved problem rating for {handle}') discord_common.attach_image(embed, discord_file) discord_common.set_author_footer(embed, ctx.author) await ctx.send(embed=embed, file=discord_file)