Python and Openpyxl - available attributes to format individual cells - python-3.x

I've looked over the Openpyxl docs, styles, cell module, and source code, but I'm not seeing what I need. Maybe I missed it (as new to Python).
I need to format certain cells within a spreadsheet(ss) differently from the rest of the ss. Am I able to specify an individual cell as shrink-to-fit, align right, align bottom, font color = grey, etc., while keeping the rest of the SS in the original style? Is this a Cell style that should be set or is there another resource to see what attributes Openpyxl will allow on an individual cells?
Here's a code snippet where the 'al' variable is working, but not the 'br', and I don't know why.
# Cell Alignment
al = Alignment(horizontal='center', vertical='center')
br = Alignment(horizontal='right', vertical='bottom')
for row in sheet['A1':'I43']:
for cell in row:
if cell == 'Hz':
cell.alignment = br #Help: not working
else:
cell.alignment = al
Thanks,
Phil

Ok, I think I've got it. So far, I'm accomplishing individual cell formatting using the NamedStyle object.
Here is my code:
# Set 'Named Styles', which are mutable, when need to apply formatting to different cells at once
headerrows = NamedStyle(name='headerrows')
headerrows.font = Font(bold=True, underline='none', sz=12)
headerrows.alignment = al
rooms = NamedStyle(name="rooms")
rooms.font = Font(bold=True, size=12)
rooms.border = Border(left=bold, top=bold, right=bold, bottom=bold)
sheet['A1'].style = rooms
sheet['A2'].style = headerrows
sheet['A3'].style = 'headerrows'
sheet['A4'].style = 'rooms'

Related

Get Excel Sheet Direction with Xlrd

How can check the excel sheet direction with python?. my mean is Left_to_Right or Right_to_Left.
You need to load the workbook using formatting_info parameter like below.
wb = xlrd.open_workbook("table.xls", formatting_info=True)
You can then use wb.xf_list attribute to retrieve formatting information like text_direction. Each cell in the workbook will have have an xf_index attribute allowing you to retrieve corresponding information in the wb.xf_list.
According to the documentation, these are the possible values for the text_direction attribute.
0 = according to context; 1 = left-to-right; 2 = right-to-left

Update an Excel style in VBA

My Excel macro reads the answers to a survey from a set of Excel files. The answers of a survey contain a score (from 1 to 4) and a description. The goal is to generate a a matrix. Each cell of the matrix has a color that represents the score. I would like the user to be able to modify the layout of these cell. To make it easy to the user, I created a template matrix and a button. The user should be able to modify the layout of the cells and on a click of a button, a set of styles (Score 1, Score 2,...) should be generated. Once the matrix is created, the Workbook should be to function without the survey files.
I have tried a couple of things:
Try 1
ThisWorkbook.Styles.Add "Score 1", BasedOn:=cell1
This gives errors. I don't fully understand when they occur, but one of the causes is when the user modifies the cell layout by selecting another style.
Try 2
ThisWorkbook.Styles("Score 1").Delete
ThisWorkbook.Styles.Add "Score 1", BasedOn:=cell1
This is not a good idea: all cells loose their styling when it is executed a second time.
Try 3: Current
Copy the most frequently used properties of the cells layout and copy them to the style. If this style is deleted by the user, it is recreated. This procedures is not ideal, since most style properties won't be covered.
Is there a way to update a cell style that is more general? I would like there to be as little room as possible to make the workbook in an inconsistent and non-functional state.
I sticked with try 3. Because it required a lot of code for all properties that seemed possible to be edited, and because of copying borders is tricky, I post the result.
'xR1_Template: the cell to base the style on
'nm_Style: the name of the style
Public Function Upsert_Style(xR1_Template As Excel.Range, nm_Style As String) As Excel.Style
Dim xStyle As Excel.Style
Set xStyle = Fn.TryGet(ThisWorkbook.Styles, nm_Style)
If Fn.IsNothing(xStyle) Then
Set xStyle = ThisWorkbook.Styles.Add(nm_Style)
End If
xStyle.Font.Color = xR1_Template.Font.Color
xStyle.Font.Bold = xR1_Template.Font.Bold
xStyle.Font.Name = xR1_Template.Font.Name
xStyle.Font.Italic = xR1_Template.Font.Italic
xStyle.Font.Size = xR1_Template.Font.Size
xStyle.Font.Strikethrough = xR1_Template.Font.Strikethrough
xStyle.Font.Subscript = xR1_Template.Font.Subscript
xStyle.Font.Superscript = xR1_Template.Font.Superscript
xStyle.Font.Underline = xR1_Template.Font.Underline
xStyle.Interior.Color = xR1_Template.Interior.Color
xStyle.Interior.Pattern = xR1_Template.Interior.Pattern
xStyle.Interior.PatternColor = xR1_Template.Interior.PatternColor
'NOTE: necessary to delete all borders first. There's no way to delete them one by one.
xStyle.Borders.LineStyle = xlNone
Dim iBorder As Long
For iBorder = 1 To xR1_Template.Borders.Count
Dim xBorder As Excel.Border
'NOTE: The Borders property claims to work with xlBordersIndex argument, but this is not true.
' Normal indexing is used.
Set xBorder = xR1_Template.Borders(iBorder)
'NOTE: "none-style" borders (=no border), should be skipped.
' Once they are retrieved using the Borders property, they are always visible.
' Setting them with xlLineStyle.xlLineStyleNone does not hide them.
If xBorder.LineStyle <> XlLineStyle.xlLineStyleNone Then
Dim xBorder_Style As Excel.Border
Set xBorder_Style = xStyle.Borders(iBorder)
xBorder_Style.Color = xBorder.Color
xBorder_Style.LineStyle = xBorder.LineStyle
xBorder_Style.Weight = xBorder.Weight
End If
Next iBorder
xStyle.AddIndent = xR1_Template.AddIndent
xStyle.FormulaHidden = xR1_Template.FormulaHidden
xStyle.HorizontalAlignment = xR1_Template.HorizontalAlignment
xStyle.IndentLevel = xR1_Template.IndentLevel
xStyle.NumberFormat = xR1_Template.NumberFormat
xStyle.NumberFormatLocal = xR1_Template.NumberFormatLocal
xStyle.Orientation = xR1_Template.Orientation
xStyle.ShrinkToFit = xR1_Template.ShrinkToFit
xStyle.VerticalAlignment = xR1_Template.VerticalAlignment
xStyle.WrapText = xR1_Template.WrapText
xStyle.IndentLevel = xR1_Template.IndentLevel
Set Upsert_Style = xStyle
End Function

How can I stop python-docx from inserting a carriage return before my cell text

I want a paragraph inside a cell, but I get a stray carriage return which pushes down the text by one line:
My code:
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Cm
document = Document()
document.add_heading("The Heading", 1).alignment = WD_ALIGN_PARAGRAPH.CENTER
table = document.add_table(rows=0, cols=2)
table.style = 'Table Grid'
for i in range(3):
row_cells = table.add_row().cells
row_cells[0].text = 'row {}, col 1'.format(i)
row_cells[0].width = Cm(3)
row_cells[1].width = Cm(8)
p = row_cells[1].add_paragraph()
p.add_run('This is an example of')
p.add_run(' some text').bold = True
p.add_run(' in a table cell.')
document.save('test.docx')
How can I get the cell text to align at the top of the cell without the stray CR? And how should I be setting the cell widths to 3 cm and 8 cm: setting _Cell.width isn't respected.
I worked this out: you get a free paragraph with each cell, so I just needed to add my text runs to this paragraph:
p = row_cells[1].paragraphs[0]
p.add_run('This is an example of')
p.add_run(' some text').bold = True
p.add_run(' in a table cell.')
To set the widths, I had to manipulate the columns directly and not set them cell-by-cell (despite this answer):
table.columns[0].width = Cm(3)
table.columns[1].width = Cm(8)
Tanks for the clear_content it made my image not to be placed beneath a linefeed, tanks for the coment, it was the last pice of advice I needed after hours of problemsolving:
#This seams to clear the content in my cell
tables[1].rows[0].cells[4]._element.clear_content()
#Then when the image is inserted to the cell it is not placed one linefeed down.
img = tables[1].rows[0].cells[4].add_paragraph().add_run().add_picture('AgressoLogga.png', width=Inches(0.4))

Format individual characters in a single Excel cell with python

I am using xlrd, xlwt, and xlutils on the Windows Vista OS with Python 2.7. I have a set of DNA sequences in an excel worksheet that are 100 characters long, with each sequence in a single cell. I am trying to highlight characters at specific positions within each of these sequences in excel (bold them or change color), but have not found a way to format individual characters within a cell. Applying a style applies it to the entire cell to my knowledge. Therefore I am trying to break the sequences down into individual components where some parts of the sequence will be modified with a style while others won't, and to then collate these back together into a single string in a single cell.
Code:
rb = open_workbook('Mybook', formatting_info=True)
rs = rb.sheet_by_index(0)
wb = copy(rb)
ws = wb.get_sheet(0)
minus35style = xlwt.easyxf('font: bold 1') # style I'd like for just one character
for b in range(0, 368, 1):
rscellin = rs.cell(b,9)
f = rscellin.value
tominus35 = str(f[0:34])
minus35 = str(f[35:36])
ws.write(b, 14, tominus35)
ws.write(b, 14, minus35, minus35style)
wb.save('Mybook')
My problem is that adding a style changes the whole cell, and I want just certain characters to be modified. Additionally, subsequent writing to the same cell overwrites what was there previously. Is there a way to modify individual characters in a single cell, or to add differently formatted text to an existing cell that already has text in it?
Please let me know if you require additional information that I've overlooked. I appreciate your time in advance.
Brett
Recent versions of xlwt include the ability to use Rich Text within a cell. Where normally you would use ws.write, use ws.write_rich_text instead. The first two parameters are the row index and column index, as usual; but the next parameter is a sequence of components. Each component can either be a "naked" text value or a (text, font) pair. The naked text values will use the font from the cell's overall style, which can be specified using the optional fourth parameter.
For the (text, font) pairs, it is simplest to generate fonts using the new easyfont feature, which is kind of like easyxf but only for fonts. Here is an example:
import xlwt
wb = xlwt.Workbook()
ws = wb.add_sheet('Sheet1')
font0 = xlwt.easyfont('')
font1 = xlwt.easyfont('bold true')
font2 = xlwt.easyfont('color_index red')
style = xlwt.easyxf('font: color_index blue')
seg1 = ('bold', font1)
seg2 = ('red', font2)
seg3 = ('plain', font0)
seg4 = ('boldagain', font1)
ws.write_rich_text(2, 5, (seg1, seg2, seg3, seg4))
ws.write_rich_text(4, 1, ('xyz', seg2, seg3, '123'), style)
wb.save('rich_text.xls')
You should be able to adapt the above for your purposes. Note that you still have to write or overwrite the whole cell at once; you can't go back and update only part of a cell later.

Importing a list from excel, but having trouble splitting it into 4 columns

I know this is very basic, but I have been using Python for 2 weeks now and banging my head against the wall trying to fix this. I have checked almost every single thread in here and tried to make sense of the Python 2.7 documentation and also researched whatever excerpts from Programming with Win32 by Hammod I could find.
Below is a section of my code. I am pulling in a named range from excel into a Python Gui. The data comes into row=4, column=1 as I coded it. The problem is I need to parse this named range so that the range (which is four float points) is split amongst row=4 clomuns 1,2,3,4. I know this is basic. I wouldnt have posted if I could find the answer anywhere else. If someone could just point me in the right direction i would really appreciate it.
xl = win32com.client.Dispatch('excel.application')
wbs = xl.Workbooks
wb = wbs.Open('C:\Users\Owner\Desktop\AutoPrime.xls')
xl.visible = 1
xlSheet = xl.Sheets(1)
xlSheet.Range('Fronts').Value
#Frame
Ftreas = Frame(F, relief="groove", border=2)
Ftreas.pack(side="left")
lp2a = Label(Ftreas, text=xl.ActiveSheet.Range('Fronts').Value, justify='center')
lp2a.grid(row=4,column=1, sticky='EW')
While I have not worked with Phyton before, I know that your line xlSheet.Range('Fronts') will return a Range object. You can access individual cells of a Range object with the default property, e.g.:
rng = xlSheet.Range('Fronts')
val1 = rng(1, 1).Value
val2 = rng(2, 1).Value //this returns the cell in row 2/column 1 of the range
arr = rng.Cells //this will return a 4x1 array of values

Resources