I am currently using xlwt to generate a report in excel based on the data I have but the problem there is I have to hardcore the formulas and if I need to add a row in the middle of the sheet all the entries below that row needs to be arranged properly and need to recheck all the formulas.
currently my meta file for sheet data is like following:
STUDENTS_ROW_IDX = 5 MARKS_ROW = 10
SHEET_META = {
const.STUDENT:{
const.NUM_OF_STUDENTS:{
"idx": STUDENT_ROW_IDX },
const.NUM_OF_PASSED_STUDENTS:{
"idx":STUDENT_ROW_IDX + 2
}
},
const.MARKS:{
const.TOTAL_MARKS:{
"idx":MARKS_ROW
},
"formula": {
const.AVG_MARKS:{
"idx":MARKS_ROW + 3,
"value":"IF(X5 = 0, 0, X10/X5)"
}
}
}
The problem here is for avg marks I need to change the value from X10 to the new value if the row for total students changes. Is there a better way to handle excel with python.
Related
I couldn't find any resources on how to format the google spreadsheet in gspread python using the row and column values instead of A1 notations.
I have a spreadsheet with 50 rows and I don't want to find the notation of the 50th column. Rather I like to use the row and column coordinates like (1,50) -> first row with 50 columns to make them bold and adjusting the width of all the columns.
Please suggest and thanks in advance
I'm able to format the cells using row and column coordinates using the below function. Accumulated different answers available for the related questions in Stackoverflow. Thank you.
def formatHeaderRow(gs, ws):
#to change the column width of the specific range of cells using row and column numbers
sheetId = ws._properties['sheetId']
numOfColumns = 26 # Keep your column number here
body = {
"requests": [
{
"updateDimensionProperties": {
"range": {
"sheetId": sheetId,
"dimension": "COLUMNS",
"startIndex": 0, #from A1
"endIndex": numOfColumns # 26 -> A26
},
"properties": {
"pixelSize": "150"
},
"fields": "pixelSize"
}
}
]
}
res = gs.batch_update(body)
#to bold the first row using row number
ws.format("1", {
"textFormat": {
"bold": True
}
})
Is it possible in gspread library to fill down the entire column by Excel formula as in GUI, without going through each line?
Currently, I'm using the method below:
def _update_formula(sheet):
for i in range(2, 100):
sheet.update_acell(f'AL{i}', f'=if(B{i}=B{i+1},1,0)')
Is it possible, for example, to add 1 line and copy formula the rest of rows as in the GUI. Do you have any ideas how to optimize it?
I believe your goal is as follows.
You want to put a formula of =if(B{i}=B{i+1},1,0) to all cells in the specific column.
You want to achieve this using gspread for python.
In your script, you use the formula of '=if(B{i}=B{i+1},1,0'. But in this case, it might be '=if(B{i}=B{i+1},1,0)'. In this case, how about the following modified script? In this modification, the formula is put using the RepeatCellRequest of batchUpdate method.
Modified script:
spreadsheetId = "###" # Please set your Spreadsheet ID.
sheetName = "###" # Please set your sheet name.
spreadsheet = client.open_by_key(spreadsheetId) # or client.open("###Spreadsheet title###")
sheet = spreadsheet.worksheet(sheetName)
requests = {
"repeatCell": {
"cell": {
"userEnteredValue": {
"formulaValue": "=if(B1=B2,1,0)"
}
},
"range": {
"sheetId": sheet.id,
"startColumnIndex": 2,
"endColumnIndex": 3,
"startRowIndex": 1
},
"fields": "userEnteredValue.formulaValue"
}
}
res = spreadsheet.batch_update({"requests": [requests]})
"startColumnIndex": 2 and "endColumnIndex": 3 of range means the column "C".
"startRowIndex": 1 of range and no endRowIndex means that the formula is put from the row 2 to end of row.
About GridRange, you can see it at the official document.
References:
batch_update(body)
RepeatCellRequest
I am converting a script that was originally done in App Script to apply formatting to google sheets.
This script needs to apply to many sheets, and the number of columns is not known in advance. Before, in the App Scripts, I used basic getDataRange() without parameters, and it would select the correct number of columns and rows. How can I do the same via API? Is there a way to set end column index to end of data range?
For example, I'm using
{
"setBasicFilter": {
"filter": {
"range": {
"sheetId": SHEET_ID,
"startRowIndex": 0
}
}
}
}
To set top row as a filter. But it applies filters to all the empty cells as well, that are outside the table with data, while I need them to stop at last column.
What is the best way to do this via the API?
Solution:
You can call spreadsheets.values.get to get the values of a range, then get the length of the first element array. Then plug it in the setBasicFilter request.
Sample Code:
# The ID and range of a sample spreadsheet.
SAMPLE_SPREADSHEET_ID = 'enter spreadsheet ID here'
SAMPLE_RANGE_NAME = 'Sheet1!A1:1'
.
.
.
# Call the Sheets API
sheet = service.spreadsheets()
result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
range=SAMPLE_RANGE_NAME).execute()
values = result.get('values', [])
length = len(values[0])
.
.
.
# filter parameters
{
"setBasicFilter": {
"filter": {
"range": {
"sheetId": SHEET_ID,
"startRowIndex": 0
"startColumnIndex": 0
"endColumnIndex" : length
}
}
}
}
References:
Python Quickstart
Grid Range
I am trying to adjust the width of columns in a google sheet using GSpread, however I can't find any documentation on the subject all across the web. I have tried the actual project documents itself, and stack overflow.
I have looked through the documentation, and stack overflow, and nobody has asked a question like this before.
No code to show, as I haven't found any that may be relevant.
I am expecting the widen column 'A' in my sheet by around 100.
Thanks in advance for the help.
Cheers.
If you are using gspread I recommend to use gspread-formatting for this task.
Example from the documentation:
set_row_height(worksheet, 1, 42)
set_row_height(worksheet, '1:100', 42)
set_row_heights(worksheet, [ ('1:100', 42), ('101:', 22) ])
set_column_width(worksheet, 'A', 190)
set_column_width(worksheet, 'A:D', 100)
set_column_widths(worksheet, [ ('A', 200), ('B:', 100) ])
Check it here: https://pypi.org/project/gspread-formatting/#setting-row-heights-and-column-widths
You want to know how to adjust the width of the column of Google Spreadsheet using gspread.
You want to set the column "A" to 100 pixels.
You have already been able to put and get values to the Spreadsheet using gspread.
If my understanding is correct, how about this answer? In this modification, batch_update() method is used.
Sample script:
Please set spreadsheetId, sheetName and the gridrange of range.
spreadsheetId = "###"
sheetName = "Sheet1"
client = gspread.authorize(credentials)
ss = client.open_by_key(spreadsheetId)
sheetId = ss.worksheet(sheetName)._properties['sheetId']
body = {
"requests": [
{
"updateDimensionProperties": {
"range": {
"sheetId": sheetId,
"dimension": "COLUMNS",
"startIndex": 0,
"endIndex": 1
},
"properties": {
"pixelSize": 100
},
"fields": "pixelSize"
}
}
]
}
res = ss.batch_update(body)
Note:
Please set the range as the gridrange.
In this sample script, startIndex: 0 and endIndex: 1 mean the column "A" because of dimension: "COLUMNS".
In this sample script, the width of the column "A" is set to 100 pixels.
When dimension is changed to ROWS, the height of rows can be adjusted.
References:
batch_update(body)
Method: spreadsheets.batchUpdate
UpdateDimensionPropertiesRequest
If this was not useful for your situation, I apologize.
I want to just apply a formatting from a JSON Entry. The first thing I did was make my desirable format on my spreadsheet for the second row of all columns. I then retrieved them with a .get request (from A2 to AO3).
request = google_api.service.spreadsheets().get(
spreadsheetId=ss_id,
ranges="Tab1!A2:AO3",
includeGridData=True).execute()
The next thing I did was collect each of the formats for each column and record them in a dictionary.
my_dictionary_of_formats = {}
row_values = row_1['sheets'][0]['data'][0]['rowData'][0]['values']
for column in range(0, len(row_values)):
my_dictionary_of_formats[column] = row_values[column]['effectiveFormat']
Now I have a dictionray of all my effective formats for all my columns. I'm having trouble now applying that format to all rows in each column. I tried a batchUpdate request:
cell_data = {
"effectiveFormat": my_dictionary_of_formats[0]}
row_data = {
"values": [
cell_data
]
}
update_cell = {
"rows": [
row_data
],
"fields": "*",
"range":
{
"sheetId": input_master.tab_id,
"startRowIndex": 2,
"startColumnIndex": 0,
"endColumnsIndex": 1
}
}
request_body = {
"requests": [
{"updateCells": update_cell}],
"includeSpreadsheetInResponse": True,
"responseIncludeGridData": True}
service.spreadsheets().batchUpdate(spreadsheetId=my_id, body=request_body).execute()
This wiped out everything and I'm not sure why. I don't think I understand the fields='* attribute.
TL;DR
I want to apply a format to all rows in a single column. Much like if I used the "Paint Format" tool on the second row, first column and dragged it all the way down to the last row.
-----Update
Hi, thanks to the comments this was my solution:
###collect all formats from second row
import json
row_2 = goolge_api.service.spreadsheets().get(
spreadsheetId=spreadsheet_id,
ranges="tab1!A2:AO2",
includeGridData=True).execute()
my_dictionary = {}
row_values = row_2['sheets'][0]['data'][0]['rowData'][0]['values']
for column in range(0,len(row_values)):
my_dictionary[column] = row_values[column]
json.dumps(my_dictionary,open('config/format.json','w'))
###Part 2, apply formats
requests = []
my_dict = json.load(open('config/format.json'))
for column in my_dict:
requests.append(
{
"repeatCell": {
"range": {
"sheetId": tab_id,
"startRowIndex": str(1),
"startColumnIndex":str(column),
"endColumnIndex":str(int(column)+1)
},
"cell": {
"userEnteredFormat": my_dict[column]
},
'fields': "userEnteredFormat({})".format(",".join(my_dict[column].keys()))
}
})
body = {"requests": requests}
google_api.service.spreadsheets().batchUpdate(spreadsheetId=s.spreadsheet_id,body=body).execute()
When you include fields as a part of the request, you indicate to the API endpoint that it should overwrite the specified fields in the targeted range with the information found in your uploaded resource. fields="*" correspondingly is interpreted as "This request specifies the entire data and metadata of the given range. Remove any previous data and metadata from the range and use what is supplied instead."
Thus, anything not specified in your updateCells requests will be removed from the range supplied in the request (e.g. values, formulas, data validation, etc.).
You can learn more in the guide to batchUpdate
For an updateCell request, the fields parameter is as described:
The fields of CellData that should be updated. At least one field must be specified. The root is the CellData; 'row.values.' should not be specified. A single "*" can be used as short-hand for listing every field.
If you then view the resource description of CellData, you observe the following fields:
"userEnteredValue"
"effectiveValue"
"formattedValue"
"userEnteredFormat"
"effectiveFormat"
"hyperlink"
"note"
"textFormatRuns"
"dataValidation"
"pivotTable"
Thus, the proper fields specification for your request is likely to be fields="effectiveFormat", since this is the only field you supply in your row_data property.
Consider also using the repeatCell request if you are just specifying a single format.