Passed
Push — master ( 315a1d...7483d8 )
by Guangyu
02:16 queued 11s
created

generate_excel()   F

Complexity

Conditions 47

Size

Total Lines 468
Code Lines 349

Duplication

Lines 468
Ratio 100 %

Importance

Changes 0
Metric Value
cc 47
eloc 349
nop 5
dl 468
loc 468
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like excelexporters.shopfloorstatistics.generate_excel() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import base64
2
import uuid
3
import os
4
from openpyxl.chart import (
5
    LineChart,
6
    Reference,
7
)
8
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
9
from openpyxl.drawing.image import Image
10
from openpyxl import Workbook
11
12
13
####################################################################################################################
14
# PROCEDURES
15
# Step 1: Validate the report data
16
# Step 2: Generate excel file
17
# Step 3: Encode the excel file bytes to Base64
18
####################################################################################################################
19
20
21 View Code Duplication
def export(report,
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
22
           name,
23
           reporting_start_datetime_local,
24
           reporting_end_datetime_local,
25
           period_type):
26
    ####################################################################################################################
27
    # Step 1: Validate the report data
28
    ####################################################################################################################
29
    if report is None:
30
        return None
31
    print(report)
32
33
    ####################################################################################################################
34
    # Step 2: Generate excel file from the report data
35
    ####################################################################################################################
36
    filename = generate_excel(report,
37
                              name,
38
                              reporting_start_datetime_local,
39
                              reporting_end_datetime_local,
40
                              period_type)
41
    ####################################################################################################################
42
    # Step 3: Encode the excel file to Base64
43
    ####################################################################################################################
44
    try:
45
        with open(filename, 'rb') as binary_file:
46
            binary_file_data = binary_file.read()
47
    except IOError as ex:
48
        pass
49
50
    # Base64 encode the bytes
51
    base64_encoded_data = base64.b64encode(binary_file_data)
0 ignored issues
show
introduced by
The variable binary_file_data does not seem to be defined for all execution paths.
Loading history...
52
    # get the Base64 encoded data using human-readable characters.
53
    base64_message = base64_encoded_data.decode('utf-8')
54
    # delete the file from server
55
    try:
56
        os.remove(filename)
57
    except NotImplementedError as ex:
58
        pass
59
    return base64_message
60
61
62 View Code Duplication
def generate_excel(report,
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
63
                   name,
64
                   reporting_start_datetime_local,
65
                   reporting_end_datetime_local,
66
                   period_type):
67
    wb = Workbook()
68
    ws = wb.active
69
70
    # Row height
71
    ws.row_dimensions[1].height = 121
72
73
    for i in range(2, 37 + 1):
74
        ws.row_dimensions[i].height = 30
75
76
    for i in range(38, 90 + 1):
77
        ws.row_dimensions[i].height = 30
78
79
    # Col width
80
    ws.column_dimensions['A'].width = 1.5
81
    ws.column_dimensions['B'].width = 20.0
82
83
    for i in range(ord('C'), ord('I')):
84
        ws.column_dimensions[chr(i)].width = 15.0
85
86
    # Font
87
    name_font = Font(name='Constantia', size=15, bold=True)
88
    title_font = Font(name='宋体', size=15, bold=True)
89
    # data_font = Font(name='Franklin Gothic Book', size=11)
90
91
    table_fill = PatternFill(fill_type='solid', fgColor='1F497D')
92
    f_border = Border(left=Side(border_style='medium', color='00000000'),
93
                      right=Side(border_style='medium', color='00000000'),
94
                      bottom=Side(border_style='medium', color='00000000'),
95
                      top=Side(border_style='medium', color='00000000')
96
                      )
97
    b_border = Border(
98
        bottom=Side(border_style='medium', color='00000000'),
99
    )
100
101
    b_c_alignment = Alignment(vertical='bottom',
102
                              horizontal='center',
103
                              text_rotation=0,
104
                              wrap_text=False,
105
                              shrink_to_fit=False,
106
                              indent=0)
107
    c_c_alignment = Alignment(vertical='center',
108
                              horizontal='center',
109
                              text_rotation=0,
110
                              wrap_text=False,
111
                              shrink_to_fit=False,
112
                              indent=0)
113
    b_r_alignment = Alignment(vertical='bottom',
114
                              horizontal='right',
115
                              text_rotation=0,
116
                              wrap_text=False,
117
                              shrink_to_fit=False,
118
                              indent=0)
119
    # c_r_alignment = Alignment(vertical='bottom',
120
    #                           horizontal='center',
121
    #                           text_rotation=0,
122
    #                           wrap_text=False,
123
    #                           shrink_to_fit=False,
124
    #                           indent=0)
125
126
    # Img
127
    img = Image("excelexporters/myems.png")
128
    # img = Image("myems.png")
129
    ws.add_image(img, 'B1')
130
131
    # Title
132
    ws['B3'].font = name_font
133
    ws['B3'].alignment = b_r_alignment
134
    ws['B3'] = 'Name:'
135
    ws['C3'].border = b_border
136
    ws['C3'].alignment = b_c_alignment
137
    ws['C3'].font = name_font
138
    ws['C3'] = name
139
140
    ws['D3'].font = name_font
141
    ws['D3'].alignment = b_r_alignment
142
    ws['D3'] = 'Period:'
143
    ws['E3'].border = b_border
144
    ws['E3'].alignment = b_c_alignment
145
    ws['E3'].font = name_font
146
    ws['E3'] = period_type
147
148
    ws['F3'].font = name_font
149
    ws['F3'].alignment = b_r_alignment
150
    ws['F3'] = 'Date:'
151
    ws['G3'].border = b_border
152
    ws['G3'].alignment = b_c_alignment
153
    ws['G3'].font = name_font
154
    ws['G3'] = reporting_start_datetime_local + "__" + reporting_end_datetime_local
155
    ws.merge_cells("G3:H3")
156
157
    if "reporting_period" not in report.keys() or \
158
            "names" not in report['reporting_period'].keys() or len(report['reporting_period']['names']) == 0:
159
        filename = str(uuid.uuid4()) + '.xlsx'
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable str does not seem to be defined.
Loading history...
160
        wb.save(filename)
161
162
        return filename
163
    #################################################
164
    # First: 统计分析
165
    # 6: title
166
    # 7: table title
167
    # 8~ca_len table_data
168
    #################################################
169
    reporting_period_data = report['reporting_period']
170
171
    has_energy_data_flag = True
172
173
    if "names" not in reporting_period_data.keys() or \
174
            reporting_period_data['names'] is None or \
175
            len(reporting_period_data['names']) == 0:
176
        has_energy_data_flag = False
177
178
        filename = str(uuid.uuid4()) + '.xlsx'
179
        wb.save(filename)
180
181
        return filename
182
183
    if has_energy_data_flag:
184
        ws['B6'].font = title_font
185
        ws['B6'] = name + ' 统计分析'
186
187
        category = reporting_period_data['names']
188
189
        # table_title
190
        ws['B7'].fill = table_fill
191
        ws['B7'].font = title_font
192
        ws['B7'].alignment = c_c_alignment
193
        ws['B7'] = '报告期'
194
        ws['B7'].border = f_border
195
196
        ws['C7'].font = title_font
197
        ws['C7'].alignment = c_c_alignment
198
        ws['C7'] = '算术平均数'
199
        ws['C7'].border = f_border
200
201
        ws['D7'].font = title_font
202
        ws['D7'].alignment = c_c_alignment
203
        ws['D7'] = '中位数'
204
        ws['D7'].border = f_border
205
206
        ws['E7'].font = title_font
207
        ws['E7'].alignment = c_c_alignment
208
        ws['E7'] = '最小值'
209
        ws['E7'].border = f_border
210
211
        ws['F7'].font = title_font
212
        ws['F7'].alignment = c_c_alignment
213
        ws['F7'] = '最大值'
214
        ws['F7'].border = f_border
215
216
        ws['G7'].font = title_font
217
        ws['G7'].alignment = c_c_alignment
218
        ws['G7'] = '样本标准差'
219
        ws['G7'].border = f_border
220
221
        ws['H7'].font = title_font
222
        ws['H7'].alignment = c_c_alignment
223
        ws['H7'] = '样本方差'
224
        ws['H7'].border = f_border
225
226
        # table_data
227
228
        for i, value in enumerate(category):
229
            row = i*2 + 8
230
            ws['B' + str(row)].font = name_font
231
            ws['B' + str(row)].alignment = c_c_alignment
232
            ws['B' + str(row)] = reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + " )"
233
            ws['B' + str(row)].border = f_border
234
235
            ws['B' + str(row + 1)].font = name_font
236
            ws['B' + str(row + 1)].alignment = c_c_alignment
237
            ws['B' + str(row + 1)] = "环比"
238
            ws['B' + str(row + 1)].border = f_border
239
240
            ws['C' + str(row)].font = name_font
241
            ws['C' + str(row)].alignment = c_c_alignment
242
            ws['C' + str(row)] = round(reporting_period_data['means'][i], 2) \
243
                if reporting_period_data['means'][i] is not None else ''
244
            ws['C' + str(row)].border = f_border
245
            ws['C' + str(row)].number_format = '0.00'
246
247
            ws['C' + str(row + 1)].font = name_font
248
            ws['C' + str(row + 1)].alignment = c_c_alignment
249
            ws['C' + str(row + 1)] = str(round(reporting_period_data['means_increment_rate'][i] * 100, 2)) + "%" \
250
                if reporting_period_data['means_increment_rate'][i] is not None else '0.00%'
251
            ws['C' + str(row + 1)].border = f_border
252
253
            ws['D' + str(row)].font = name_font
254
            ws['D' + str(row)].alignment = c_c_alignment
255
            ws['D' + str(row)] = round(reporting_period_data['medians'][i], 2) \
256
                if reporting_period_data['medians'][i] is not None else ''
257
            ws['D' + str(row)].border = f_border
258
            ws['D' + str(row)].number_format = '0.00'
259
260
            ws['D' + str(row + 1)].font = name_font
261
            ws['D' + str(row + 1)].alignment = c_c_alignment
262
            ws['D' + str(row + 1)] = str(round(reporting_period_data['medians_increment_rate'][i] * 100, 2)) + "%" \
263
                if reporting_period_data['medians_increment_rate'][i] is not None else '0.00%'
264
            ws['D' + str(row + 1)].border = f_border
265
266
            ws['E' + str(row)].font = name_font
267
            ws['E' + str(row)].alignment = c_c_alignment
268
            ws['E' + str(row)] = round(reporting_period_data['minimums'][i], 2) \
269
                if reporting_period_data['minimums'][i] is not None else ''
270
            ws['E' + str(row)].border = f_border
271
            ws['E' + str(row)].number_format = '0.00'
272
273
            ws['E' + str(row + 1)].font = name_font
274
            ws['E' + str(row + 1)].alignment = c_c_alignment
275
            ws['E' + str(row + 1)] = str(round(reporting_period_data['minimums_increment_rate'][i] * 100, 2)) + "%" \
276
                if reporting_period_data['minimums_increment_rate'][i] is not None else '0.00%'
277
            ws['E' + str(row + 1)].border = f_border
278
279
            ws['F' + str(row)].font = name_font
280
            ws['F' + str(row)].alignment = c_c_alignment
281
            ws['F' + str(row)] = round(reporting_period_data['maximums'][i], 2) \
282
                if reporting_period_data['maximums'][i] is not None else ''
283
            ws['F' + str(row)].border = f_border
284
            ws['F' + str(row)].number_format = '0.00'
285
286
            ws['F' + str(row + 1)].font = name_font
287
            ws['F' + str(row + 1)].alignment = c_c_alignment
288
            ws['F' + str(row + 1)] = str(round(reporting_period_data['maximums_increment_rate'][i] * 100, 2)) + "%" \
289
                if reporting_period_data['maximums_increment_rate'][i] is not None else '0.00%'
290
            ws['F' + str(row + 1)].border = f_border
291
292
            ws['G' + str(row)].font = name_font
293
            ws['G' + str(row)].alignment = c_c_alignment
294
            ws['G' + str(row)] = round(reporting_period_data['stdevs'][i], 2) \
295
                if reporting_period_data['stdevs'][i] is not None else ''
296
            ws['G' + str(row)].border = f_border
297
            ws['G' + str(row)].number_format = '0.00'
298
299
            ws['G' + str(row + 1)].font = name_font
300
            ws['G' + str(row + 1)].alignment = c_c_alignment
301
            ws['G' + str(row + 1)] = str(round(reporting_period_data['stdevs_increment_rate'][i] * 100, 2)) + "%" \
302
                if reporting_period_data['stdevs_increment_rate'][i] is not None else '0.00%'
303
            ws['G' + str(row + 1)].border = f_border
304
305
            ws['H' + str(row)].font = name_font
306
            ws['H' + str(row)].alignment = c_c_alignment
307
            ws['H' + str(row)] = round(reporting_period_data['variances'][i], 2) \
308
                if reporting_period_data['variances'][i] is not None else ''
309
            ws['H' + str(row)].border = f_border
310
            ws['H' + str(row)].number_format = '0.00'
311
312
            ws['H' + str(row + 1)].font = name_font
313
            ws['H' + str(row + 1)].alignment = c_c_alignment
314
            ws['H' + str(row + 1)] = str(round(reporting_period_data['variances_increment_rate'][i] * 100, 2)) + "%" \
315
                if reporting_period_data['variances_increment_rate'][i] is not None else '0.00%'
316
            ws['H' + str(row + 1)].border = f_border
317
    #################################################
318
    # Second: 报告期消耗
319
    # 9 + ca_len * 2: title
320
    # 10 + ca_len * 2: table title
321
    # row_title + 2 ~ row_title + 2 + ca_len :  table_data
322
    #################################################
323
324
    if has_energy_data_flag:
325
        names = reporting_period_data['names']
326
        ca_len = len(names)
327
328
        row_title = 9 + ca_len * 2
329
330
        ws['B' + str(row_title)].font = title_font
331
        ws['B' + str(row_title)] = name + ' 单位面积值'
332
        ws['D' + str(row_title)].font = title_font
333
        ws['D' + str(row_title)] = str(report['shopfloor']['area']) + 'M²'
334
335
        category = reporting_period_data['names']
336
337
        # table_title
338
        ws['B' + str(row_title + 1)].fill = table_fill
339
        ws['B' + str(row_title + 1)].font = title_font
340
        ws['B' + str(row_title + 1)].alignment = c_c_alignment
341
        ws['B' + str(row_title + 1)] = '报告期'
342
        ws['B' + str(row_title + 1)].border = f_border
343
344
        ws['C' + str(row_title + 1)].font = title_font
345
        ws['C' + str(row_title + 1)].alignment = c_c_alignment
346
        ws['C' + str(row_title + 1)] = '算术平均数'
347
        ws['C' + str(row_title + 1)].border = f_border
348
349
        ws['D' + str(row_title + 1)].font = title_font
350
        ws['D' + str(row_title + 1)].alignment = c_c_alignment
351
        ws['D' + str(row_title + 1)] = '中位数'
352
        ws['D' + str(row_title + 1)].border = f_border
353
354
        ws['E' + str(row_title + 1)].font = title_font
355
        ws['E' + str(row_title + 1)].alignment = c_c_alignment
356
        ws['E' + str(row_title + 1)] = '最小值'
357
        ws['E' + str(row_title + 1)].border = f_border
358
359
        ws['F' + str(row_title + 1)].font = title_font
360
        ws['F' + str(row_title + 1)].alignment = c_c_alignment
361
        ws['F' + str(row_title + 1)] = '最大值'
362
        ws['F' + str(row_title + 1)].border = f_border
363
364
        ws['G' + str(row_title + 1)].font = title_font
365
        ws['G' + str(row_title + 1)].alignment = c_c_alignment
366
        ws['G' + str(row_title + 1)] = '样本标准差'
367
        ws['G' + str(row_title + 1)].border = f_border
368
369
        ws['H' + str(row_title + 1)].font = title_font
370
        ws['H' + str(row_title + 1)].alignment = c_c_alignment
371
        ws['H' + str(row_title + 1)] = '样本方差'
372
        ws['H' + str(row_title + 1)].border = f_border
373
374
        # table_data
375
376
        for i, value in enumerate(category):
377
            row_data = row_title + 2 + i
378
            ws['B' + str(row_data)].font = name_font
379
            ws['B' + str(row_data)].alignment = c_c_alignment
380
            ws['B' + str(row_data)] = reporting_period_data['names'][i] + " (" + reporting_period_data['units'][
381
                i] + "/M²)"
382
            ws['B' + str(row_data)].border = f_border
383
384
            ws['C' + str(row_data)].font = name_font
385
            ws['C' + str(row_data)].alignment = c_c_alignment
386
            if reporting_period_data['means_per_unit_area'][i] \
387
                    or reporting_period_data['means_per_unit_area'][i] == 0:
388
                ws['C' + str(row_data)] = round(reporting_period_data['means_per_unit_area'][i], 2)
389
            ws['C' + str(row_data)].border = f_border
390
            ws['C' + str(row_data)].number_format = '0.00'
391
392
            ws['D' + str(row_data)].font = name_font
393
            ws['D' + str(row_data)].alignment = c_c_alignment
394
            if reporting_period_data['medians_per_unit_area'][i] \
395
                    or reporting_period_data['medians_per_unit_area'][i] == 0:
396
                ws['D' + str(row_data)] = round(reporting_period_data['medians_per_unit_area'][i], 2)
397
            ws['D' + str(row_data)].border = f_border
398
            ws['D' + str(row_data)].number_format = '0.00'
399
400
            ws['E' + str(row_data)].font = name_font
401
            ws['E' + str(row_data)].alignment = c_c_alignment
402
            if reporting_period_data['minimums_per_unit_area'][i] \
403
                    or reporting_period_data['minimums_per_unit_area'][i] == 0:
404
                ws['E' + str(row_data)] = round(reporting_period_data['minimums_per_unit_area'][i], 2)
405
            ws['E' + str(row_data)].border = f_border
406
            ws['E' + str(row_data)].number_format = '0.00'
407
408
            ws['F' + str(row_data)].font = name_font
409
            ws['F' + str(row_data)].alignment = c_c_alignment
410
            if reporting_period_data['maximums_per_unit_area'][i] \
411
                    or reporting_period_data['maximums_per_unit_area'][i] == 0:
412
                ws['F' + str(row_data)] = round(reporting_period_data['maximums_per_unit_area'][i], 2)
413
            ws['F' + str(row_data)].border = f_border
414
            ws['F' + str(row_data)].number_format = '0.00'
415
416
            ws['G' + str(row_data)].font = name_font
417
            ws['G' + str(row_data)].alignment = c_c_alignment
418
            if (reporting_period_data['stdevs_per_unit_area'][i]) \
419
                    or reporting_period_data['stdevs_per_unit_area'][i] == 0:
420
                ws['G' + str(row_data)] = round(reporting_period_data['stdevs_per_unit_area'][i], 2)
421
            ws['G' + str(row_data)].border = f_border
422
            ws['G' + str(row_data)].number_format = '0.00'
423
424
            ws['H' + str(row_data)].font = name_font
425
            ws['H' + str(row_data)].alignment = c_c_alignment
426
            if reporting_period_data['variances_per_unit_area'][i] \
427
                    or reporting_period_data['variances_per_unit_area'][i] == 0:
428
                ws['H' + str(row_data)] = round(reporting_period_data['variances_per_unit_area'][i], 2)
429
            ws['H' + str(row_data)].border = f_border
430
            ws['H' + str(row_data)].number_format = '0.00'
431
432
    ########################################################
433
    # Third: 详细数据
434
    # row_sat+row_title~ row_sat+row_title+time_len: line
435
    # row_sat+1+row_title: table title
436
    # i + row_sat + 2 + 9 * ca_len~: table_data
437
    ########################################################
438
    has_timestamps_flag = True
439
    if "timestamps" not in reporting_period_data.keys() or \
440
            reporting_period_data['timestamps'] is None or \
441
            len(reporting_period_data['timestamps']) == 0:
442
        has_timestamps_flag = False
443
444
    if has_timestamps_flag:
445
        timestamps = reporting_period_data['timestamps'][0]
446
        values = reporting_period_data['values']
447
        names = reporting_period_data['names']
448
        ca_len = len(names)
449
        time_len = len(timestamps)
450
        # title
451
        row_title = 9 * ca_len
452
        # row_st == row_statistical analysis table
453
        row_sat = 12 + 3 * ca_len
454
455
        ws['B' + str(row_sat+row_title)].font = title_font
456
        ws['B' + str(row_sat+row_title)] = name + ' 详细数据'
457
        # table_title
458
        ws['B' + str(row_sat+1+row_title)].fill = table_fill
459
        ws['B' + str(row_sat+1+row_title)].font = name_font
460
        ws['B' + str(row_sat+1+row_title)].alignment = c_c_alignment
461
        ws['B' + str(row_sat+1+row_title)] = "时间"
462
        ws['B' + str(row_sat+1+row_title)].border = f_border
463
464
        for i in range(0, ca_len):
465
            col = chr(ord('C') + i)
466
467
            ws[col + str(row_sat+1+row_title)].font = name_font
468
            ws[col + str(row_sat+1+row_title)].alignment = c_c_alignment
469
            ws[col + str(row_sat+1+row_title)] = names[i] + " - (" + reporting_period_data['units'][i] + ")"
470
            ws[col + str(row_sat+1+row_title)].border = f_border
471
        # table_date
472
        for i in range(0, time_len):
473
            rows = i + row_sat + 2 + 9 * ca_len
474
475
            ws['B' + str(rows)].font = name_font
476
            ws['B' + str(rows)].alignment = c_c_alignment
477
            ws['B' + str(rows)] = timestamps[i]
478
            ws['B' + str(rows)].border = f_border
479
480
            for index in range(0, ca_len):
481
                col = chr(ord('C') + index)
482
483
                ws[col + str(rows)].font = name_font
484
                ws[col + str(rows)].alignment = c_c_alignment
485
                ws[col + str(rows)] = round(values[index][i], 2)
486
                ws[col + str(rows)].number_format = '0.00'
487
                ws[col + str(rows)].border = f_border
488
489
        # 小计
490
        row_subtotals = row_sat + 2 + time_len + 9 * ca_len
491
        ws['B' + str(row_subtotals)].font = name_font
492
        ws['B' + str(row_subtotals)].alignment = c_c_alignment
493
        ws['B' + str(row_subtotals)] = "小计"
494
        ws['B' + str(row_subtotals)].border = f_border
495
496
        for i in range(0, ca_len):
497
            col = chr(ord('C') + i)
498
499
            ws[col + str(row_subtotals)].font = name_font
500
            ws[col + str(row_subtotals)].alignment = c_c_alignment
501
            ws[col + str(row_subtotals)] = round(reporting_period_data['subtotals'][i], 2)
502
            ws[col + str(row_subtotals)].border = f_border
503
            ws[col + str(row_subtotals)].number_format = '0.00'
504
505
        # LineChart
506
        for i in range(0, ca_len):
507
508
            lc = LineChart()
509
            lc.title = "报告期消耗" + " - " + names[i] + "(" + reporting_period_data['units'][i] + ")"
510
            lc.style = 10
511
            lc.height = 8.40  # cm 1.05*8 1.05cm = 30 pt
512
            lc.width = 31
513
            lc.x_axis.majorTickMark = 'in'
514
            lc.y_axis.majorTickMark = 'in'
515
            times = Reference(ws, min_col=2, min_row=row_sat + 2 + row_title,
516
                              max_row=row_sat + 2 + row_title + time_len)
517
            lc_data = Reference(ws, min_col=3 + i, min_row=row_sat + 1 + row_title,
518
                                max_row=row_sat + 1 + row_title + time_len)
519
            lc.add_data(lc_data, titles_from_data=True)
520
            lc.set_categories(times)
521
            ser = lc.series[0]
522
            ser.marker.symbol = "diamond"
523
            ser.marker.size = 5
524
            ws.add_chart(lc, 'B' + str(row_sat + 9 * i))
525
526
    filename = str(uuid.uuid4()) + '.xlsx'
527
    wb.save(filename)
528
529
    return filename
530