1
- from typing import Any , Optional , Dict
1
+ from typing import Any , List , Optional , Dict
2
2
3
3
from openpyxl .styles import Font , PatternFill
4
4
from openpyxl .styles import NamedStyle
7
7
from pandas import DataFrame , ExcelWriter
8
8
9
9
from mitosheet .excel_utils import get_column_from_column_index
10
+ from mitosheet .is_type_utils import is_float_dtype
10
11
from mitosheet .types import (
11
12
FC_BOOLEAN_IS_FALSE , FC_BOOLEAN_IS_TRUE , FC_DATETIME_EXACTLY ,
12
13
FC_DATETIME_GREATER , FC_DATETIME_GREATER_THAN_OR_EQUAL , FC_DATETIME_LESS ,
@@ -89,10 +90,13 @@ def get_conditional_format_rule(
89
90
return FormulaRule (fill = fill , font = font , formula = formula )
90
91
91
92
def add_conditional_formats (
92
- conditional_formats : list ,
93
+ conditional_formats : Optional [ List [ Any ]] ,
93
94
sheet : Worksheet ,
94
95
df : DataFrame
95
96
) -> None :
97
+ if conditional_formats is None :
98
+ return
99
+
96
100
for conditional_format in conditional_formats :
97
101
for filter in conditional_format .get ('filters' , []):
98
102
# Create the conditional formatting color objects
@@ -127,90 +131,153 @@ def add_number_formatting(
127
131
sheet : Worksheet ,
128
132
df : DataFrame
129
133
) -> None :
130
- if number_formats is None :
131
- return
132
- for column_header , number_format in number_formats .items ():
133
- column_index = df .columns .tolist ().index (column_header )
134
+ default_number_format_column_indexes = set (range (len (df .columns )))
135
+
136
+ # For all the columns that have user defined number formats
137
+ # apply those
138
+ if number_formats is not None :
139
+ for column_header , number_format in number_formats .items ():
140
+ column_index = df .columns .tolist ().index (column_header )
141
+ column = get_column_from_column_index (column_index )
142
+ cell_range = f'{ column } 2:{ column } { sheet .max_row } '
143
+ for cell in sheet [cell_range ]:
144
+ cell [0 ].number_format = number_format
145
+
146
+ default_number_format_column_indexes .remove (column_index )
147
+
148
+ # For all the float columns that have default number formats
149
+ # and contain numbers, apply the default number format
150
+ # which has comma separators and 2 decimal places
151
+ column_headers = df .columns .tolist ()
152
+ for column_index in default_number_format_column_indexes :
153
+ column_header = column_headers [column_index ]
154
+ dtype = str (df [column_header ].dtype )
155
+ if not is_float_dtype (dtype ):
156
+ continue
157
+
134
158
column = get_column_from_column_index (column_index )
135
159
cell_range = f'{ column } 2:{ column } { sheet .max_row } '
136
160
for cell in sheet [cell_range ]:
137
- cell [0 ].number_format = number_format
161
+ cell [0 ].number_format = '#,##0.00'
162
+
163
+ def add_header_formatting_to_excel_sheet (
164
+ writer : ExcelWriter ,
165
+ sheet_name : str ,
166
+ header_background_color : Optional [str ]= None ,
167
+ header_font_color : Optional [str ]= None
168
+ ) -> None :
169
+ """
170
+ Adds formatting to the header row of the sheet_name, based on the formatting the user
171
+ currently has applied in the frontend.
172
+ """
173
+ workbook = writer .book
174
+ sheet = workbook .get_sheet_by_name (sheet_name )
175
+
176
+ # Add formatting to the header row
177
+ header_name = f"{ sheet_name } _Header"
178
+ header_format = NamedStyle (name = header_name )
179
+ if header_font_color :
180
+ # Remove the # from the color
181
+ header_format .font = Font (color = header_font_color [1 :])
182
+ if header_background_color :
183
+ # Remove the # from the color
184
+ header_format .fill = PatternFill (start_color = header_background_color [1 :], end_color = header_background_color [1 :], fill_type = "solid" )
185
+
186
+ # Only add format if there is a header color or background color
187
+ has_header_formatting = header_background_color or header_font_color
188
+ if has_header_formatting :
189
+ # Add named styles for the header rows to improve performance
190
+ workbook .add_named_style (header_format )
191
+
192
+ # Write the formatting to the sheet
193
+ for col in range (1 , sheet .max_column + 1 ):
194
+ sheet .cell (row = 1 , column = col ).style = header_name
195
+
196
+ def add_row_formatting_to_excel_sheet (
197
+ writer : ExcelWriter ,
198
+ sheet_name : str ,
199
+ even_background_color : Optional [str ]= None ,
200
+ even_font_color : Optional [str ]= None ,
201
+ odd_background_color : Optional [str ]= None ,
202
+ odd_font_color : Optional [str ]= None
203
+ ) -> None :
204
+ """
205
+ Adds formatting to the rows of the sheet_name, based on the formatting the user
206
+ currently has applied in the frontend.
207
+ """
208
+ workbook = writer .book
209
+ sheet = workbook .get_sheet_by_name (sheet_name )
210
+
211
+ # Add formatting to the rows
212
+ even_name = f"{ sheet_name } _Even"
213
+ odd_name = f"{ sheet_name } _Odd"
214
+ even_format = NamedStyle (name = even_name )
215
+ odd_format = NamedStyle (name = odd_name )
216
+
217
+ # Remove the # from the colors and define the formatting objects
218
+ if even_background_color :
219
+ even_format .fill = PatternFill (start_color = even_background_color [1 :], end_color = even_background_color [1 :], fill_type = "solid" )
220
+ if even_font_color :
221
+ even_format .font = Font (color = even_font_color [1 :])
222
+ if odd_background_color :
223
+ odd_format .fill = PatternFill (start_color = odd_background_color [1 :], end_color = odd_background_color [1 :], fill_type = "solid" )
224
+ if odd_font_color :
225
+ odd_format .font = Font (color = odd_font_color [1 :])
226
+
227
+ # Only add format if there is a background color or font color
228
+ has_row_formatting = even_background_color or even_font_color or odd_background_color or odd_font_color
229
+ if not has_row_formatting :
230
+ return
231
+
232
+ workbook .add_named_style (even_format )
233
+ workbook .add_named_style (odd_format )
234
+
235
+ for row in range (2 , sheet .max_row + 1 ):
236
+ for col in range (1 , sheet .max_column + 1 ):
237
+ if row % 2 == 0 :
238
+ sheet .cell (row = row , column = col ).style = even_name
239
+ else :
240
+ sheet .cell (row = row , column = col ).style = odd_name
138
241
139
242
140
243
def add_formatting_to_excel_sheet (
141
- writer : ExcelWriter ,
142
- sheet_name : str ,
143
- df : DataFrame ,
144
- header_background_color : Optional [str ]= None ,
145
- header_font_color : Optional [str ]= None ,
146
- even_background_color : Optional [str ]= None ,
147
- even_font_color : Optional [str ]= None ,
148
- odd_background_color : Optional [str ]= None ,
149
- odd_font_color : Optional [str ]= None ,
150
- conditional_formats : Optional [list ]= None ,
151
- number_formats : Optional [Dict [str , Any ]]= None
152
- ) -> None :
153
- """
154
- Adds formatting to the sheet_name, based on the formatting the user
155
- currently has applied in the frontend.
156
-
157
- NOTE: this is a Mito Pro feature.
158
- """
159
- workbook = writer .book
160
- sheet = workbook .get_sheet_by_name (sheet_name )
161
-
162
- # Add formatting to the header row
163
- header_name = f"{ sheet_name } _Header"
164
- header_format = NamedStyle (name = header_name )
165
- if header_font_color :
166
- # Remove the # from the color
167
- header_format .font = Font (color = header_font_color [1 :])
168
- if header_background_color :
169
- # Remove the # from the color
170
- header_format .fill = PatternFill (start_color = header_background_color [1 :], end_color = header_background_color [1 :], fill_type = "solid" )
171
-
172
- # Only add format if there is a header color or background color
173
- has_header_formatting = header_background_color or header_font_color
174
- if has_header_formatting :
175
- # Add named styles for the header rows to improve performance
176
- workbook .add_named_style (header_format )
177
-
178
- # Write the formatting to the sheet
179
- for col in range (1 , sheet .max_column + 1 ):
180
- sheet .cell (row = 1 , column = col ).style = header_name
181
-
182
- # Add formatting to the rows
183
- even_name = f"{ sheet_name } _Even"
184
- odd_name = f"{ sheet_name } _Odd"
185
- even_format = NamedStyle (name = even_name )
186
- odd_format = NamedStyle (name = odd_name )
187
-
188
- # Remove the # from the colors and define the formatting objects
189
- if even_background_color :
190
- even_format .fill = PatternFill (start_color = even_background_color [1 :], end_color = even_background_color [1 :], fill_type = "solid" )
191
- if even_font_color :
192
- even_format .font = Font (color = even_font_color [1 :])
193
- if odd_background_color :
194
- odd_format .fill = PatternFill (start_color = odd_background_color [1 :], end_color = odd_background_color [1 :], fill_type = "solid" )
195
- if odd_font_color :
196
- odd_format .font = Font (color = odd_font_color [1 :])
197
-
198
- # Only add format if there is a background color or font color
199
- has_row_formatting = even_background_color or even_font_color or odd_background_color or odd_font_color
200
- if has_row_formatting :
201
- workbook .add_named_style (even_format )
202
- workbook .add_named_style (odd_format )
203
-
204
- for row in range (2 , sheet .max_row + 1 ):
205
- for col in range (1 , sheet .max_column + 1 ):
206
- if row % 2 == 0 :
207
- sheet .cell (row = row , column = col ).style = even_name
208
- else :
209
- sheet .cell (row = row , column = col ).style = odd_name
210
-
211
- # Add conditional formatting
212
- if conditional_formats is not None :
213
- add_conditional_formats (conditional_formats , sheet , df )
214
-
215
- if number_formats is not None :
216
- add_number_formatting (number_formats , sheet , df )
244
+ writer : ExcelWriter ,
245
+ sheet_name : str ,
246
+ df : DataFrame ,
247
+ header_background_color : Optional [str ]= None ,
248
+ header_font_color : Optional [str ]= None ,
249
+ even_background_color : Optional [str ]= None ,
250
+ even_font_color : Optional [str ]= None ,
251
+ odd_background_color : Optional [str ]= None ,
252
+ odd_font_color : Optional [str ]= None ,
253
+ conditional_formats : Optional [list ]= None ,
254
+ number_formats : Optional [Dict [str , Any ]]= None
255
+ ) -> None :
256
+ """
257
+ Adds formatting to the sheet_name, based on the formatting the user
258
+ currently has applied in the frontend.
259
+
260
+ NOTE: this is a Mito Pro feature.
261
+ """
262
+ workbook = writer .book
263
+ sheet = workbook .get_sheet_by_name (sheet_name )
264
+
265
+ add_header_formatting_to_excel_sheet (
266
+ writer = writer ,
267
+ sheet_name = sheet_name ,
268
+ header_background_color = header_background_color ,
269
+ header_font_color = header_font_color
270
+ )
271
+
272
+ add_row_formatting_to_excel_sheet (
273
+ writer = writer ,
274
+ sheet_name = sheet_name ,
275
+ even_background_color = even_background_color ,
276
+ even_font_color = even_font_color ,
277
+ odd_background_color = odd_background_color ,
278
+ odd_font_color = odd_font_color
279
+ )
280
+
281
+ add_conditional_formats (conditional_formats , sheet , df )
282
+
283
+ add_number_formatting (number_formats , sheet , df )
0 commit comments