libs.commands.report.results_list
libs/commands/report/results_list.py
1""" 2libs/commands/report/results_list.py 3""" 4 5import os 6 7import matplotlib.font_manager as fm 8import matplotlib.pyplot as plt 9 10import libs.global_value as g 11from cls.types import GameInfoDict 12from libs.data import aggregate, loader 13from libs.functions import configuration, message 14from libs.utils import formatter 15 16 17def main(): 18 """成績一覧表を生成する 19 20 Returns: 21 str: 生成ファイルパス 22 """ 23 24 # 検索動作を合わせる 25 g.params.update(guest_skip=g.params.get("guest_skip2")) 26 27 # --- データ取得 28 game_info: GameInfoDict = aggregate.game_info() 29 df = loader.read_data("report/results_list.sql").reset_index(drop=True) 30 df.index = df.index + 1 31 if df.empty: 32 return False 33 34 if g.params.get("anonymous"): 35 mapping_dict = formatter.anonymous_mapping(df["name"].unique().tolist()) 36 df["name"] = df["name"].replace(mapping_dict) 37 38 # 見出し設定 39 if g.params.get("individual"): 40 title = "個人成績一覧" 41 df = df.rename(columns={"name": "player"}) 42 else: # チーム集計 43 title = "チーム成績一覧" 44 df = df.rename(columns={"name": "team"}) 45 46 # 非表示項目 47 if g.cfg.mahjong.ignore_flying: 48 df = df.drop(columns=["flying_mix", "flying_count", "flying_%"]) 49 if "トビ" in g.cfg.dropitems.report: 50 df = df.drop(columns=["flying_mix", "flying_count", "flying_%"]) 51 if "役満" in g.cfg.dropitems.report: 52 df = df.drop(columns=["yakuman_mix", "yakuman_count", "yakuman_%"]) 53 if "役満和了" in g.cfg.dropitems.report: 54 df = df.drop(columns=["yakuman_mix", "yakuman_count", "yakuman_%"]) 55 56 match str(g.params.get("format", "default")).lower(): 57 case "text" | "txt": 58 file_path = text_generation(df) 59 case "csv": 60 file_path = csv_generation(df) 61 case _: 62 file_path = graph_generation(game_info, df, title) 63 64 return file_path 65 66 67def graph_generation(game_info: GameInfoDict, df, title): 68 """グラフ生成処理 69 70 Args: 71 game_info (GameInfoDict): ゲーム情報 72 df (pd.DataFrame): 描写データ 73 title (str): グラフタイトル 74 75 Returns: 76 str: 生成ファイルパス 77 """ 78 79 df = formatter.df_rename(df.filter( 80 items=[ 81 "player", "team", 82 "game", "total_mix", "avg_mix", "rank_avg", 83 "1st_mix", "2nd_mix", "3rd_mix", "4th_mix", "rank_dist", 84 "flying_mix", "yakuman_mix", 85 ] 86 )) 87 88 report_file_path = os.path.join( 89 g.cfg.setting.work_dir, 90 f"{g.params["filename"]}.png" if g.params.get("filename") else "report.png", 91 ) 92 93 # フォント/色彩設定 94 configuration.graph_setup(plt, fm) 95 plt.rcParams["font.size"] = 6 96 97 match (plt.rcParams["text.color"], plt.rcParams["figure.facecolor"]): 98 case text_color, bg_color if text_color == "black" and bg_color == "white": 99 line_color1 = "#dddddd" 100 line_color2 = "#ffffff" 101 case text_color, bg_color if text_color == "white" and bg_color == "black": 102 line_color1 = "#111111" 103 line_color2 = "#000000" 104 case _: 105 line_color1 = plt.rcParams["figure.facecolor"] 106 line_color2 = plt.rcParams["figure.facecolor"] 107 108 column_color = ["#000080"] * len(df.columns) 109 cell_color = [] 110 for x in range(len(df)): 111 if int(x % 2): 112 cell_color.append([line_color1] * len(df.columns)) 113 else: 114 cell_color.append([line_color2] * len(df.columns)) 115 116 fig = plt.figure( 117 figsize=(8, (len(df) * 0.2) + 0.8), 118 dpi=200, tight_layout=True 119 ) 120 ax_dummy = fig.add_subplot(111) 121 ax_dummy.axis("off") 122 123 plt.title(title, fontsize=12) 124 tb = plt.table( 125 cellText=df.values, 126 colLabels=df.columns, 127 colColours=column_color, 128 cellColours=cell_color, 129 loc="center", 130 ) 131 132 tb.auto_set_font_size(False) 133 tb.auto_set_column_width(range(len(df))) 134 for i in range(len(df.columns)): 135 tb[0, i].set_text_props(color="#FFFFFF", weight="bold") 136 for j in range(len(df) + 1): 137 tb[j, i].set_text_props(ha="center") 138 139 # 追加テキスト 140 remark_text = message.remarks(True) + message.search_word(True) 141 add_text = "[{}] [総ゲーム数:{}] {}".format( # pylint: disable=consider-using-f-string 142 message.item_search_range(None, "time").strip(), 143 game_info["game_count"], 144 f"[{remark_text}]" if remark_text else "", 145 ) 146 147 fig.text( 148 0.01, 0.01, # 表示位置(左下0,0 右下0,1) 149 add_text, 150 transform=fig.transFigure, 151 fontsize=6, 152 ) 153 fig.savefig(report_file_path) 154 plt.close() 155 156 return report_file_path 157 158 159def text_generation(df): 160 """テキストテーブル生成 161 162 Args: 163 df (pd.DataFrame): 描写データ 164 165 Returns: 166 str: 生成ファイルパス 167 """ 168 169 report_file_path = os.path.join( 170 g.cfg.setting.work_dir, 171 f"{g.params["filename"]}.txt" if g.params.get("filename") else "report.txt", 172 ) 173 174 df = df.filter( 175 items=[ 176 "player", "team", 177 "game", "point_sum", "point_avg", 178 "1st_count", "1st_%", 179 "2nd_count", "2nd_%", 180 "3rd_count", "3rd_%", 181 "4th_count", "4th_%", 182 "rank_avg", 183 "flying_count", "flying_%", 184 "yakuman_count", "yakuman_%", 185 ] 186 ) 187 188 fmt = [""] # index分 189 for x in df.columns: 190 match x: 191 case "point_sum" | "point_avg": 192 fmt.append("+.1f") 193 case "1st_%" | "2nd_%" | "3rd_%" | "4th_%" | "flying_%" | "yakuman_%": 194 fmt.append(".2f") 195 case "rank_avg": 196 fmt.append(".2f") 197 case _: 198 fmt.append("") 199 200 df = formatter.df_rename(df) 201 df.to_markdown(report_file_path, tablefmt="outline", floatfmt=fmt) 202 203 return report_file_path 204 205 206def csv_generation(df): 207 """CSV生成 208 209 Args: 210 df (pd.DataFrame): 描写データ 211 212 Returns: 213 str: 生成ファイルパス 214 """ 215 216 report_file_path = os.path.join( 217 g.cfg.setting.work_dir, 218 f"{g.params["filename"]}.csv" if g.params.get("filename") else "report.csv", 219 ) 220 221 df = df.filter( 222 items=[ 223 "player", "team", 224 "game", "point_sum", "point_avg", 225 "1st_count", "1st_%", 226 "2nd_count", "2nd_%", 227 "3rd_count", "3rd_%", 228 "4th_count", "4th_%", 229 "rank_avg", 230 "flying_count", "flying_%", 231 "yakuman_count", "yakuman_%", 232 ] 233 ) 234 235 for x in df.columns: 236 match x: 237 case "point_sum" | "point_avg": 238 df[x] = df[x].round(1) 239 case "1st_%" | "2nd_%" | "3rd_%" | "4th_%" | "flying_%" | "yakuman_%": 240 df[x] = df[x].round(2) 241 case "rank_avg": 242 df[x] = df[x].astype(float).round(2) 243 244 df.to_csv(report_file_path) 245 246 return report_file_path
def
main():
18def main(): 19 """成績一覧表を生成する 20 21 Returns: 22 str: 生成ファイルパス 23 """ 24 25 # 検索動作を合わせる 26 g.params.update(guest_skip=g.params.get("guest_skip2")) 27 28 # --- データ取得 29 game_info: GameInfoDict = aggregate.game_info() 30 df = loader.read_data("report/results_list.sql").reset_index(drop=True) 31 df.index = df.index + 1 32 if df.empty: 33 return False 34 35 if g.params.get("anonymous"): 36 mapping_dict = formatter.anonymous_mapping(df["name"].unique().tolist()) 37 df["name"] = df["name"].replace(mapping_dict) 38 39 # 見出し設定 40 if g.params.get("individual"): 41 title = "個人成績一覧" 42 df = df.rename(columns={"name": "player"}) 43 else: # チーム集計 44 title = "チーム成績一覧" 45 df = df.rename(columns={"name": "team"}) 46 47 # 非表示項目 48 if g.cfg.mahjong.ignore_flying: 49 df = df.drop(columns=["flying_mix", "flying_count", "flying_%"]) 50 if "トビ" in g.cfg.dropitems.report: 51 df = df.drop(columns=["flying_mix", "flying_count", "flying_%"]) 52 if "役満" in g.cfg.dropitems.report: 53 df = df.drop(columns=["yakuman_mix", "yakuman_count", "yakuman_%"]) 54 if "役満和了" in g.cfg.dropitems.report: 55 df = df.drop(columns=["yakuman_mix", "yakuman_count", "yakuman_%"]) 56 57 match str(g.params.get("format", "default")).lower(): 58 case "text" | "txt": 59 file_path = text_generation(df) 60 case "csv": 61 file_path = csv_generation(df) 62 case _: 63 file_path = graph_generation(game_info, df, title) 64 65 return file_path
成績一覧表を生成する
Returns:
str: 生成ファイルパス
68def graph_generation(game_info: GameInfoDict, df, title): 69 """グラフ生成処理 70 71 Args: 72 game_info (GameInfoDict): ゲーム情報 73 df (pd.DataFrame): 描写データ 74 title (str): グラフタイトル 75 76 Returns: 77 str: 生成ファイルパス 78 """ 79 80 df = formatter.df_rename(df.filter( 81 items=[ 82 "player", "team", 83 "game", "total_mix", "avg_mix", "rank_avg", 84 "1st_mix", "2nd_mix", "3rd_mix", "4th_mix", "rank_dist", 85 "flying_mix", "yakuman_mix", 86 ] 87 )) 88 89 report_file_path = os.path.join( 90 g.cfg.setting.work_dir, 91 f"{g.params["filename"]}.png" if g.params.get("filename") else "report.png", 92 ) 93 94 # フォント/色彩設定 95 configuration.graph_setup(plt, fm) 96 plt.rcParams["font.size"] = 6 97 98 match (plt.rcParams["text.color"], plt.rcParams["figure.facecolor"]): 99 case text_color, bg_color if text_color == "black" and bg_color == "white": 100 line_color1 = "#dddddd" 101 line_color2 = "#ffffff" 102 case text_color, bg_color if text_color == "white" and bg_color == "black": 103 line_color1 = "#111111" 104 line_color2 = "#000000" 105 case _: 106 line_color1 = plt.rcParams["figure.facecolor"] 107 line_color2 = plt.rcParams["figure.facecolor"] 108 109 column_color = ["#000080"] * len(df.columns) 110 cell_color = [] 111 for x in range(len(df)): 112 if int(x % 2): 113 cell_color.append([line_color1] * len(df.columns)) 114 else: 115 cell_color.append([line_color2] * len(df.columns)) 116 117 fig = plt.figure( 118 figsize=(8, (len(df) * 0.2) + 0.8), 119 dpi=200, tight_layout=True 120 ) 121 ax_dummy = fig.add_subplot(111) 122 ax_dummy.axis("off") 123 124 plt.title(title, fontsize=12) 125 tb = plt.table( 126 cellText=df.values, 127 colLabels=df.columns, 128 colColours=column_color, 129 cellColours=cell_color, 130 loc="center", 131 ) 132 133 tb.auto_set_font_size(False) 134 tb.auto_set_column_width(range(len(df))) 135 for i in range(len(df.columns)): 136 tb[0, i].set_text_props(color="#FFFFFF", weight="bold") 137 for j in range(len(df) + 1): 138 tb[j, i].set_text_props(ha="center") 139 140 # 追加テキスト 141 remark_text = message.remarks(True) + message.search_word(True) 142 add_text = "[{}] [総ゲーム数:{}] {}".format( # pylint: disable=consider-using-f-string 143 message.item_search_range(None, "time").strip(), 144 game_info["game_count"], 145 f"[{remark_text}]" if remark_text else "", 146 ) 147 148 fig.text( 149 0.01, 0.01, # 表示位置(左下0,0 右下0,1) 150 add_text, 151 transform=fig.transFigure, 152 fontsize=6, 153 ) 154 fig.savefig(report_file_path) 155 plt.close() 156 157 return report_file_path
グラフ生成処理
Arguments:
- game_info (GameInfoDict): ゲーム情報
- df (pd.DataFrame): 描写データ
- title (str): グラフタイトル
Returns:
str: 生成ファイルパス
def
text_generation(df):
160def text_generation(df): 161 """テキストテーブル生成 162 163 Args: 164 df (pd.DataFrame): 描写データ 165 166 Returns: 167 str: 生成ファイルパス 168 """ 169 170 report_file_path = os.path.join( 171 g.cfg.setting.work_dir, 172 f"{g.params["filename"]}.txt" if g.params.get("filename") else "report.txt", 173 ) 174 175 df = df.filter( 176 items=[ 177 "player", "team", 178 "game", "point_sum", "point_avg", 179 "1st_count", "1st_%", 180 "2nd_count", "2nd_%", 181 "3rd_count", "3rd_%", 182 "4th_count", "4th_%", 183 "rank_avg", 184 "flying_count", "flying_%", 185 "yakuman_count", "yakuman_%", 186 ] 187 ) 188 189 fmt = [""] # index分 190 for x in df.columns: 191 match x: 192 case "point_sum" | "point_avg": 193 fmt.append("+.1f") 194 case "1st_%" | "2nd_%" | "3rd_%" | "4th_%" | "flying_%" | "yakuman_%": 195 fmt.append(".2f") 196 case "rank_avg": 197 fmt.append(".2f") 198 case _: 199 fmt.append("") 200 201 df = formatter.df_rename(df) 202 df.to_markdown(report_file_path, tablefmt="outline", floatfmt=fmt) 203 204 return report_file_path
テキストテーブル生成
Arguments:
- df (pd.DataFrame): 描写データ
Returns:
str: 生成ファイルパス
def
csv_generation(df):
207def csv_generation(df): 208 """CSV生成 209 210 Args: 211 df (pd.DataFrame): 描写データ 212 213 Returns: 214 str: 生成ファイルパス 215 """ 216 217 report_file_path = os.path.join( 218 g.cfg.setting.work_dir, 219 f"{g.params["filename"]}.csv" if g.params.get("filename") else "report.csv", 220 ) 221 222 df = df.filter( 223 items=[ 224 "player", "team", 225 "game", "point_sum", "point_avg", 226 "1st_count", "1st_%", 227 "2nd_count", "2nd_%", 228 "3rd_count", "3rd_%", 229 "4th_count", "4th_%", 230 "rank_avg", 231 "flying_count", "flying_%", 232 "yakuman_count", "yakuman_%", 233 ] 234 ) 235 236 for x in df.columns: 237 match x: 238 case "point_sum" | "point_avg": 239 df[x] = df[x].round(1) 240 case "1st_%" | "2nd_%" | "3rd_%" | "4th_%" | "flying_%" | "yakuman_%": 241 df[x] = df[x].round(2) 242 case "rank_avg": 243 df[x] = df[x].astype(float).round(2) 244 245 df.to_csv(report_file_path) 246 247 return report_file_path
CSV生成
Arguments:
- df (pd.DataFrame): 描写データ
Returns:
str: 生成ファイルパス