create_excel_tables.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. import pandas as pd
  2. import numpy as np
  3. # from pandas import DataFrame
  4. # from styleframe import StyleFrame
  5. import xlsxwriter
  6. import openpyxl
  7. # import Jinja2
  8. from openpyxl.worksheet.datavalidation import DataValidation
  9. # Values have to be a list of list
  10. # Title_string have to be a list of list of strings
  11. class CreateTable:
  12. def __init__(self, dict_, insert=True, path=None, index=None, axis=0, ordered_by=[], order=[]):
  13. self.insert = insert
  14. self.path = path
  15. self.index = index
  16. self.dict = dict_
  17. self.axis = axis
  18. self.ordered_by = ordered_by
  19. self.order = order
  20. self.column = []
  21. self.currency_format = []
  22. for key, v in self.dict.items():
  23. self.column += [key]
  24. if self.order:
  25. ordered_column = []
  26. for each_key in self.order:
  27. if each_key in self.column:
  28. ordered_column += [each_key]
  29. self.column.remove(each_key)
  30. else:
  31. assert (False, 'Order contains values which are not in the Table')
  32. self.column = ordered_column + self.column
  33. self.dataframes = pd.DataFrame(dict([(k, pd.Series(v)) for k, v in self.dict.items()]), columns=self.column)
  34. def create_writer(self):
  35. return pd.ExcelWriter(self.path, engine='xlsxwriter') # openpyxl xlsxwriter
  36. def create_openpyxl_writer(self):
  37. return pd.ExcelWriter(self.path, engine='openpyxl') # openpyxl xlsxwriter
  38. def load_openpyxl_workbook(self, additional_path=''):
  39. if additional_path:
  40. return openpyxl.load_workbook("dropdown.xlsx")
  41. return openpyxl.load_workbook("dropdown.xlsx")
  42. def create_workbook(self):
  43. return xlsxwriter.Workbook(self.path)
  44. def create_openpyxl_workbook(self):
  45. return openpyxl.Workbook(self.path)
  46. def get_dataframe(self):
  47. return self.dataframes
  48. def append_to_csv(self):
  49. self.dataframes.to_csv(path_or_buf=self.path, index=self.index, mode='a')
  50. def add_style_(self, style_dict):
  51. return self.dataframes.style.format(style_dict)
  52. def set_style_properties(self, style_dict):
  53. return self.dataframes.style.set_properties(**style_dict)
  54. def create_format(self):
  55. self.currency_format = self.create_workbook().add_format()
  56. def export_to_csv(self):
  57. if self.order:
  58. raise NotImplementedError
  59. if self.ordered_by == []:
  60. self.dataframes.to_csv(path_or_buf=self.path, index=self.index)
  61. else:
  62. self.dataframes = self.dataframes.sort_values(by=self.ordered_by, axis=self.axis)
  63. self.dataframes.to_csv(path_or_buf=self.path, index=self.index)
  64. def export_to_excel(self, writer, additional_dataframes=[]):
  65. if self.ordered_by == []:
  66. pass
  67. else:
  68. self.dataframes = self.dataframes.sort_values(by=self.ordered_by, axis=self.axis)
  69. # Format
  70. if self.currency_format:
  71. self.currency_format.set_align('center')
  72. else:
  73. self.create_format()
  74. self.currency_format.set_align('center')
  75. # First Tab
  76. self.dataframes.to_excel(excel_writer=writer, sheet_name='Karte ' + str(1), index=False)
  77. for column in self.dataframes:
  78. column_width = max(self.dataframes[column].astype(str).map(len).max(), len(column) + 5)
  79. col_idx = self.dataframes.columns.get_loc(column)
  80. writer.sheets['Karte ' + str(1)].set_column(col_idx, col_idx, column_width, cell_format=self.currency_format)
  81. # All other Tabs
  82. for count, each_dataframe in enumerate(additional_dataframes):
  83. each_dataframe.to_excel(writer, sheet_name='Karte ' + str(count + 2), index=False)
  84. for column in each_dataframe:
  85. column_width = max(each_dataframe[column].astype(str).map(len).max(), len(column) + 5)
  86. col_idx = each_dataframe.columns.get_loc(column)
  87. writer.sheets['Karte ' + str(count + 2)].set_column(col_idx, col_idx, column_width, cell_format=self.currency_format)
  88. writer.save()
  89. def append_df_to_xlsx(self, df): # TODO extract even more
  90. df_excel = pd.read_excel(self.path)
  91. self.dataframes = pd.concat([df_excel, df], ignore_index=True)
  92. self.export_to_excel(self.create_writer())
  93. def create_custom_excel_economy_calendar(self, writer):
  94. if self.ordered_by == []:
  95. pass
  96. else:
  97. self.dataframes = self.dataframes.sort_values(by=self.ordered_by, axis=self.axis)
  98. # Format
  99. self.currency_format = self.create_workbook().add_format()
  100. self.currency_format.set_align('center')
  101. self.currency_format.set_align('center')
  102. self.dataframes.to_excel(excel_writer=writer, sheet_name='Karte ' + str(1), index=False)
  103. for column in self.dataframes:
  104. column_width = max(self.dataframes[column].astype(str).map(len).max(), len(column) + 5)
  105. col_idx = self.dataframes.columns.get_loc(column)
  106. writer.sheets['Karte ' + str(1)].set_column(col_idx, col_idx, column_width, cell_format=self.currency_format)
  107. writer.save()
  108. def add_another_page_to_excel(self, additional_dataframes, writer):
  109. # Format
  110. currency_format = self.create_workbook().add_format()
  111. currency_format.set_align('center')
  112. currency_format.set_align('center')
  113. for count, each_dataframe in enumerate(additional_dataframes):
  114. each_dataframe.to_excel(writer, sheet_name='Karte ' + str(count + 2), index=False)
  115. for column in each_dataframe:
  116. column_width = max(each_dataframe[column].astype(str).map(len).max(), len(column) + 5)
  117. col_idx = each_dataframe.columns.get_loc(column)
  118. writer.sheets['Karte ' + str(count + 2)].set_column(col_idx, col_idx, column_width, cell_format=currency_format)
  119. return writer
  120. def create_hyperlink_from_string(self, name: str):
  121. self.dataframes.style.format({name: make_clickable})
  122. def make_clickable(val):
  123. # target _blank to open new window
  124. return '<a target="_blank" href="{}">{}</a>'.format(val, val)
  125. class XlsxWriterClass:
  126. def __init__(self, path, another_sheet=''):
  127. '''
  128. :param path: Absolute Path
  129. :param list_of_sheets: in this version only two sheets can be created. A little bit sloppy..
  130. '''
  131. self.path = path
  132. self.wb = xlsxwriter.Workbook(self.path)
  133. self.ws = self.wb.add_worksheet('Karte 1')
  134. self.last_column = 0
  135. self.alphabet = ['A', 'B', 'C', 'D', 'E',
  136. 'F', 'G', 'H', 'I', 'J',
  137. 'K', 'L', 'M', 'N', 'O',
  138. 'P', 'Q', 'R', 'S', 'T',
  139. 'U', 'V', 'W', 'X', 'Y',
  140. 'Z',
  141. 'AA', 'AB', 'AC', 'AD', 'AE',
  142. 'AF', 'AG', 'AH', 'AI', 'AJ',
  143. 'AK', 'AL', 'AM', 'AN', 'AO',
  144. 'AP', 'AQ', 'AR', 'AS', 'AT',
  145. 'AU', 'AV', 'AW', 'AX', 'AY',
  146. 'AZ', ]
  147. if another_sheet:
  148. self.another_sheet = self.wb.add_worksheet('Karte2')
  149. self.last_column_sheet2 = 1
  150. def create_format_for_data(self, added_style):
  151. self.style_ = self.wb.add_format(added_style)
  152. def del_current_format_for_data(self):
  153. self.style_ = False
  154. def set_column_prop(self, col, width):
  155. self.ws.set_column(first_col=col, last_col=col, width=width)
  156. def set_row(self, count_rows, height):
  157. for row in range(1, count_rows):
  158. self.ws.set_row(row, height=height)
  159. def write_data_in_free_column_with_bold_header(self, data, column_range=1, format_=False, data_with_own_format={}):
  160. '''
  161. :param data: dict format [key: list_of_values] or list of lists
  162. :param column_range: only for list of lists
  163. :param data_with_own_format: tuple of data and format : (data, format)
  164. :return:
  165. '''
  166. assert column_range + self.last_column <= len(self.alphabet), 'Alphabet len is to small add new Columns [self.alphabet]'
  167. if data_with_own_format:
  168. special_data = data_with_own_format[0]
  169. special_data_format = data_with_own_format[1]
  170. if isinstance(data, dict):
  171. for col, key in enumerate(data.keys()):
  172. offset=0
  173. # Header
  174. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1), key, self.wb.add_format({'bold': True}))
  175. if data_with_own_format:
  176. for row in range(1, 1 + len(special_data[key])):
  177. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), special_data[key][row - 1],
  178. self.wb.add_format(special_data_format))
  179. offset += 1
  180. for row in range(1, 1 + len(data[key])):
  181. if format_:
  182. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row+offset), data[key][row - 1], self.style_)
  183. else:
  184. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row+offset), data[key][row - 1])
  185. self.last_column += len(data.keys())
  186. else:
  187. for col in range(0, column_range):
  188. offset=0
  189. # Header
  190. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1), data[col][0], {'bold': True})
  191. if data_with_own_format:
  192. for row in range(1, 1 + len(special_data[col])):
  193. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), special_data[col][row],
  194. self.wb.add_format(special_data_format))
  195. offset += 1
  196. for row in range(1, 1 + len(data[col])):
  197. if format_:
  198. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row+offset), data[col][row], self.style_)
  199. else:
  200. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row+offset), data[col][row])
  201. self.last_column += len(data)
  202. def write_dict_of_dicts_in_free_column_with_color_for_each_cell(self, data, column_range=1):
  203. '''
  204. :param data: dict format [key: {Color: [...], Value : [...]}]
  205. :param column_range: len of used columns for dict only in assertions
  206. :return:
  207. '''
  208. assert column_range + self.last_column <= len(self.alphabet), 'Alphabet len is to small add new Columns [self.alphabet]'
  209. for col, key in enumerate(data.keys()):
  210. # Header
  211. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1), key, self.wb.add_format({'bold': True}))
  212. for row in range(1, 1 + len(data[key])):
  213. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), data[key][row - 1]['Value'],
  214. self.wb.add_format({'font_color': data[key][row - 1]['Color']}))
  215. self.last_column += len(data.keys())
  216. def write_data_in_free_column_with_custom_style_and_dropdown(self, data, column_range=1, format_=False, source=[1]):
  217. '''
  218. :param data: dict format [key: list_of_values] or list of lists
  219. :param column_range: only for list of lists
  220. :param source : list of dropdown values
  221. :return:
  222. '''
  223. assert column_range + self.last_column <= len(self.alphabet), 'Alphabet len is to small add new Columns [self.alphabet]'
  224. if isinstance(data, dict):
  225. for col, key in enumerate(data.keys()):
  226. # Header
  227. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1), key, self.wb.add_format({'bold': True}))
  228. for row in range(1, 1 + len(data[key])):
  229. if format_:
  230. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), data[key][row - 1], self.style_)
  231. self.ws.conditional_format('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), {'type': 'cell',
  232. 'criteria': '>=',
  233. 'value': 10,
  234. 'format': self.wb.add_format(
  235. {
  236. 'bg_color': '#90ee90',
  237. 'font_color': 'black'})})
  238. self.ws.data_validation('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), {'validate': 'list',
  239. 'source': source
  240. })
  241. else:
  242. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), data[key][row - 1])
  243. self.ws.conditional_format('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), {'type': 'cell',
  244. 'criteria': '>=',
  245. 'value': 10,
  246. 'format': self.wb.add_format(
  247. {
  248. 'bg_color': '#90ee90',
  249. 'font_color': 'black'})})
  250. self.ws.data_validation('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), {'validate': 'list',
  251. 'source': source
  252. })
  253. self.last_column += len(data.keys())
  254. else:
  255. for col in range(0, column_range):
  256. # Header
  257. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1), data[col][0], {'bold': True})
  258. for row in range(1, 1 + len(data[col])):
  259. if format_:
  260. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), data[col][row], self.style_)
  261. self.ws.conditional_format('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), {'type': 'cell',
  262. 'criteria': '>=',
  263. 'value': 10,
  264. 'format': self.wb.add_format(
  265. {
  266. 'bg_color': '#90ee90',
  267. 'font_color': 'black'})})
  268. self.ws.data_validation('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), {'validate': 'list',
  269. 'source': source
  270. })
  271. else:
  272. self.ws.write('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), data[col][row])
  273. self.ws.conditional_format('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), {'type': 'cell',
  274. 'criteria': '>=',
  275. 'value': 10,
  276. 'format': self.wb.add_format(
  277. {
  278. 'bg_color': '#90ee90',
  279. 'font_color': 'black'})})
  280. self.ws.data_validation('{}{}'.format(self.alphabet[col + self.last_column], 1 + row), {'validate': 'list',
  281. 'source': source
  282. })
  283. self.last_column += len(data)
  284. def write_data_in_free_column_on_another_sheet(self, data, column_range=1, format_=False):
  285. '''
  286. TODO This function does not work properly, generalization is recommended
  287. :param data: dict format or list of lists
  288. :param column_range:
  289. :return:
  290. '''
  291. assert column_range <= len(self.alphabet), 'Alphabet len is to small add new Columns [self.alphabet]'
  292. if isinstance(data, dict):
  293. pass
  294. else:
  295. for col in range(0, column_range): # Generates 99 "ip" address in the Column A;
  296. for row in range(self.last_column_sheet2, self.last_column_sheet2 + len(data[col])):
  297. if format_:
  298. self.another_sheet.write('{}{}'.format(self.alphabet[col], row), data[col][row - 1], self.style_)
  299. else:
  300. self.another_sheet.write('{}{}'.format(self.alphabet[col], row), data[col][row - 1])
  301. self.last_column_sheet2 = len(data)
  302. def save_and_close_excel(self):
  303. self.wb.close()