2022年9月28日水曜日

Pythonでヒストグラムを生成する【3/3】

 前回



前回はデータの分類をやったので今回はグラフの作成


3.グラフの作成



こういったグラフにするためには、「階級数」だけリストを作成し、それらの要素数は「最大の階級の値」する。そのうえで、各リストを最後尾から「■」で埋めて、最後に縦軸を合成すればいい。つまり、階級数が10、最大の階級の値が10であれば、10個の空白の要素を持つ10個のリストを用意すればよい。
#sep_listは階級(横軸)
#separatedは元データを階級別に分けたもの

longest = 0
for i in separated:
    if len(i) > longest:
        longest = len(i)
y = longest + 1 
x = len(sep_list)
graph = [[' ']*x for _ in range(y)]
sep_list = list(map(lambda x: (map(lambda y: str(y),x)), sep_list))
 	#sep_listは[int, int]の形なのでstrに変換
graph[y-1] = list(map(lambda x:'~'.join(x), sep_list))
	#グラフのリスト末尾に軸を追加
for i in range(x):
    volume = len(separated[i])
    for k in range(volume,0,-1): #後ろから■で埋めてく
        graph[y-1-k][i] = "■"
    

最後にグラフの縦軸を作成する。
まず、グラフの縦軸の数字を含むリスト用意する。縦軸は、グラフを含むリストの一次元目の要素数~1までをとる。ここでは次のステップの都合上0まで含むリストを「要素数」、「要素数-1」... 「0」といった形で作成する。
その後、このリストをグラフリストの一次元目の要素(リスト)の先頭に入れる形で結合する。
最後にグラフリストの[0][0]を半角スペースに置換する。


#graphはグラフを格納しているリスト
num = [[i] for i in range(len(graph)-1,-1,-1)]
for i in range(len(graph)):
	graph[i] = num[i] + graph[i]
self.graph[len(graph)-1][0] = ' '
最後にこれまでのコードをまとめてクラス化するとこう
class histogram:
    """docstring-
        data_array -> ヒストグラムにしたいデータ(一次元リスト)
        sep -> ヒストグラムの階級    
        drawメソッドで実行
        output_to_csvメソッドでワーキングディレクトリにcsv書き出し
    """
    def __init__(self, data_array, sep):
        self.data = data_array
        self.s = min(data_array)
        self.e = max(data_array)
        self.sep = sep
        self.separated = []
        self.sep_list = []

    def draw(self):
        self.distribute_data()
        self.select_list()
        self.draw_a_histogram()
        self.draw_vertical_axis()

    def draw_a_histogram(self):
        longest = 0
        for i in self.separated:
            if len(i) > longest:
                longest = len(i)
        y = longest + 1
        x = len(self.sep_list)
        self.graph = [[' ']*x for _ in range(y)]
        self.sep_list = list(map(lambda x: (map(lambda y: str(y),x)), self.sep_list))
        self.graph[y-1] = list(map(lambda x:'~'.join(x), self.sep_list))
        for i in range(x):
            volume = len(self.separated[i])
            for k in range(volume,0,-1):
                self.graph[y-1-k][i] = "■"
        
    def distribute_data(self):
        n = (self.e - self.s+1)//self.sep
        if (self.e - self.s +1)%self.sep != 0:
            n += 1
        self.separated = [[] for _ in range(n)]
        for i in range(n):
            if i == 0:
                self.sep_list.append([self.s, self.s + self.sep -1])
            else:
                previous = self.sep_list[i-1][1]
                nxt = previous + self.sep
                if nxt >= self.e:
                    nxt = self.e
                if previous + 1 == nxt:
                    self.sep_list.append([previous+1])
                else:
                    self.sep_list.append([previous+1, nxt])

    def select_list(self):
        for i in self.data:
            counter = (i - self.s) // self.sep
            self.separated[counter].append(i)

    def draw_vertical_axis(self):
        num = [[i] for i in range(len(self.graph)-1,-1,-1)]
        for i in range(len(self.graph)):
            self.graph[i] = num[i] + self.graph[i]
        self.graph[len(self.graph)-1][0] = ' '
        
    def output_to_csv(self):
        import csv
        with open("./histogram.csv",encoding = "utf-8",newline='',mode="w") as f:
            writer = csv.writer(f)
            writer.writerows(self.graph)