@@ -384,24 +384,46 @@ def to_dict(self):
384384 dict_values = vars(self)
385385 return dict_values
386386
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.
389391
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
393393 :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
395395 :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
398397 :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
399407 :return: None
400-
401408 """
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+
402425 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))
405427 filename = 'ToExcelfile_' + rand_id + '.xlsx'
406428 if '.xlsx' not in filename:
407429 filename = filename + '.xlsx'
@@ -414,58 +436,108 @@ def to_excel(self, filename=None, attributes=None, allValues=False):
414436 else:
415437 dictValss[i] = dictVals[i]
416438 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+
417493 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+
436513 if allValues:
514+ worksheet_name = 'All values'
437515 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}")
469541
470542 def to_json(self, filename=None):
471543 """ Transforms val class values to json object and saves them
0 commit comments