BBorisov95
BBorisov95

Reputation: 61

Python openpyxl blank cells conditional formating

I have a problem with formating blank cells. My code is

import setting_prices
import pandas as pd
from openpyxl import Workbook, load_workbook
from openpyxl.styles import Color, PatternFill, Font, Border
from openpyxl.styles.differential import DifferentialStyle
from openpyxl.formatting.rule import ColorScaleRule, CellIsRule, FormulaRule
import os
from datetime import datetime


def load_file_apply_format():

    wb = load_workbook(filename)
    writer = pd.ExcelWriter(filename, engine='openpyxl')
    writer.book = wb
    prices.to_excel(writer, sheet_name=today_as_str)
    ws = wb[today_as_str]

    redFill = PatternFill(start_color='EE1111',
                              end_color='EE1111',
                              fill_type='solid')
    # whiteFill = PatternFill(start_color='FFFFFF',
    #                           end_color='FFFFFF',
    #                           fill_type='solid')


    ws.conditional_formatting.add('B2:H99',
                                      CellIsRule(operator='lessThan',
                                                 formula=['$I2'],
                                                 stopIfTrue=False, fill=redFill))
    

    writer.save()


prices = setting_prices.df

today_as_str = datetime.strftime(datetime.now(), ' %d_%m_%y')
desktop_path = os.path.expanduser("~/Desktop")

filename = 'price_check.xlsx'


if os.path.exists(filename):
    load_file_apply_format()
else:
    prices.to_excel(filename, sheet_name=today_as_str)
    load_file_apply_format()

My formula works just fine, but excel treats blanks cells as 0 therefore they are always less than column I, and formats them. I would like to skip blank cells, or to format them to looks like regular cells.

I have tried almost all suggestions from the forum but seems like that I'm not able to fix it.

Please give me some suggestions.

@Greg answer for using :

   ws.conditional_formatting.add('B2:H99',
                                  CellIsRule(operator='between',
                                             formula=['1', '$I2'],
                                             stopIfTrue=False, fill=redFill))

results in formating cells which are == to 'I' column which I want to avoid. Also 'between' is setting format to all blank cells if cell in 'I' column is empty.

Example picture

For example: All cells for productA must be default formated because they are equal to cell in column 'I'. For productB the only formatted cell must be G3 because is lower then I3. All cells for productC must be default formatted because cell in I is empty.

I thought that if I use my formatting code for lessThen, and another formula for blanks cells would do the work. But I was not able to make it work.

Upvotes: 2

Views: 1962

Answers (1)

BBorisov95
BBorisov95

Reputation: 61

I manage to fix my issue with the try/error method. I will post my solution here and hope that someone will find it usefull. The final result is made by:

  1. Placeing all cells from row to a list
  2. Compare all values from the list with the desired one
  3. IF the cell is lower -> apply formating

The final code is:

import ...



def apply_format_to_cell(cell):

    """
    Set background and font color For the current cell
    """

    ft = Font(color="FF0000")
    fill_black = PatternFill(bgColor="FFC7CE", fill_type="solid")

    cell.font = ft
    cell.fill = fill_black

    return cell


def open_existing_file(file_name):
    """
    open an existing file to format cell
    which is meeting a condition
    """

    wb = load_workbook(file_name)
    writer = pd.ExcelWriter(file_name, engine='openpyxl')
    writer.book = wb
    prices.to_excel(writer, sheet_name=today_as_str)
    ws = wb[today_as_str]

    for row in ws.iter_rows(2, ws.max_row, 2):
        """
        1st parameter says to start from 2 row 
        2nd parameter stands for -> till the last row with data. 
        3th parameter says start from 2 COLUMN. 
            In this case this is B2
        """
        cells_in_row = []  # making a list of cells which we will compare
        for cells in row:
            cells_in_row.append(cells)
        for cell in cells_in_row:
            if cell.value is not None and type(cell.value) is not str \
                    and cells_in_row[-1].value is not None and type(cells_in_row[-1].value) is not str:
                """
                Checks if the cell value is not Empty or str ( '' ).
                """

                if cell.value < cells_in_row[-1].value:
                    apply_format_to_cell(cell)
    if wb[f'{today_as_str + "1"}']:
        """
        For the first run only!
        Because: prices.to_excel(writer, sheet_name=today_as_str) will make again sheet
        with the same name -> Excel will put '1' at the end of name 'Sheet_name' > 'Sheet_name1'
        This if will delete this unwanted sheet!
        """
        del wb[f'{today_as_str + "1"}']

    writer.save()


prices = setting_prices.df  # import df with prices

today_as_str = datetime.strftime(datetime.now(), ' %d_%m_%y')
desktop_path = os.path.expanduser("~/Desktop")

filename = 'price_check.xlsx'


if os.path.exists(filename):
    open_existing_file(filename)
else:
    prices.to_excel(filename, sheet_name=today_as_str)
    open_existing_file(filename)

Example of the final result: Final result example

Upvotes: 2

Related Questions