LoginSignup
3
1

More than 1 year has passed since last update.

【Excel + Python】セルの値が変わったタイミングで色付けして読みやすくする

Last updated at Posted at 2021-10-04

概要

以下のような Excel ファイルを、

以下のように色付けし、1つ上のセルと比較して変更されている箇所を分かりやすくしたい。

実行イメージ (ゴール)

excel-color.gif

Python バージョン

3.8.2

実行手順

  1. venv などで仮想環境を構築する
  2. pip install -r requirements.txt
  3. 対象とする Excel ファイルを開く
  4. python main.py
    1. 引数として all を渡す: アクティブブック内の全てのシートに対して適用する
    2. 引数を渡さない: アクティブブック内のアクティブシートのみに適用する

コード

requirements.txt

xlwings
xlsxwriter

settings.py

import xlwings as xw
from xlsxwriter.utility import xl_col_to_name


# 1つ上のセルと値が違う際に使用する背景色 (RGB)
background_color = (252, 228, 214)
# 1つ上のセルと値が同じ際に使用する文字色 (RGB)
font_color = (191, 191, 191)


def make_target_cell_range(sheet: xw.Sheet) -> str:
    """
    実行対象とするセルの範囲を 'A1:C5' のような形式の文字列で返す
    Excel ファイルの内容に応じて処理を修正する必要あり
    """
    # 列の開始と終了地点のアルファベットを取得
    start_col_alphabet = None
    end_col_alphabet = None
    for cell in sheet.used_range:
        if cell.value == '操作':
            start_col_alphabet = xl_col_to_name(cell.column - 1)
        if cell.value == '想定結果':
            end_col_alphabet = xl_col_to_name(cell.column - 2)
            break

    # 行の開始と終了地点の番号を取得
    a_col_values = list(map(lambda a: a.value, sheet.used_range.columns[0]))
    a_col_nums = list(filter(lambda a: isinstance(a, float), a_col_values))
    min_num = min(a_col_nums)
    max_num = max(a_col_nums)
    start_row_num = a_col_values.index(min_num) + 1
    end_row_num = a_col_values.index(max_num) + 1

    # 列のアルファベットと行番号を 'A1:C5' のように形に連結して返す
    return start_col_alphabet + str(start_row_num) + ':' + end_col_alphabet + str(end_row_num)

main.py

from settings import *
import xlwings as xw
import sys


def sheet_to_readable(
    sheet: xw.Sheet,
    range_str: str,
):
    """
    エクセルの1シートと、対象とするセルの範囲を受け取り、色付けして読みやすくする
    :param sheet: Excel ファイルの1シート
    :param range_str: 実行対象とするセルの範囲。例: 'A1:C5'
    """
    for col in sheet.range(range_str).columns:
        # 1つ上のセルの値
        prev_value = None

        for cell in col:
            # 背景色をリセット
            if cell.color == background_color:
                cell.color = None
            # 文字色をリセット
            if cell.font.color == font_color:
                cell.font.color = (0, 0, 0)

            value = cell.value
            if (value != prev_value) and (value is None):
                pass
            elif value != prev_value:
                cell.color = background_color
            else:
                cell.font.color = font_color

            prev_value = value


def main():
    # Excel ファイルが開かれていない場合は処理を終える
    if len(xw.books) <= 0:
        print('対象とする Excel ファイルを開いてから再度実行してください。')
        return

    # 受け取った引数内に 'all' という文字列が含まれている場合、
    # アクティブブック内の全てのシートに適用する
    if (len(sys.argv) >= 2) and ('all' in sys.argv[1]):
        book = xw.books.active
        for sheet in book.sheets:
            sheet.activate()
            sheet_to_readable(sheet, make_target_cell_range(sheet))

    # アクティブブック内のアクティブシートのみに適用する
    else:
        sheets = xw.sheets
        sheet = sheets.active
        sheet.activate()
        sheet_to_readable(sheet, make_target_cell_range(sheet))

    print('🚀 Success')


if __name__ == '__main__':
    main()
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1