📊

AtCoderの自分のパフォーマンスを円グラフにする

2021/02/10に公開

きっかけ

精進グラフのようなグラフ(そしてAtCoderのマイプロフィールにはないグラフ)を作ってみたい、と思い作りました。また、スクレイピングの練習になれば、と思い作りました。

実行環境

AnacondaのSpyder Pythonのバージョンは3.8.3 IPythonのバージョンは 7.16.1
MacOS Catalina バージョン10.15.6

注意点

ウェブスクレイピングはいくつかのウェブサイトの規約に反する可能性がある。 例えば、短文投稿サイトのツイッターではサービス利用規約によって明示的に禁止されており[3]、APIの利用が必須となる。
(Wikipedia WEBスクレイピングより抜粋)
例えば、Amazonは利用規約にスクレイピングを禁止していることを書いている。スクレイピングによる大量アクセスで、サーバに負荷をかけてしまうからである。岡崎市立中央図書館事件など事件に発達することがある。

Pythonで実装

テンプレート

atcoder_per.py
import requests
from bs4 import BeautifulSoup

def main(username):#usernameにあなたのユーザーネームを入れる
    site = requests.get('https://atcoder.jp/users/'+username+'/history/json')
    data = BeautifulSoup(site.text, 'html.parser')
    #スクレイピング
    S = str(data.text)
    say = ('"Performance":',',"InnerPerformance"')
    return search(S,say)


def search(S,say):
    '''
    ----------
    S : str
        スクレイピングした情報を入れる。
    say : tuple
        探す言葉

    Returns
    -------
    ans : list
        全てのSの中にあるsay[0]とsay[1]の間にある情報を戻り値とする
    '''
    ans = []
    num = 0
    l = []
    for i in range(len(S)):
        try:
            if S[i:i+len(say[num])] == say[num]:
                if num == 0:
                    l.append(i+len(say[0]))
                    
                else:
                    l.append(i)
                num = (num+1)%2
                
        except:
            break
    i = 0
    for i in range(len(l)//2):
        ans.append(S[l[i*2]:l[i*2+1]])
        
    return ans

if __name__ == "__main__":
    main("")

円グラフ

main.py
import matplotlib.pyplot as plt
from atcoder_per import main

def types(x):#種類(黒、灰色......赤)
    l = list(set([color(i) for i in x]))
    d = []
    if'black'in l:
        d.append('black')
    if'gray'in l:
        d.append('gray')
    if'brown'in l:
        d.append('brown')
    if'green'in l:
        d.append('green')
    if'lightblue'in l:
        d.append('lightblue')
    if'blue'in l:
        d.append('blue')
    if'yellow'in l:
        d.append('yellow')
    if'orange'in l:
        d.append('orange')
    if'red'in l:
        d.append('red')
    return d


def color(a):#xの色を返す
    x = int(a)
    if x  <= 0:
        return "black"
    if x < 400:
        return "gray"
    if x < 800:
        return "brown"
    if x < 1200:
        return "green"
    if x < 1600:
        return "lightblue"
    if x < 2000:
        return "blue"
    if x < 2400:
        return "yellow"
    if x < 2800:
        return "orange"
    return "red"



def colors(x):
    l = {"black":0,"gray":0,"brown":0,"green":0,"lightblue":0,"blue":0,"yellow":0,"orange":0,"red":0}
    for i in x:
        l[color(i)] = l[color(i)]+1
    ans =  list(l.values())
    while True:
        try:
            del ans[ans.index(0)]
        except:
            break
    return ans
    
def color_names(a):
    x = list(a)
    l = [x[i] for i in range(len(x))]
    d = {'black': 'k', 'gray': 'lightgrey', 'brown': 'saddlebrown', 'green': 'g', 'lightblue': 'aqua', 'blue': 'b', 'yellow': 'y', 'orange': 'orange', 'red': 'r'}
    for i in range(len(x)):
        l[i] = d[x[i]]
    return l



l = main("")#あなたのユーザーネーム


# Pie chart, where the slices will be ordered and plotted counter-clockwise:
labels = types(l)
sizes = colors(l)

colorlist = color_names(types(l))

fig1, ax1 = plt.subplots()
ax1.pie(sizes, labels=labels, colors = colorlist,autopct='%1.1f%%',
        shadow=True, startangle=90)
ax1.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.

plt.show()
出来上がるグラフの例

chokudai様

LayCurse様

これだと、Unratedなど(黒)が多くなってしまう、と言う弱点がある。
それが気になる方は、main.pyの73行目を

73行目変更
l = [l[i] for i in range(len(l)) if int(l[i]) > 0]

に変えれば良い。

参考文献

https://tech-camp.in/note/technology/48812/
https://blog.pyq.jp/entry/Python_kaiketsu_180207
https://ja.wikipedia.org/wiki/岡崎市立中央図書館事件
https://matplotlib.org/gallery/index.html
https://qiita.com/kenmatsu4/items/fe8a2f1c34c8d5676df8
https://matplotlib.org/examples/color/colormaps_reference.html
https://ai-inter1.com/python-piechart/
https://pythondatascience.plavox.info/matplotlib/色の名前

Discussion