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: 生成ファイルパス

def graph_generation(game_info: cls.types.GameInfoDict, df, title):
 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: 生成ファイルパス