@@ -384,24 +384,46 @@ def to_dict(self):
384
384
dict_values = vars(self)
385
385
return dict_values
386
386
387
- def to_excel(self, filename=None, attributes=None, allValues=False):
388
- """ Save to an Excel file the values of EpytValues class
387
+ def to_excel(self, filename=None, attributes=None, allValues=False,
388
+ node_id_list=None, link_id_list=None, both=False, header=True):
389
+ """
390
+ Save to an Excel file the values of EpytValues class.
389
391
390
- :param self: Values to add to the Excel file
391
- :type self: EpytValues class
392
- :param filename: excel filename, defaults to None
392
+ :param filename: Excel filename, defaults to None
393
393
:type filename: str, optional
394
- :param attributes: attributes to add to the file, defaults to None
394
+ :param attributes: Attributes to add to the file, defaults to None
395
395
:type attributes: str or list of str, optional
396
- :param allValues: 'True' if all the values will be included in a
397
- separate sheet, defaults to False
396
+ :param allValues: If True, writes all the values into a separate "All values" sheet, defaults to False
398
397
:type allValues: bool, optional
398
+ :param node_id_list: Array of IDs for node-related attributes
399
+ :type node_id_list: list or np.ndarray, optional
400
+ :param link_id_list: Array of IDs for link-related attributes
401
+ :type link_id_list: list or np.ndarray, optional
402
+ :param both: If True, and ID array available, print both 'Index' and 'Id'. If no ID array, just Index.
403
+ If False and ID array available, print only 'Id'; if no ID array, print only 'Index'.
404
+ :type both: bool, optional
405
+ :param header: If False, remove the first row from all sheets and do not write column headers
406
+ :type header: bool, optional
399
407
:return: None
400
-
401
408
"""
409
+ node_keywords = ['nodequality', 'head', 'demand', 'pressure']
410
+ link_keywords = [
411
+ 'linkquality', 'flow', 'velocity', 'headloss',
412
+ 'Status', 'Setting', 'ReactionRate', 'StatusStr', 'FrictionFactor'
413
+ ]
414
+
415
+ def is_node_attribute(key):
416
+ key_lower = key.lower()
417
+ return (any(re.search(r'\b' + kw + r'\b', key_lower) for kw in node_keywords)
418
+ or 'node' in key_lower)
419
+
420
+ def is_link_attribute(key):
421
+ key_lower = key.lower()
422
+ return (any(re.search(r'\b' + kw + r'\b', key_lower) for kw in link_keywords)
423
+ or 'link' in key_lower)
424
+
402
425
if filename is None:
403
- rand_id = ''.join(random.choices(string.ascii_letters
404
- + string.digits, k=5))
426
+ rand_id = ''.join(random.choices(string.ascii_letters + string.digits, k=5))
405
427
filename = 'ToExcelfile_' + rand_id + '.xlsx'
406
428
if '.xlsx' not in filename:
407
429
filename = filename + '.xlsx'
@@ -414,58 +436,108 @@ def to_excel(self, filename=None, attributes=None, allValues=False):
414
436
else:
415
437
dictValss[i] = dictVals[i]
416
438
dictVals = dictValss
439
+
440
+ def process_dataframe(key, df):
441
+ header_labels = []
442
+ num_rows = len(df)
443
+ chosen_id_array = None
444
+
445
+ if is_node_attribute(key) and node_id_list is not None:
446
+ chosen_id_array = node_id_list
447
+ elif is_link_attribute(key) and link_id_list is not None:
448
+ chosen_id_array = link_id_list
449
+
450
+ print_id_col = False
451
+ print_index_col = False
452
+
453
+ if both:
454
+ print_index_col = True
455
+ if chosen_id_array is not None:
456
+ print_id_col = True
457
+ else:
458
+ if chosen_id_array is not None:
459
+ print_id_col = True
460
+ else:
461
+ print_index_col = True
462
+
463
+ if print_id_col and chosen_id_array is not None:
464
+ if len(chosen_id_array) != num_rows:
465
+ warnings.warn(
466
+ f"ID array length does not match rows for '{key}'. Truncating."
467
+ )
468
+ adjusted_id_array = chosen_id_array[:num_rows]
469
+ df.insert(0, 'Id', adjusted_id_array)
470
+ header_labels.append('Id')
471
+
472
+ if print_index_col:
473
+ index_values = list(range(1, num_rows + 1))
474
+ if print_id_col:
475
+ id_col = df.pop('Id')
476
+ df.insert(0, 'Index', index_values)
477
+ df.insert(1, 'Id', id_col)
478
+ header_labels.insert(0, 'Index')
479
+ else:
480
+ df.insert(0, "Index", index_values)
481
+ header_labels.insert(0, 'Index')
482
+
483
+ num_data_columns = df.shape[1] - len(header_labels)
484
+ if 'Time' in dictVals and len(dictVals['Time']) == num_data_columns:
485
+ header_labels.extend(dictVals['Time'])
486
+ else:
487
+ data_column_names = [f"Column{i + 1}" for i in range(num_data_columns)]
488
+ header_labels.extend(data_column_names)
489
+
490
+ df.columns = header_labels
491
+ return df
492
+
417
493
with pd.ExcelWriter(filename, mode="w") as writer:
418
- for key in dictVals:
419
- if 'Time' not in key:
420
- if not attributes:
421
- df = pd.DataFrame(dictVals[key])
422
- df.insert(0, "Index", list(range(1, len(dictVals[key]) + 1)), True)
423
- df.set_index("Index", inplace=True)
424
- df.to_excel(writer, sheet_name=key,
425
- header=dictVals['Time'])
426
- else:
427
- if not isList(attributes):
428
- attributes = [attributes]
429
- if key in attributes:
430
- df = pd.DataFrame(dictVals[key])
431
- df.insert(0, "Index", list(range(1, len(dictVals[key]) + 1)), True)
432
- df.set_index("Index", inplace=True)
433
- df.to_excel(writer,
434
- sheet_name=key,
435
- header=dictVals['Time'])
494
+
495
+ for key, data in dictVals.items():
496
+ if key == 'Time':
497
+ continue
498
+ if attributes and key not in attributes:
499
+ continue
500
+ if not isinstance(data, (list, np.ndarray, pd.Series, pd.DataFrame)):
501
+ continue
502
+
503
+ df = pd.DataFrame(data)
504
+ df = process_dataframe(key, df)
505
+
506
+ if not header:
507
+ df.columns = df.iloc[0]
508
+ df = df.iloc[1:]
509
+ df.to_excel(writer, sheet_name=key, index=False, header=True)
510
+ else:
511
+ df.to_excel(writer, sheet_name=key, index=False, header=True)
512
+
436
513
if allValues:
514
+ worksheet_name = 'All values'
437
515
first_iter = True
438
- titleFormat = writer.book.add_format(
439
- {'bold': True, 'align': 'center',
440
- 'valign': 'vcenter', 'font_size': 16})
441
- for key in dictVals:
442
- if key != 'Time' and not attributes:
443
- df = pd.DataFrame(dictVals[key])
444
- df.insert(0, "Index", list(range(1, len(dictVals[key]) + 1)), True)
445
- df.set_index("Index", inplace=True)
446
- if first_iter:
447
- df.to_excel(
448
- writer,
449
- sheet_name='All values',
450
- header=dictVals['Time'],
451
- startrow=1
452
- )
453
- writer.book.worksheets()[-1].write(0, 1, key,
454
- titleFormat)
455
- first_iter = False
456
- else:
457
- startrow = writer.book.worksheets()[-1].dim_rowmax \
458
- + 3
459
- writer.book.worksheets()[-1].write(startrow - 1,
460
- 1,
461
- key,
462
- titleFormat)
463
- df.to_excel(
464
- writer,
465
- sheet_name='All values',
466
- header=dictVals['Time'],
467
- startrow=startrow
468
- )
516
+ for key, data in dictVals.items():
517
+ if key == 'Time':
518
+ continue
519
+ if attributes and key not in attributes:
520
+ continue
521
+ if not isinstance(data, (list, np.ndarray, pd.Series, pd.DataFrame)):
522
+ print(f"Skipping key '{key}' due to unsupported data type: {type(data)}")
523
+ continue
524
+
525
+ df = pd.DataFrame(data)
526
+ df = process_dataframe(key, df)
527
+
528
+
529
+ worksheet = writer.sheets.get(worksheet_name)
530
+ if first_iter:
531
+ df.to_excel(writer, sheet_name=worksheet_name, index=False, header=header, startrow=1)
532
+ worksheet = writer.sheets[worksheet_name]
533
+ worksheet.write(0, 0, key)
534
+ first_iter = False
535
+ else:
536
+ startrow = worksheet.dim_rowmax + 3
537
+ worksheet.write(startrow - 1, 0, key)
538
+ df.to_excel(writer, sheet_name=worksheet_name, index=False, header=header, startrow=startrow)
539
+
540
+ print(f"Data successfully exported to {filename}")
469
541
470
542
def to_json(self, filename=None):
471
543
""" Transforms val class values to json object and saves them
0 commit comments