Formula Cell Wont Update Openpyxl - python

I fill the cells I need, then I set the total formula. It works right in one column, with normal numbers, but in the column with times (hh:mm:ss) the total cell is not being updated. If i manually change a cell, then it will be computed to the total. I dont know why this happens.
excel sheet:
The G column total cell (Qt_horas) has the formula, but it does not apply via openpyxl
the code:
df = pd.read_excel('Status Report Coagril 20-04-2022.xlsx', 'Acompanhamento Solics. Projeto')
planilha = load_workbook('Status Report Coagril 20-04-2022.xlsx', data_only=True)
ws = planilha['Acompanhamento Solics. Projeto']
start = 17
for i, nr_solic in enumerate(sols_filhas):
query_sol = f"select nr_solicitacao, ds_assunto, st_solic, ds_status from solicservico_v2 a, statussolic b where a.nr_solicitacao = {nr_solic} and a.st_solic = b.cd_status"
query = db.query(query_sol)
# atribuo as variaveis que vieram da query do banco
nr_solicitacao = query['nr_solicitacao'].values[0]
ds_assunto = query['ds_assunto'].values[0]
ds_status = query['ds_status'].values[0]
horas_realizadas = formata_horas(db.query(f'SELECT retorna_min_realizados_solic({nr_solicitacao})/60 minutos FROM DUAL')['minutos'].values[0])
# verifico se alguma das células que estou preenchendo, foi erroneamente mergeada com as coluna E ou F, e então desfaço o merge
e_merged = f'B{start+i}:E{start+i}'
f_merged = f'B{start+i}:F{start+i}'
lista = str(ws.merged_cells).split(' ')
if e_merged in lista:
ws.unmerge_cells(e_merged)
if f_merged in lista:
ws.unmerge_cells(f_merged)
# insiro uma nova linha, a não ser que seja o primeiro registro, pois já há uma linha em branco
# if i != 0:
# ws.insert_rows(start+i)
ws.insert_rows(start+i)
# preenche_linha(ds_assunto, 'B', start+1, 'left', 'no_right', ws)
# preenche_linha(None, 'C', start+1, 'left', 'no_left', ws)
# preenche_linha(nr_solicitacao, 'D', start+1, 'center', 'total', ws)
# preenche_linha(ds_status, 'E', start+1, 'center', 'total', ws)
# preenche_linha(1, 'F', start+1, 'center', 'total', ws)
# preenche_linha(horas_realizadas, 'G', start+1, 'center', 'total', ws)
# preenche_linha('Maxicon', 'H', start+1, 'center', 'total', ws)
ws[f'B{start+i}'] = ds_assunto
ws[f'B{start+i}'].alignment = Alignment(horizontal='left')
ws[f'B{start+i}'].border = aplica_borda_sem_direita()
ws[f'C{start+i}'].border = aplica_borda_sem_esquerda()
ws[f'D{start+i}'] = nr_solicitacao
ws[f'D{start+i}'].alignment = Alignment(horizontal='center')
ws[f'D{start+i}'].border = aplica_borda_total()
ws[f'E{start+i}'] = ds_status
ws[f'E{start+i}'].alignment = Alignment(horizontal='center')
ws[f'E{start+i}'].border = aplica_borda_total()
ws[f'F{start+i}'] = 1
ws[f'F{start+i}'].alignment = Alignment(horizontal='center')
ws[f'F{start+i}'].border = aplica_borda_total()
ws[f'G{start+i}'].number_format = 'h:mm:ss'
ws[f'G{start+i}'] = horas_realizadas
ws[f'G{start+i}'].border = aplica_borda_total()
ws[f'G{start+i}'].alignment = Alignment(horizontal='center')
ws[f'H{start+i}'] = 'Maxicon'
ws[f'H{start+i}'].alignment = Alignment(horizontal='center')
ws[f'H{start+i}'].border = aplica_borda_total()
last_sol = len(sols_filhas) + start - 1
ws[f'F{last_sol+1}'] = f'=SUM(F{start}:F{last_sol})'
ws[f'G{last_sol+1}'].number_format = 'h:mm:ss'
ws[f'G{last_sol+1}'] = f'=SUM(G{start}:G{last_sol})'
ws[f'F{last_sol+1}'].alignment = Alignment(horizontal='center')
ws[f'G{last_sol+1}'].alignment = Alignment(horizontal='center')
planilha.save('teste.xlsx')````
[1]: https://i.stack.imgur.com/e2xOV.png

I would say that even though you are setting the cell format to 'h:mm:ss', Excel does not recognise the cells as being time values until a cell is updated. However the cell format you're using will result in an incorrect resultE.g. those values that do not conform with 'normal time' will be reset to 24hr time as the format assumes the highest value to be 23:59:59. Anything larger like 197:06:00 and 29:32:00 are going to be converted to 5:06:00 and 5:32:00 respectively.
You should use the format
'[h]:mm:ss'
(where 'h' is in square brackets) to allow hours above 24.
Even given a different format you may still have the same issues summing the values as
'=SUM(GX:GY)'
if there are and you want/need to do the sum in Excel it might work better to use the long hand like
'=SUM(GA+GB+GC+GD+...)'
Otherwise use python to change the format e.g. change everything to seconds and sum as numerical data (Excel can then display in format as required) or just do the summing in python writing all values to Excel.

Related

Python Index out of range Error in lib loop issue

everything's fine? I hope so.
I'm dealing with this issue: List index out of range. -
Error message:
c:\Users.....\Documents\t.py:41: FutureWarning: As the xlwt package is no longer maintained, the xlwt engine will be removed in a future version of pandas. This is the only engine in pandas that supports writing in the xls format. Install openpyxl and write to an xlsx file instead. You can set the option io.excel.xls.writer to 'xlwt' to silence this warning. While this option is deprecated and will also raise a warning, it can be globally set and the warning suppressed.
read_file.to_excel(planilhaxls, index = None, header=True)
The goal: I need to create a loop that store a specific line of a worksheet such as sheet_1.csv, this correspondent line in sheet_2.csv and a third sheet also, stored in 3 columns in a sheet_output.csv
Issue: It's getting an index error out of range that I don't know what to do
Doubt: There is any other way that I can do it?
The code is below:
(Please, ignore portuguese comments)
import xlrd as ex
import pyautogui as pag
import os
import pyperclip as pc
import pandas as pd
import pygetwindow as pgw
import openpyxl
#Inputs
numerolam = int(input('Escolha o número da lamina: '))
amostra = input('Escoha a amostra: (X, Y, W ou Z): ')
milimetro_inicial = int(input("Escolha o milimetro inicial: "))
milimetro_final = int(input("Escolha o milimetro final: "))
tipo = input("Escolha o tipo - B para Branco & E para Espelho: ")
linha = int(input("Escolha a linha da planilha: "))
# Conversão de código
if tipo == 'B':
tipo2 = 'BRA'
else:
tipo2 = 'ESP'
#Arquivo xlsx
#planilhaxlsx = f'A{numerolam}{amostra}{milimetro_inicial}{tipo2}.xlsx'
#planilhaxls = f'A{numerolam}{amostra}{milimetro_inicial}{tipo2}.xls'
#planilhacsv = f'A{numerolam}{amostra}{milimetro_inicial}{tipo2}.csv'
#planilhacsv_ = f'A{numerolam}{amostra}{milimetro_final}{tipo2}.csv'
#arquivoorigin = f'A{numerolam}{amostra}{milimetro_inicial}{tipo2}.opj'
#Pasta
pasta = f'L{numerolam}{amostra}'
while milimetro_inicial < milimetro_final:
planilhaxlsx = f'A{numerolam}{amostra}{milimetro_inicial}{tipo2}.xlsx'
planilhaxls = f'A{numerolam}{amostra}{milimetro_inicial}{tipo2}.xls'
planilhacsv = f'A{numerolam}{amostra}{milimetro_inicial}{tipo2}.csv'
planilhacsv_ = f'A{numerolam}{amostra}{milimetro_final}{tipo2}.csv'
arquivoorigin = f'A{numerolam}{amostra}{milimetro_inicial}{tipo2}.opj'
# Converte o arquivo .csv para .xls e .xlsx
read_file = pd.read_csv(planilhacsv)
read_file.to_excel(planilhaxls, index = None, header=True)
#read_file.to_excel(planilhaxlsx, index = None, header=True)
# Abre o arquivo .xls com o xlrd - arquivo excel.
book = ex.open_workbook(planilhaxls)
sh = book.sheet_by_index(0)
# Declaração de variáveis.
coluna_inicial = 16 # Q - inicia em 0
valor = []
index = 0
# Loop que armazena o valor da linha pela coluna Q-Z na variável valor 0-(len-1)
while coluna_inicial < 25:
**#ERRO NA LINHA ABAIXO**
**temp = sh.cell_value(linha, coluna_inicial)**
valor.append(temp) # Adiciona o valor
print(index)
print(valor[index])
index +=1
coluna_inicial += 1
# Abre planilha de saída
wb = openpyxl.Workbook()
ws = wb.active
#Inicia loop de escrita
colunas = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
idx_colunas = 0
contador_loop = colunas[idx_colunas]
linha_loop = 1
index_out = 0
s = f'{contador_loop}{linha_loop}'
print(s)
while linha_loop < len(valor):
valor[index_out] = "{}".format(valor[index_out])
ws[s].value = valor[index_out]
print(valor[index_out] + ' feito')
linha_loop += 1
idx_colunas += 1
index_out += 1
# Salva planilha de saída
wb.save("teste.xlsx")
milimetro_inicial += 1
Your problem is on this line
temp = sh.cell_value(linha, coluna_inicial)
There are two index params used linha and coluna_inicial, 'linha' appears to be a static value so the problem would seem to be with 'coluna_inicial' which gets increased by 1 each iteration
coluna_inicial += 1
The loop continues while 'coluna_inicial' value is less than 25. I suggest you check number of columns in the sheet 'sh' using
sh.ncols
either for debugging or as the preferred upper value of your loop. If this is less than 25 you will get the index error once 'coluna_inicial' value exceeds the 'sh.ncols' value.
<---------------Additional Information---------------->
Since this is an xls file there would be no need for delimiter settings, your code as is should open it correctly. However since the xls workbook to be opened is determined by params entered by the user at the start presumably meaning there are a number in the directory to choose from, are you sure you are checking the xls file your code run is opening? Also if there is more than one sheet in the workbook(s) are you opening the correct sheet?
You can print the workbook name to be sure which one is being opened. Also by adding verbosity to the open_workbook command (level 2 should be high enough), it will upon opening the book, print in console details of the sheets available including number of rows and columns in each.
print(planilhaxls)
book = ex.open_workbook(planilhaxls, verbosity=2)
sh = book.sheet_by_index(0)
print(sh.name)
E.g.
BOF: op=0x0809 vers=0x0600 stream=0x0010 buildid=14420 buildyr=1997 -> BIFF80
sheet 0('Sheet1') DIMENSIONS: ncols=21 nrows=21614
BOF: op=0x0809 vers=0x0600 stream=0x0010 buildid=14420 buildyr=1997 ->
BIFF80
sheet 1('Sheet2') DIMENSIONS: ncols=13 nrows=13
the print(sh.name) as shown checks the name of the sheet that 'sh' is assigned to.

IndexError: index 8 is out of bounds for axis 0 with size 1

I'm trying to make some code where I get certain columns from a .csv file and manipulate some data
but there is always an index error with index 3,6,7,8 and 9 and I don't understand why
ponto_medicao = 'Ponto de Medição'
calendario = 'Data'
hora = 'Hora'
tipo_de_energia = 'Tipo de Energia'
ativa_geracao = 'Ativa Geração (kWh)'
ativa_consumo = 'Ativa Consumo (kWh)'
reativa_geracao = 'Reativa Geração (kVArh)'
reativa_consumo = 'Reativa Consumo (kVArh)'
origem_coleta = 'Origem da Coleta'
notif_coleta = 'Notificação de Coleta'
tabela = pd.read_csv(
"2498455.csv",
skiprows=[0,1,2])
mode = tabela[ponto_medicao].value_counts().index[0]
tabela[ponto_medicao].fillna(value=mode, inplace=True)
mode = tabela[calendario].value_counts().index[1]
tabela[calendario].fillna(value=mode, inplace=True)
mode = tabela[hora].value_counts().index[2]
tabela[hora].fillna(value=mode, inplace=True)
mode = tabela[ativa_geracao].value_counts().index[4]
tabela[ativa_geracao].fillna(value=0, inplace=True)
mode = tabela[ativa_consumo].value_counts().index[5]
tabela[ativa_consumo].fillna(value=0, inplace=True)
mode = tabela[origem_coleta].value_counts().index[8]
tabela[origem_coleta].fillna(value=0, inplace=True)

Split each line in a file based on delimitters

This is the sample data in a file. I want to split each line in the file and add to a dataframe. In some cases they have more than 1 child. So whenever they have more than one child new set of column have to be added child2 Name and DOB
(P322) Rashmika Chadda 15/05/1995 – Rashmi C 12/02/2024
(P324) Shiva Bhupati 01/01/1994 – Vinitha B 04/08/2024
(P356) Karthikeyan chandrashekar 22/02/1991 – Kanishka P 10/03/2014
(P366) Kalyani Manoj 23/01/1975 - Vandana M 15/05/1995 - Chandana M 18/11/1998
This is the code I have tried but this splits only by taking "-" into consideration
with open("text.txt") as read_file:
file_contents = read_file.readlines()
content_list = []
temp = []
for each_line in file_contents:
temp = each_line.replace("–", " ").split()
content_list.append(temp)
print(content_list)
Current output:
[['(P322)', 'Rashmika', 'Chadda', '15/05/1995', 'Rashmi', 'Chadda', 'Teega', '12/02/2024'], ['(P324)', 'Shiva', 'Bhupati', '01/01/1994', 'Vinitha', 'B', 'Sahu', '04/08/2024'], ['(P356)', 'Karthikeyan', 'chandrashekar', '22/02/1991', 'Kanishka', 'P', '10/03/2014'], ['(P366)', 'Kalyani', 'Manoj', '23/01/1975', '-', 'Vandana', 'M', '15/05/1995', '-', 'Chandana', 'M', '18/11/1998']]
Final output should be like below
Code
Parent_Name
DOB
Child1_Name
DOB
Child2_Name
DOB
P322
Rashmika Chadda
15/05/1995
Rashmi C
12/02/2024
P324
Shiva Bhupati
01/01/1994
Vinitha B
04/08/2024
P356
Karthikeyan chandrashekar
22/02/1991
Kanishka P
10/03/2014
P366
Kalyani Manoj
23/01/1975
Vandana M
15/05/1995
Chandana M
18/11/1998
I'm not sure if you want it as a list or something else.
To get lists:
result = []
for t in text[:]:
# remove the \n at the end of each line
t = t.strip()
# remove the parenthesis you don't wnt
t = t.replace("(", "")
t = t.replace(")", "")
# split on space
t = t.split(" – ")
# reconstruct
for i, person in enumerate(t):
person = person.split(" ")
# print(person)
# remove code
if i==0:
res = [person.pop(0)]
res.extend([" ".join(person[:2]), person[2]])
result.append(res)
print(result)
Which would give the below output:
[['P322', 'Rashmika Chadda', '15/05/1995', 'Rashmi C', '12/02/2024'], ['P324', 'Shiva Bhupati', '01/01/1994', 'Vinitha B', '04/08/2024'], ['P356', 'Karthikeyan chandrashekar', '22/02/1991', 'Kanishka P', '10/03/2014'], ['P366', 'Kalyani Manoj', '23/01/1975', 'Vandana M', '15/05/1995', 'Chandana M', '18/11/1998']]
You can organise a bit more the data using dictionnary:
result = {}
for t in text[:]:
# remove the \n at the end of each line
t = t.strip()
# remove the parenthesis you don't wnt
t = t.replace("(", "")
t = t.replace(")", "")
# split on space
t = t.split(" – ")
for i, person in enumerate(t):
# split name
person = person.split(" ")
# remove code
if i==0:
code = person.pop(0)
if i==0:
result[code] = {"parent_name": " ".join(person[:2]), "parent_DOB": person[2], "children": [] }
else:
result[code]['children'].append({f"child{i}_name": " ".join(person[:2]), f"child{i}_DOB": person[2]})
print(result)
Which would give this output:
{'P322': {'children': [{'child1_DOB': '12/02/2024',
'child1_name': 'Rashmi C'}],
'parent_DOB': '15/05/1995',
'parent_name': 'Rashmika Chadda'},
'P324': {'children': [{'child1_DOB': '04/08/2024',
'child1_name': 'Vinitha B'}],
'parent_DOB': '01/01/1994',
'parent_name': 'Shiva Bhupati'},
'P356': {'children': [{'child1_DOB': '10/03/2014',
'child1_name': 'Kanishka P'}],
'parent_DOB': '22/02/1991',
'parent_name': 'Karthikeyan chandrashekar'},
'P366': {'children': [{'child1_DOB': '15/05/1995',
'child1_name': 'Vandana M'},
{'child2_DOB': '18/11/1998', 'child2_name': 'Chandana M'}],
'parent_DOB': '23/01/1975',
'parent_name': 'Kalyani Manoj'}}
In the end, to have an actual table, you would need to use pandas but that will require for you to fix the number of children max so that you can pad the empty cells.

Generating a table with docx from a dataframe in python

Hellow,
Currently I´m working in a project in which I have to generate some info with docx library in python. I want to know how to generate a docx table from a dataframe in order to have the output with all the columns and rows from de dataframe I've created. Here is my code, but its not working correctly because I can´t reach the final output:
table = doc.add_table(rows = len(detalle_operaciones_total1), cols=5)
table.style = 'Table Grid'
table.rows[0].cells[0].text = 'Nombre'
table.rows[0].cells[1].text = 'Operacion Nro'
table.rows[0].cells[2].text = 'Producto'
table.rows[0].cells[3].text = 'Monto en moneda de origen'
table.rows[0].cells[4].text = 'Monto en moneda local'
for y in range(1, len(detalle_operaciones_total1)):
Nombre = str(detalle_operaciones_total1.iloc[y,0])
Operacion = str(detalle_operaciones_total1.iloc[y,1])
Producto = str(detalle_operaciones_total1.iloc[y,2])
Monto_en_MO = str(detalle_operaciones_total1.iloc[y,3])
Monto_en_ML = str(detalle_operaciones_total1.iloc[y,4])
table.rows[y].cells[0].text = Nombre
table.rows[y].cells[1].text = Operacion
table.rows[y].cells[2].text = Producto
table.rows[y].cells[3].text = Monto_en_MO
table.rows[y].cells[4].text = Monto_en_ML

Show percentage and label

I'm trying to show the label and the percentage in the Qchart but it show me only one of them
Is there a way to show both of them
This is my function that run the QtChart
def charts_jr_acte(self):# pushButton_123
rightseries = QPieSeries()
rightseries.setLabelsVisible(True)
rightseries.setLabelsPosition(QPieSlice.LabelInsideHorizontal)
for C_acte, montant in rows:
rightseries.append(C_acte, montant)
slice = QPieSlice()
slice = rightseries.slices() [2]
slice.setExploded(True)
slice.setPen(QtGui.QPen(Qt.darkBlue))
for slice in rightseries.slices():
slice.setLabel("{:.2f}%".format(100 * slice.percentage()))
rightchart = QChart()
rightchart.createDefaultAxes()
rightchart.addSeries(rightseries)
rightchart.setTitle("total journalier de chaque Acte")
rightchart.setAnimationOptions(QChart.SeriesAnimations)
rightchart.legend().setVisible(True)
rightchart.legend().setAlignment(Qt.AlignBottom)
rightchart.legend().markers(rightseries)[1].setLabel(lab)
rightseries.setLabelsVisible()
rightseries.setLabelsPosition(QtChart.QPieSlice.LabelInsideHorizontal)
self.graphicsView_4.setChart(rightchart)
`
and this is an example of the result
i find a way to make it work
def charts_jr_acte(self):# pushButton_123
rightseries = QPieSeries()
rightseries.setLabelsVisible(True)
for C_acte, montant in rows:
rightseries.append(C_acte, montant)
slice = QPieSlice()
slice = rightseries.slices() [2]
slice.setExploded(True)
slice.setPen(QtGui.QPen(Qt.darkBlue))
for slice in rightseries.slices():
slice.setLabelVisible()
oldLabel=slice.label()
slice.setLabel((oldLabel+": %.1f%%" %(slice.percentage()*100) ))
rightchart = QChart()
rightchart.createDefaultAxes()
rightchart.addSeries(rightseries)
rightchart.setTitle("total journalier de chaque Acte")
rightchart.setAnimationOptions(QChart.SeriesAnimations)
rightchart.legend().setVisible(True)
self.graphicsView_4.setChart(rightchart)
this how it look like

Categories

Resources