AtCoderの順位ヒストグラムのソースから上位何パーセントかわかる早見グラフをPythonで作ってみた

 先日、AtCoderで上位何パーセントかわかる早見グラフを作ってみたという記事を書きました。前回はグラフを目視でトレースしたのですが、ページのソースから配列をとれることが分かったので、Pythonでもっと効率的に早見グラフを作ることにしました。コメントくださった方、ありがとうございます!

(2023/6/1追記)

スクレイピングプログラムを作成し、
定期実行によってログ取得できるようにしました。
順位ヒストグラムの定期スクレイピングによるログ作成!【AtCoder】【レーティング分布】

順位ヒストグラムの配列の取り方

 以下の様に、コンテスト実績のRating分布で、右クリックから、ページのHTMLソースを表示します。ソースの239行目に横軸のレーティング(var_xaxis)、240行目に縦軸の人数(var_data)があります。これをコピーしてPythonでヒストグラムを作りました。

Rating分布のページで右クリック→ページのソースを表示

239,240行目の配列をコピーしておく

Pythonプログラム

 ヒストグラムを作るためのコードを作りました。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime
# グラフの見た目を調整
plt.rcParams["figure.figsize"] = [6.4,4.0]  # 図の縦横のサイズ([横(inch),縦(inch)])
plt.rcParams["figure.dpi"] = 150            # dpi(dots per inch)
plt.rcParams["figure.autolayout"] = False   # レイアウトの自動調整を利用するかどうか
plt.rcParams["figure.subplot.left"] = 0.14  # 余白
plt.rcParams["figure.subplot.bottom"] = 0.14# 余白
plt.rcParams["figure.subplot.right"] =0.90  # 余白
plt.rcParams["figure.subplot.top"] = 0.91   # 余白
plt.rcParams["figure.subplot.wspace"] = 0.20# 図が複数枚ある時の左右との余白
plt.rcParams["figure.subplot.hspace"] = 0.20# 図が複数枚ある時の上下との余白

plt.rcParams["font.family"] = "serif"       # 使用するフォント
plt.rcParams["font.serif"] = "Arial"
plt.rcParams["font.size"] = 18              # 基本となるフォントの大きさ
plt.rcParams["mathtext.cal"] = "serif"      # TeX表記に関するフォント設定
plt.rcParams["mathtext.rm"] = "serif"       # TeX表記に関するフォント設定
plt.rcParams["mathtext.it"] = "serif:italic"# TeX表記に関するフォント設定
plt.rcParams["mathtext.bf"] = "serif:bold"  # TeX表記に関するフォント設定
plt.rcParams["mathtext.fontset"] = "cm"     # TeX表記に関するフォント設定

plt.rcParams["xtick.direction"] = "in"      # 目盛り線の向き、内側"in"か外側"out"かその両方"inout"か
plt.rcParams["ytick.direction"] = "in"      # 目盛り線の向き、内側"in"か外側"out"かその両方"inout"か
plt.rcParams["xtick.top"] = False           # 上部に目盛り線を描くかどうか
plt.rcParams["xtick.bottom"] = False         # 下部に目盛り線を描くかどうか
plt.rcParams["ytick.left"] = True           # 左部に目盛り線を描くかどうか
plt.rcParams["ytick.right"] = True          # 右部に目盛り線を描くかどうか
plt.rcParams["xtick.major.size"] = 4.0      # x軸主目盛り線の長さ
plt.rcParams["ytick.major.size"] = 4.0      # y軸主目盛り線の長さ
plt.rcParams["xtick.major.width"] = 1.0     # x軸主目盛り線の線幅
plt.rcParams["ytick.major.width"] = 1.0     # y軸主目盛り線の線幅
plt.rcParams["xtick.minor.visible"] = False # x軸副目盛り線を描くかどうか
plt.rcParams["ytick.minor.visible"] = False # y軸副目盛り線を描くかどうか
plt.rcParams["xtick.minor.size"] = 2.0      # x軸副目盛り線の長さ
plt.rcParams["ytick.minor.size"] = 2.0      # y軸副目盛り線の長さ
plt.rcParams["xtick.minor.width"] = 0.6     # x軸副目盛り線の線幅
plt.rcParams["ytick.minor.width"] = 0.6     # y軸副目盛り線の線幅
plt.rcParams["xtick.labelsize"] = 16        # 目盛りのフォントサイズ
plt.rcParams["ytick.labelsize"] = 16        # 目盛りのフォントサイズ
# AtCoder のページソースから配列をコピー
var_xaxis = [0,1,2,3,4,5,7,9,12,15,19,25,32,42,54,69,89,114,147,188,242,311,400,500,600,700,800,900,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800,2900,3000,3100,3200,3300,3400,3500,3600,3700,3800,3900]
var_data = [1241,1982,5157,2060,1300,3466,2832,3319,2835,2731,3312,3104,3753,3677,3792,3839,3785,3980,3922,3789,3584,3437,3719,3323,3080,2678,2793,2247,1871,1530,1512,1079,1044,777,845,595,517,368,699,255,179,100,106,73,55,32,59,25,17,16,6,7,2,4,3,3,0,1]
# numpy配列に変換して累積和を計算
var_xaxis=np.array(var_xaxis)
var_data=np.array(var_data)
cum_var= np.round((1-var_data.cumsum()/var_data.sum())*100,6)

# 横軸用にnumpyの文字列の配列としておく
xlabel = var_xaxis.astype('str')
#色のリストを作る
color = []
for x in var_xaxis:
    if x < 400:
        color.append('gray')
    elif x < 800:
        color.append('brown')
    elif x < 1200:
        color.append('green')
    elif x < 1600:
        color.append('cyan')
    elif x < 2000:
        color.append('blue')
    elif x < 2400:
        color.append('y')
    elif x < 2800:
        color.append('orange')
    else:
        color.append('red')
# データラベルを張り付けるための関数

def add_value_label(x_list,y_list,offset):
    for i in range(0, len(x_list)):
        plt.text(x_list[i],y_list[i]+offset, y_list[i], ha='center', color='black',rotation=90) 
               #(x座標,y座標,表示するテキスト)

2022年8月28日時点でのヒストグラム

#全参加者のグラフ
fig, ax = plt.subplots(figsize=(20,16))
rect = ax.bar(xlabel, var_data, color=color) # プロット時にcolor引数に色を指定
ax.set_title(f'{datetime.date.today()} ({var_data.sum()} Participants)')
ax.set_xticklabels(xlabel, rotation=90)
ax.set_ylabel('Number of Participants')
add_value_label(xlabel,var_data,50)

fig.show()
plt.savefig('participants.jpg')

各レーティング毎の累積上位パーセンテージ

#全レーティング帯の上位パーセントグラフ
fig, ax = plt.subplots(figsize=(20,16))
rect = ax.bar(xlabel, cum_var, color=color)
ax.set_title(f'{datetime.date.today()} CumSumRank ({var_data.sum()} Participants)')
ax.set_xticklabels(xlabel, rotation=90)
ax.set_ylabel('Percentage_Rank(%)')

add_value_label(xlabel,np.round(cum_var,1),1)

fig.show()
plt.savefig('CumSumRank_all.jpg')

レーティング1200未満の累積上位パーセンテージ

#レーティング1200未満の上位パーセントグラフ
plt.rcParams["xtick.labelsize"] = 18
plt.rcParams["ytick.labelsize"] = 18 

Rr = 30
x=xlabel[:Rr]
y=cum_var[:Rr]
c=color[:Rr]

fig, ax = plt.subplots(figsize=(20,16))
rect = ax.bar(x, y, color=c)
ax.set_title(f'{datetime.date.today()} CumSumRank Rating < 1200')
ax.set_xticklabels(x, rotation=90)
ax.set_ylabel('Percentage_Rank(%)')

add_value_label(x,np.round(y,1),1)

fig.show()
plt.savefig('CumSumRank_below1200.jpg')

レーティング1200以上の累積上位パーセンテージ

#レーティング1200以上の上位パーセントグラフ
x = xlabel[Rr:]
y=cum_var[Rr:]
c=color[Rr:]

fig, ax = plt.subplots(figsize=(20,16))
rect = ax.bar(x, y, color=c)
ax.set_title(f'{datetime.date.today()} CumSumRank Rating >= 1200')
ax.set_xticklabels(x, rotation=90)
ax.set_ylabel('Percentage_Rank(%)')

add_value_label(x,np.round(y,3),0.1)

fig.show()
plt.savefig('CumSumRank_over1200.jpg')

参考サイト様

以下のサイト様を参考にしました

グラフのデザイン(https://qiita.com/aurueps/items/d04a3bb127e2d6e6c21b)
棒グラフの色変更(https://beiznotes.org/matplotlib-set-bar-color-depend-on-condition/)
棒グラフにデータラベルを表示(https://smart-hint.com/python/graph-label/)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA