2022年9月28日水曜日

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

 前回



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


3.グラフの作成



こういったグラフにするためには、「階級数」だけリストを作成し、それらの要素数は「最大の階級の値」する。そのうえで、各リストを最後尾から「■」で埋めて、最後に縦軸を合成すればいい。つまり、階級数が10、最大の階級の値が10であれば、10個の空白の要素を持つ10個のリストを用意すればよい。
  1. #sep_listは階級(横軸)
  2. #separatedは元データを階級別に分けたもの
  3. longest = 0
  4. for i in separated:
  5. if len(i) > longest:
  6. longest = len(i)
  7. y = longest + 1
  8. x = len(sep_list)
  9. graph = [[' ']*x for _ in range(y)]
  10. sep_list = list(map(lambda x: (map(lambda y: str(y),x)), sep_list))
  11. #sep_listは[int, int]の形なのでstrに変換
  12. graph[y-1] = list(map(lambda x:'~'.join(x), sep_list))
  13. #グラフのリスト末尾に軸を追加
  14. for i in range(x):
  15. volume = len(separated[i])
  16. for k in range(volume,0,-1): #後ろから■で埋めてく
  17. graph[y-1-k][i] = "■"

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


  1. #graphはグラフを格納しているリスト
  2. num = [[i] for i in range(len(graph)-1,-1,-1)]
  3. for i in range(len(graph)):
  4. graph[i] = num[i] + graph[i]
  5. self.graph[len(graph)-1][0] = ' '
最後にこれまでのコードをまとめてクラス化するとこう
  1. class histogram:
  2. """docstring-
  3. data_array -> ヒストグラムにしたいデータ(一次元リスト)
  4. sep -> ヒストグラムの階級
  5. drawメソッドで実行
  6. output_to_csvメソッドでワーキングディレクトリにcsv書き出し
  7. """
  8. def __init__(self, data_array, sep):
  9. self.data = data_array
  10. self.s = min(data_array)
  11. self.e = max(data_array)
  12. self.sep = sep
  13. self.separated = []
  14. self.sep_list = []
  15. def draw(self):
  16. self.distribute_data()
  17. self.select_list()
  18. self.draw_a_histogram()
  19. self.draw_vertical_axis()
  20. def draw_a_histogram(self):
  21. longest = 0
  22. for i in self.separated:
  23. if len(i) > longest:
  24. longest = len(i)
  25. y = longest + 1
  26. x = len(self.sep_list)
  27. self.graph = [[' ']*x for _ in range(y)]
  28. self.sep_list = list(map(lambda x: (map(lambda y: str(y),x)), self.sep_list))
  29. self.graph[y-1] = list(map(lambda x:'~'.join(x), self.sep_list))
  30. for i in range(x):
  31. volume = len(self.separated[i])
  32. for k in range(volume,0,-1):
  33. self.graph[y-1-k][i] = "■"
  34. def distribute_data(self):
  35. n = (self.e - self.s+1)//self.sep
  36. if (self.e - self.s +1)%self.sep != 0:
  37. n += 1
  38. self.separated = [[] for _ in range(n)]
  39. for i in range(n):
  40. if i == 0:
  41. self.sep_list.append([self.s, self.s + self.sep -1])
  42. else:
  43. previous = self.sep_list[i-1][1]
  44. nxt = previous + self.sep
  45. if nxt >= self.e:
  46. nxt = self.e
  47. if previous + 1 == nxt:
  48. self.sep_list.append([previous+1])
  49. else:
  50. self.sep_list.append([previous+1, nxt])
  51. def select_list(self):
  52. for i in self.data:
  53. counter = (i - self.s) // self.sep
  54. self.separated[counter].append(i)
  55. def draw_vertical_axis(self):
  56. num = [[i] for i in range(len(self.graph)-1,-1,-1)]
  57. for i in range(len(self.graph)):
  58. self.graph[i] = num[i] + self.graph[i]
  59. self.graph[len(self.graph)-1][0] = ' '
  60. def output_to_csv(self):
  61. import csv
  62. with open("./histogram.csv",encoding = "utf-8",newline='',mode="w") as f:
  63. writer = csv.writer(f)
  64. writer.writerows(self.graph)