How to iterate over an Excel file and ID colored cell values - openpyxl

I have an excel workbook that has cells of a column colored with specific colors to keep or exclude certain users that will then be used to filter another excel workbook.
I want to loop through this column and identify cells with red background and add a functional column stating 0 and identify cells with yellow background and add 1 to this same functional column so as to work as the filter for the other workbook.
I'm hoping to use OpenPyXL to complete this task.
column_pi = ws["A"]
for cell in column_pi:
f cell.fill.fgColor == "00FF0000": # Red Hex
# add column stating 0 as value
Have also tried this but no luck, returning nothing
red_fill = PatternFill(fill_type=None, start_color='00FF0000', end_color='00FF0000')
yellow_fill = PatternFill(fill_type=None, start_color='00FFFF00', end_color='00FFFF00')
for cell in column_pi:
if cell.fill == yellow_fill:
print(cell)
Works with no hex codes provided for no_fill
no_fill = PatternFill(fill_type=None)
for cell in column_pi:
if cell.fill == no_fill:
print(cell)
Any thoughts on the best way to iterate over the values and check the fill/background color are of a specific color and then add a functional column like this?

fill is a set of more complicated variables, so looking for it to be exactly equal only to red_fill or yellow_fill here isn't going to work. The complication is mostly due to being able to set a colour either as a static rgba value, or as one that will automatically update when the theme is changed. Styles in openpyxl, with parameters like PatternFill, are easy ways to set multiple of these values at once.
If you look up cell.fill for a particular cell, it returns something like:
<openpyxl.styles.fills.PatternFill object>
Parameters:
patternType='solid', fgColor=<openpyxl.styles.colors.Color object>
Parameters:
rgb='FFD9D9D9', indexed=None, auto=None, theme=None, tint=0.0, type='rgb', bgColor=<openpyxl.styles.colors.Color object>
Parameters:
rgb='00000000', indexed=None, auto=None, theme=None, tint=0.0, type='rgb'
You can specify these values directly as part of cell.fill.fill_type (synonym for cell.fill.patternType), cell.fill.fgColor, and cell.fill.bgColor. Plus sub-attributes like cell.fill.fgColor.rgb.
You could also make it quicker by picking knowncell.fill.fgColor of a cell you know to have red_fill, if one exists. That way, you could check any of fill_type, fgColor and/or bgColor match. Try:
red_fill = knowncell.fill
for cell in column_pi:
if cell.fill.fgColor == red_fill.fgColor and cell.fill.fill_type == red_fill.fill_type:
print(cell)
However, you can't match knowncell.fill directly with cell.fill, I think because a new openpyxl style object is created each time you define a new one.

Related

Using Epplus to read spreadsheet and determine all the cell's style, including conditionally format

I am using Epplus (C#.net) to read the values and the styling of cells(background and font color) in a spreadsheet, that is protected and locked.
Style.Fill.BackgroundColor.Rgb; Style.Fill.BackgroundColor.Theme and Style.Font.Color.Rgb; Style.Font.Color
work correctly in most of the cells. I am running into a problem with cells that are using the conditional format 'Format only unique or duplicate values'. Background and Font colors are being returned from Epplus as null.
Here is the code to get the background/font color from a particular cell
private ExcelStyleLoad GetStyleInfo(ExcelRange currentCell)
{
ExcelStyleLoad retval = new ExcelStyleLoad();
//background
retval.BackgroundColor = currentCell.Style.Fill.BackgroundColor.Rgb;
retval.BackgroundTheme = currentCell.Style.Fill.BackgroundColor.Theme;
//font
retval.FontColor = currentCell.Style.Font.Color.Rgb;
retval.FontTheme = currentCell.Style.Font.Color.Theme;
//other
retval.isBold = currentCell.Style.Font.Bold;
retval.isUnderline = currentCell.Style.Font.UnderLine;
retval.isItalics = currentCell.Style.Font.Italic;
retval.FullAddress = currentCell.FullAddress;
return retval;
}
I have also tried to use currentCell.ConditionalFormatting.AddDuplicateValues() to determine the background/font color and have had no success.
Any suggestions how I can get the background/font color of the cells that are using the ConditionalFormatting?
In my understanding, cells with conditional formatting do not (necessarily) have a backgroundcolor, they just have the conditional formatting rule. The background colour is infered from the value and the rule when the sheet is being displayed.
This meets your observation.
So you will have to look for conditional formatting in the cells and calculate the colour values yourself when reading the formatting. That's little hope in your case where the sheet is protected and locked.
Anyway, you should be able to determine unique / duplicate cells even in protected and locked sheets. Good luck!

VBA for changing font and colour of a cell if a certain word is typed in it

I have a somewhat large spreadsheet with a type of summary page that follows a calender layout.
On this page I manually change the font and color of cells to make it easy for me to find certain things on it. For example, (I lecture mathematics) if I have revision on a certain lesson, I make that cell bold and green. (exact type of green I can sort out myself). I want a VBA code if possible so that if I type the word revision into a cell on that sheet only, not whole workbook, that it would automatically change it to green.
Realistically, I don't manually type in the word revision always. Some of it uses lookups of various types to find what happens on that day to display a word (for example revision) in that given cell.
I don't know if this is possible to do. I realize that if "revision" is shown due to a lookup then the contents of that cell is not equal to "revision" but a formula which simply displays "revision"
Any assistance would be appreciated. If I have a basic code I can manipulate to get it right.
Thanks
Maybe you're looking for something along the lines of:
Sub CheckRevision()
Dim CurCell As Object
For Each CurCell In ActiveWorkbook.ActiveSheet.Range("A1:AZ500")
If CurCell.Value = "Revision" Then CurCell.Interior.Color = RGB(0,204,0)
Next
End Sub
Or equivalently, you can probably use conditional formatting. Home Tab > Conditional Formatting > Highlight Cells Rules > Text that Contains. From there, type the value "Revision" into the value box and you can change the format of the cell to how you like it.

Number to be copied from cell with the same number format and show it as a label for a shape without any change in the number format

I have a cell in excel which contains a value, lets say 100000.
Now i want this value to have commas in between them to represent the thousands and millions i.e. 100,000. I can do this by changing the number format in the home menu.
Now i want this value to be copied from that cell and paste it as a label for a shape. When i am doing this the commas go away showing me just the numbers.
I want it to happen through VBA but this is not happening in excel itself.
Does anyone have a plausible solution for this?
In range object use Text property, like this:
Sheet1.Shapes(1).TextFrame.Characters.Text = Range("A1").Text

Change #N/A to Blank cell

How can I change the #N/A to the blank cell if nothing in that cell?
Eg. =VLOOKUP(B19:B36;$TABLE.A1:C46;2;0)
I think I might need something like an ISERROR check but I don't 100% know what I'm doing.
If we're talking about Excel 2010 and later you can use IFERROR:
=IFERROR(VLOOKUP(B19:B36;$TABLE.A1:C46;2;0);"")
You can also put text into the final string result
The question was misleading about the spreadsheet software as 2 different spreadsheets were originally stated in tags. However, it can be seen that the question is about OpenOffice Calc:
- Absolute sheet referencing ($ sign before the sheet name) is not possible in Excel.
- We also see a dot between the sheet name and the range, which is again not possible in Excel.
As in OpenOffice Calc you don't have IFERROR function, the only way is to repeat your main function twice in the following form (you can use both, ISNA and ISERROR, but I suggest ISNA as it's more specific and fits your case):
=IF(ISNA(YourFormula);"";YourFormula)
In your case something like:
=IF(ISNA(VLOOKUP(B19;$TABLE.A1:C46;2;0));"";VLOOKUP(B19;$TABLE.A1:C46;2;0))
You may want to make absolute reference to the range where you look for matching values, as I see you want to copy the formula down.
=IF(ISNA(VLOOKUP(B19;$TABLE.$A$1:$C$46;2;0));"";VLOOKUP(B19;$TABLE.$A$1:$C$46;2;0))
Since the cells will contain a formula this is about appearances, so Conditional formatting might suit, say if the cell background is white, for style choose Font > Font Effects > Font color white.
For this, select the relevant range - I have assumed D19:D36 - and Format > Conditional Formatting... and for Condition 1 choose Cell value is and equal to and:
ISNA(D19)

In Apache POI HSSF, Cell Type Still Shows Up as "General" Excel, Even Though it's Number-Formatted

I am using Apache POI HSSF to generate an Excel spreadsheet from my Java Web app.
I need a cell formatted as "Number" with 2 decimal points. (My values in Java are BigDecimals, but I can convert them to doubles, no problem.) I am using this code:
CellStyle numericStyle = wb.createCellStyle();
numericStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0.00"));
// output in this new style...
row.createCell(cellnum).setCellValue(((BigDecimal)value).doubleValue());
row.getCell(cellnum).setCellStyle(numericStyle);
The issue is that, even though this works, Excel still shows my cells as General. They need to be shown as Number. As a result, for example, 0 is shown as 0, but it should be 0.00, which would happen if the format was correct (Number).
I see that it gets generated as General because I can right-click on a cell and then choose "Format Cells" to see what it is right now. It needs to be set to "Number" by Apache POI HSSF.
Reviewing the Apache POI API it looks like you should be able to specify the cell's type.
...
Cell cell = row.createCell(...);
cell.setCellType(Cell.CELL_TYPE_NUMERIC);
...
I'm assuming you haven't yet found an answer for your question.
One way to display numbers with two decimals is to set a cell style. This allows you to customize the number of decimal places and the decimal separator, among other things.
protected CellStyle getCellStyle(HSSFWorkbook workbook) {
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setDataFormat(
workbook.getCreationHelper().createDataFormat().getFormat("#,##0.00"));
return cellStyle;
}
Later on, when you fill your workbook, you apply this cellStyle to the desired cells:
CellStyle cellStyle = getCellStyle();
//...
// create your cell
cell.setCellStyle(cellStyle);
// set the value
It won't show as numeric type in Excel. It shows as Custom type. But visually it should be the same, or at least close enough.