rephorm 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. rephorm/__init__.py +19 -0
  2. rephorm/decorators/__init__.py +0 -0
  3. rephorm/decorators/settings_validation.py +49 -0
  4. rephorm/dict/__init__.py +1 -0
  5. rephorm/dict/colors.py +22 -0
  6. rephorm/dict/legend_positions.py +136 -0
  7. rephorm/dict/styles.py +206 -0
  8. rephorm/dict/update_layout.py +129 -0
  9. rephorm/dict/update_traces.py +90 -0
  10. rephorm/object_mappers/__init__.py +0 -0
  11. rephorm/object_mappers/_globals.py +16 -0
  12. rephorm/object_mappers/_utilities/__init__.py +0 -0
  13. rephorm/object_mappers/_utilities/chart_mapper_utility.py +34 -0
  14. rephorm/object_mappers/_utilities/grid_mapper_utility.py +11 -0
  15. rephorm/object_mappers/_utilities/table_mapper_utility.py +59 -0
  16. rephorm/object_mappers/chapter_mapper.py +82 -0
  17. rephorm/object_mappers/chart_mapper.py +120 -0
  18. rephorm/object_mappers/chart_series_mapper.py +52 -0
  19. rephorm/object_mappers/grid_mapper.py +106 -0
  20. rephorm/object_mappers/page_break_mapper.py +8 -0
  21. rephorm/object_mappers/report_mapper.py +76 -0
  22. rephorm/object_mappers/table_mapper.py +191 -0
  23. rephorm/object_mappers/table_section_mapper.py +41 -0
  24. rephorm/object_mappers/table_series_mapper.py +79 -0
  25. rephorm/object_mappers/text_mapper.py +36 -0
  26. rephorm/object_params/__init__.py +0 -0
  27. rephorm/object_params/settings.py +184 -0
  28. rephorm/objects/__init__.py +0 -0
  29. rephorm/objects/_utilities/__init__.py +0 -0
  30. rephorm/objects/_utilities/settings_container.py +8 -0
  31. rephorm/objects/chapter.py +44 -0
  32. rephorm/objects/chart.py +70 -0
  33. rephorm/objects/chart_series.py +40 -0
  34. rephorm/objects/footnote.py +13 -0
  35. rephorm/objects/grid.py +57 -0
  36. rephorm/objects/page_break.py +13 -0
  37. rephorm/objects/report.py +196 -0
  38. rephorm/objects/table.py +76 -0
  39. rephorm/objects/table_section.py +48 -0
  40. rephorm/objects/table_series.py +36 -0
  41. rephorm/objects/text.py +35 -0
  42. rephorm/utility/PDF.py +80 -0
  43. rephorm/utility/__init__.py +0 -0
  44. rephorm/utility/add_style_prefix.py +30 -0
  45. rephorm/utility/fonts/OpenSans-Bold.ttf +0 -0
  46. rephorm/utility/fonts/OpenSans-BoldItalic.ttf +0 -0
  47. rephorm/utility/fonts/OpenSans-Italic.ttf +0 -0
  48. rephorm/utility/fonts/OpenSans.ttf +0 -0
  49. rephorm/utility/fonts/__init__.py +0 -0
  50. rephorm/utility/fonts/font_loading.py +74 -0
  51. rephorm/utility/is_set.py +9 -0
  52. rephorm/utility/merge/__init__.py +0 -0
  53. rephorm/utility/merge/chart_properties_manager.py +80 -0
  54. rephorm/utility/merge/merge_settings.py +134 -0
  55. rephorm/utility/merge/merge_styles.py +79 -0
  56. rephorm/utility/merge/pdf_merger.py +29 -0
  57. rephorm/utility/report/__init__.py +0 -0
  58. rephorm/utility/report/add_footnotes.py +46 -0
  59. rephorm/utility/report/cleanup_utility.py +19 -0
  60. rephorm/utility/report/footnotes_counter.py +15 -0
  61. rephorm/utility/report/image_utility.py +14 -0
  62. rephorm/utility/report/layout_utility.py +59 -0
  63. rephorm/utility/report/range_utility.py +94 -0
  64. rephorm/utility/report/report_utility.py +93 -0
  65. rephorm/utility/report/resolve_color.py +39 -0
  66. rephorm/utility/report/table_utility.py +71 -0
  67. rephorm/utility/report/title_utility.py +49 -0
  68. rephorm/utility/unit_converter.py +12 -0
  69. rephorm-1.0.1.dist-info/METADATA +41 -0
  70. rephorm-1.0.1.dist-info/RECORD +73 -0
  71. rephorm-1.0.1.dist-info/WHEEL +5 -0
  72. rephorm-1.0.1.dist-info/licenses/LICENSE +21 -0
  73. rephorm-1.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,191 @@
1
+ from fpdf import FontFace
2
+
3
+ from rephorm.object_mappers._utilities.table_mapper_utility import (
4
+ get_max_numerical_width,
5
+ get_max_width,
6
+ )
7
+ from rephorm.utility.report.add_footnotes import add_footnotes_at_bottom
8
+ from rephorm.utility.report.footnotes_counter import generate_footnote_numbers
9
+ from rephorm.utility.report.report_utility import get_page_dimensions
10
+ from rephorm.utility.report.resolve_color import resolve_color
11
+ from rephorm.utility.report.title_utility import add_title_with_references
12
+
13
+
14
+ class TableMapper:
15
+ def __init__(self, table):
16
+ self.table = table
17
+
18
+ def add_to_pdf(self, **kwargs):
19
+
20
+ pdf = kwargs["pdf"]
21
+ highlight = []
22
+ x = kwargs["x"]
23
+ w = kwargs["w"]
24
+ h = kwargs["h"]
25
+ y = kwargs["y"]
26
+
27
+ title_bottom_padding = self.table.settings.styles["report"]["title_bottom_padding"]
28
+ #Todo: Consider extracting context based on caller. So we do not need to deal with string checks. Discuss with Sergey.
29
+ context = kwargs.get("context", None)
30
+ custom_width = self.table.width
31
+ footer_top_padding = self.table.settings.styles["report"]["footer"]["top_padding"]
32
+ footer_top_margin = self.table.settings.styles["report"]["footer"]["top_margin"]
33
+ footer_last_y = kwargs["footer_last_y"] if "footer_last_y" in kwargs else None
34
+
35
+ # Todo: Consider replacing (full_width_grid) conditional based on grid row settings? if nrow and ncol = 1? Talk to Sergey why
36
+ full_width_grid = (w == pdf.epw)
37
+ is_multi_cell_grid = context == "grid" and not full_width_grid
38
+
39
+ skip_cols = 1
40
+ headers = [""]
41
+
42
+ pdf.set_xy(x, y)
43
+ page_width, _ = get_page_dimensions(pdf)
44
+
45
+ num_col_width = get_max_numerical_width(
46
+ self.table,
47
+ pdf,
48
+ font_family=self.table.settings.styles["table"]["series"]["font_family"],
49
+ font_size=self.table.settings.styles["table"]["series"]["font_size"],
50
+ biggest_nr="10000",
51
+ )
52
+
53
+ title_col_width = get_max_width(
54
+ self.table,
55
+ pdf,
56
+ font_family=self.table.settings.styles["table"]["series"]["font_family"],
57
+ font_size=self.table.settings.styles["table"]["series"]["font_size"],
58
+ parameter="title",
59
+ max_width=0,
60
+ )
61
+ unit_col_width = get_max_width(
62
+ self.table,
63
+ pdf,
64
+ font_family=self.table.settings.styles["table"]["series"]["font_family"],
65
+ font_size=self.table.settings.styles["table"]["series"]["font_size"],
66
+ parameter="unit",
67
+ max_width=0,
68
+ )
69
+
70
+ if self.table.settings.highlight is not None:
71
+ highlight = self.table._get_table_highlight()
72
+
73
+ span = self.table._get_span()
74
+
75
+ if self.table.settings.show_units:
76
+ skip_cols += 1
77
+
78
+ if self.table.settings.show_units:
79
+ headers = headers + ["Units"]
80
+
81
+ heading_data = [
82
+ headers + list(span.to_compact_strings()),
83
+ ]
84
+
85
+ heading = heading_data[0][skip_cols:]
86
+
87
+ num_col_padding = 10
88
+
89
+ col_widths = (
90
+ [
91
+ title_col_width + 10
92
+ ] # TODO: first column width | We introduce param for this. the name of param: title_col_width
93
+ + [unit_col_width + 0]
94
+ * self.table.settings.show_units # TODO: second column width | We introduce param for this. the name of param: unit_col_width
95
+ + [num_col_width + num_col_padding] * len(heading) # numerical columns width
96
+ )
97
+
98
+ # we use effective page width here (excluding margins)
99
+ page_width = pdf.epw
100
+
101
+ natural_table_width = sum(col_widths) + 10
102
+
103
+ if natural_table_width > page_width:
104
+ table_width = page_width
105
+ else:
106
+ if is_multi_cell_grid:
107
+ table_width = w
108
+ else:
109
+ table_width = natural_table_width
110
+
111
+ text_align = ["L"] * skip_cols + ["R"] * len(heading)
112
+
113
+ h_data = headers + heading
114
+
115
+ # ----------------- Set Table Title -----------------
116
+
117
+ footnote_references = generate_footnote_numbers(self.table.footnotes)
118
+ y = add_title_with_references(
119
+ pdf=pdf,
120
+ title=self.table.title,
121
+ references=footnote_references,
122
+ font_family=self.table.settings.styles["table"]["title"]["font_family"],
123
+ font_size=self.table.settings.styles["table"]["title"]["font_size"],
124
+ font_style=self.table.settings.styles["table"]["title"]["font_style"],
125
+ title_y=y,
126
+ cell_width=w,
127
+ )
128
+ if bool(self.table.footnotes):
129
+ footer_last_y = add_footnotes_at_bottom(
130
+ pdf,
131
+ self.table.footnotes,
132
+ footnote_references,
133
+ last_y=footer_last_y,
134
+ font_family=self.table.settings.styles["footnotes"]["font_family"],
135
+ font_size=self.table.settings.styles["footnotes"]["font_size"],
136
+ font_style=self.table.settings.styles["footnotes"]["font_style"],
137
+ footer_padding=footer_top_padding,
138
+ footer_top_margin=footer_top_margin,
139
+ )
140
+
141
+ # Todo: Consider: title padding could be part of add_title_with_ref function, so we only pass here Y after calling that func)
142
+ pdf.set_y(y + title_bottom_padding)
143
+
144
+ # ----------------- Set Table Header -----------------
145
+ with pdf.table(
146
+ width=custom_width if custom_width else table_width,
147
+ col_widths=col_widths,
148
+ text_align=text_align,
149
+ align="l" if is_multi_cell_grid else "c",
150
+ # TODO: ADD border settings to styles for table
151
+ borders_layout="SINGLE_TOP_LINE",
152
+ # line height sets the height of rows, 1,4 is multiplier. (We cannot precisely extract height of the text)
153
+ # Todo: Consider extracting this to param/styles, like inrow_offset...
154
+ line_height=self.table.settings.styles["table"]["series"]["font_size"]
155
+ * 1.4,
156
+ ) as pdf_table:
157
+
158
+ heading_row = pdf_table.row()
159
+ header_color = resolve_color(
160
+ self.table.settings.styles["table"]["heading"]["highlight_color"]
161
+ )
162
+
163
+ for i, header in enumerate(h_data):
164
+ # Todo: Remove Grey and etc params from table object and move them to styles
165
+ style = FontFace(
166
+ emphasis=self.table.settings.styles["table"]["heading"][
167
+ "font_style"
168
+ ],
169
+ size_pt=self.table.settings.styles["table"]["heading"]["font_size"],
170
+ fill_color=header_color if i in highlight else "#FFFFFF00",
171
+ family=self.table.settings.styles["table"]["heading"][
172
+ "font_family"
173
+ ],
174
+ color=resolve_color(
175
+ self.table.settings.styles["table"]["heading"]["font_color"]
176
+ ),
177
+ )
178
+
179
+ heading_row.cell(header, style=style)
180
+
181
+ # ----------------- Set Table Rows -----------------
182
+ for item in self.table.CHILDREN:
183
+ mapper = item._get_mapper()
184
+ mapper.add_to_pdf(
185
+ span=span,
186
+ pdf_table=pdf_table,
187
+ highlight=highlight,
188
+ n_cols=len(col_widths),
189
+ show_units=self.table.settings.show_units,
190
+ footer_last_y=footer_last_y,
191
+ )
@@ -0,0 +1,41 @@
1
+ from fpdf import FontFace
2
+ from rephorm.utility.report.resolve_color import resolve_color
3
+
4
+ class TableSectionMapper:
5
+ def __init__(self, table_section):
6
+ self.table_section = table_section
7
+
8
+ def add_to_pdf(self, **kwargs):
9
+
10
+ n_cols = kwargs["n_cols"]
11
+ highlight = kwargs["highlight"]
12
+ pdf_table = kwargs["pdf_table"]
13
+ span = kwargs["span"]
14
+ title_row = pdf_table.row()
15
+
16
+
17
+ for i in range(n_cols):
18
+
19
+ color = resolve_color(self.table_section.settings.styles["table"]["section"]["highlight_color"])
20
+
21
+ style = FontFace(
22
+ emphasis= self.table_section.settings.styles["table"]["section"]["font_style"],
23
+ size_pt=self.table_section.settings.styles["table"]["section"]["font_size"],
24
+ fill_color= color if i in highlight else "#FFFFFF00",
25
+ family=self.table_section.settings.styles["table"]["section"]["font_family"],
26
+ color=self.table_section.settings.styles["table"]["section"]["font_color"],
27
+ )
28
+
29
+ content = self.table_section.TITLE if i == 0 else ""
30
+ title_row.cell(content, style=style)
31
+
32
+ for item in self.table_section.CHILDREN:
33
+ mapper = item._get_mapper()
34
+ mapper.add_to_pdf(span=span, pdf_table=pdf_table, highlight=highlight, show_units=self.table_section.settings.show_units)
35
+
36
+
37
+
38
+
39
+
40
+
41
+
@@ -0,0 +1,79 @@
1
+
2
+ from fpdf import FontFace
3
+
4
+ from rephorm.utility.report.resolve_color import resolve_color
5
+ from rephorm.utility.report.table_utility import prepare_row
6
+
7
+
8
+ class TableSeriesMapper:
9
+ def __init__(self, series):
10
+ self.series = series
11
+
12
+ def add_to_pdf(self, **kwargs):
13
+
14
+
15
+ highlight = kwargs["highlight"]
16
+ pdf_table = kwargs["pdf_table"]
17
+ span = kwargs["span"]
18
+ show_units = kwargs["show_units"]
19
+ #fpdf = kwargs["fpdf"]#todo: add to kwargs
20
+ # last_y = kwargs["footer_last_y"] # We get last Y from parent,
21
+ # so to add footnote to the bottom of the page right after parent footnotes.
22
+
23
+ # Get start page nr before adding row
24
+ # start_page_nr = fpdf.page_no()
25
+
26
+ # add row
27
+ element_row = pdf_table.row()
28
+
29
+ #get page number after adding row
30
+ # current_page_nr = fpdf.page_no()
31
+
32
+ # In case the first element is on the next page, we need to reset last_y to none,
33
+ # so that the add_footnotes_at_bottom function recalculates footnote positions
34
+ # if current_page_nr > start_page_nr:
35
+ # last_y = None
36
+
37
+ #Gen references here, pass it down to prep row and later to add_footnotes_. ...
38
+ # footnote_references = generate_footnote_numbers(self.series.footnotes)
39
+
40
+ row = prepare_row(
41
+ series=self.series,
42
+ compare_style=self.series.settings.compare_style,
43
+ span=span,
44
+ show_units=show_units,
45
+ unit=self.series.unit,
46
+ title=self.series.title,
47
+ decimal_precision=self.series.settings.decimal_precision,
48
+ footnote_references=None, # Todo: footnote_references
49
+ )
50
+
51
+ # add_footnotes_at_bottom(footnotes=self.series.footnotes,
52
+ # last_y=last_y,)
53
+
54
+ color = resolve_color(self.series.settings.styles["table"]["series"]["highlight_color"])
55
+
56
+ # I think we use similar logic in couple places, look if it's the case and put in utility.
57
+ for i, cell in enumerate(row): # Process each cell in the row
58
+
59
+ style = FontFace(
60
+ family=self.series.settings.styles["table"]["series"]["font_family"],
61
+ emphasis=self.series.settings.styles["table"]["series"]["font_style"],
62
+ size_pt=self.series.settings.styles["table"]["series"]["font_size"],
63
+ fill_color= color if i in highlight else "#FFFFFF00",
64
+ color=resolve_color(self.series.settings.styles["table"]["series"]["font_color"]),
65
+ )
66
+
67
+ # ^^^^^^^^^^^^^^^^^^^^^^^^^^
68
+
69
+ if self.series.settings.comparison_series:
70
+ padding = (-self.series.settings.styles["table"]["series"]["font_size"]*0.6, 0, 5, 0)
71
+ style.size_pt *= 0.8 # Sets size of comparison series
72
+ else:
73
+ padding = (0, 0, 0, 0)
74
+
75
+ element_row.cell(
76
+ cell,
77
+ style=style,
78
+ padding = padding,
79
+ )
@@ -0,0 +1,36 @@
1
+ from rephorm.utility.report.title_utility import add_title_with_references
2
+
3
+
4
+ class TextMapper:
5
+ def __init__(self, text):
6
+ self.text = text
7
+
8
+ def add_to_pdf(self, **kwargs):
9
+ pdf = kwargs["pdf"]
10
+ w = kwargs["w"]
11
+ y = kwargs["y"]
12
+ x = kwargs["x"]
13
+
14
+ family = self.text.settings.styles["text"]["title"]["font_family"]
15
+ size = self.text.settings.styles["text"]["title"]["font_size"]
16
+ style = self.text.settings.styles["text"]["title"]["font_style"]
17
+
18
+ # todo: check multipliers everywhere and use line height const for it.
19
+ line_height = 1.5 # todo: consider extracting to styles, once again.
20
+
21
+ y = add_title_with_references(pdf=pdf, title=self.text.title, references=None,
22
+ font_family=family, font_size=size, font_style=style, title_y=y)
23
+
24
+ pdf.set_font(family=self.text.settings.styles["text"]["font_family"],
25
+ size=self.text.settings.styles["text"]["font_size"],
26
+ style=self.text.settings.styles["text"]["font_style"])
27
+
28
+ pdf.set_xy(x, y)
29
+
30
+ pdf.multi_cell(
31
+ w=w,
32
+ h=self.text.settings.styles["text"]["font_size"] * line_height,
33
+ txt=self.text.TEXT,
34
+ align=self.text.align,
35
+ markdown=self.text.markdown,
36
+ )
File without changes
@@ -0,0 +1,184 @@
1
+ from typing import Dict
2
+ import irispie as ir
3
+
4
+ from rephorm.dict.styles import default_styles
5
+
6
+ """
7
+ This Dictionary defines all possible parameters that can be applied to any object within the report.
8
+
9
+ - default_value - default value of the parameter
10
+ - type - for type checking | if type is None, then it is not being checked ("useful" in case of Complex data Types)
11
+ - ultimates - list of objects that should get/receive this parameter
12
+ """
13
+
14
+ object_params = {
15
+ "span": {
16
+ "default_value": ir.start >> ir.end,
17
+ "type": ir.Span,
18
+ "ultimates": ["Chart", "Table", "ChartSeries", "TableSeries"],
19
+ },
20
+ "highlight" : {
21
+ "default_value": None,
22
+ "type": ir.Span,
23
+ "ultimates": ["Chart", "Table", "TableSection", "TableSeries"],
24
+ },
25
+ "show_legend" : {
26
+ "default_value": True,
27
+ "type": bool,
28
+ "ultimates": ["ChartSeries"],
29
+ },
30
+ "yaxis": {
31
+ "default_value": "left",
32
+ "type": str,
33
+ "possible_values":
34
+ {"left", "right"},
35
+ "ultimates": ["ChartSeries"],
36
+ },
37
+ "update_traces" : { # todo: check if this is used
38
+ "default_value": None,
39
+ "type": Dict,
40
+ "ultimates": ["ChartSeries"],
41
+ },
42
+ "show_grid" : {
43
+ "default_value": True,
44
+ "type": bool,
45
+ "ultimates": ["Chart"],
46
+ },
47
+ "axis_border" : {
48
+ "default_value": False,
49
+ "type": bool,
50
+ "ultimates": ["Chart"],
51
+ },
52
+ "xaxis_title" : {
53
+ "default_value": "",
54
+ "type": str,
55
+ "ultimates": ["Chart"],
56
+ },
57
+ "yaxis_title" : {
58
+ "default_value": "",
59
+ "type": str,
60
+ "ultimates": ["Chart"],
61
+ },
62
+ "yaxis2_title" : {
63
+ "default_value": "",
64
+ "type": str,
65
+ "ultimates": ["Chart"],
66
+ },
67
+ "legend_orientation" : {
68
+ "default_value": "h",
69
+ "type": str,
70
+ "ultimates": ["Chart"],
71
+ },
72
+ "legend_position" : {
73
+ "default_value": "SO",
74
+ "type": str,
75
+ "possible_values":
76
+ {"N", "S", "E", "W",
77
+ "NE", "NW", "SE", "SW",
78
+ "NO", "SO", "EO", "WO",
79
+ "NEO", "NWO", "SEO", "SWO"},
80
+ "ultimates": ["Chart"],
81
+ },
82
+ "ncol" : {
83
+ "default_value": 2,
84
+ "type": int,
85
+ "ultimates": ["Grid"],
86
+ },
87
+ "nrow" : {
88
+ "default_value": 2,
89
+ "type": int,
90
+ "ultimates": ["Grid"],
91
+ },
92
+ "apply_report_layout": {
93
+ "default_value": False,
94
+ "type": bool,
95
+ "ultimates": ["Chart"],
96
+ },
97
+ "layout": {
98
+ "default_value": None,
99
+ "type": None,
100
+ "ultimates": ["Grid"],
101
+ },
102
+ "comparison_series" : {
103
+ "default_value": False,
104
+ "type": bool,
105
+ "ultimates": ["TableSeries"],
106
+ },
107
+ "series_type" : {
108
+ "default_value": "line",
109
+ "type": str,
110
+ "possible_values": {"line", "bar", "contribution_bar", "barcon", "conbar", "bar_stack", "bar_group", "bar_overlay", "bar_relative"},
111
+ "ultimates": ["Chart", "ChartSeries"],
112
+ },
113
+ "markers_mode" : {
114
+ "default_value": "lines",
115
+ "type": str,
116
+ "possible_values": {"lines+markers", "lines", "markers"},
117
+ "ultimates": ["ChartSeries"], # TEST IT: Chart was removed as Chart should not use it in any way
118
+ },
119
+ "legend" : {
120
+ "default_value": None,
121
+ "type": tuple,
122
+ "ultimates": ["Chart", "ChartSeries"],
123
+ },
124
+ "compare_style" : {
125
+ "default_value": "",
126
+ "type": str,
127
+ "ultimates": ["TableSeries"],
128
+ },
129
+ "marker_symbol" : {
130
+ "default_value": "asterisk",
131
+ "type": str,
132
+ "ultimates": ["Chart", "ChartSeries"],
133
+ },
134
+ "orientation" : {
135
+ "default_value": "P",
136
+ "type": str,
137
+ "ultimates": ["Report"],
138
+ },
139
+ "unit" : {
140
+ "default_value": "pt",
141
+ "type": str,
142
+ "ultimates": ["Report"],
143
+ },
144
+ "format" : {
145
+ "default_value": "A4",
146
+ "type": str,
147
+ "ultimates": ["Report"],
148
+ },
149
+ "decimal_precision" : {
150
+ "default_value": 1,
151
+ "type": int,
152
+ "ultimates": ["TableSeries"],
153
+ },
154
+ "show_units" : {
155
+ "default_value": True,
156
+ "type": bool,
157
+ "ultimates": ["TableSection", "Table"],
158
+ },
159
+ "zeroline" : {
160
+ "default_value": False,
161
+ "type": bool,
162
+ "ultimates": ["Chart"],
163
+ },
164
+ "legend_ncol" : {
165
+ "default_value": None,
166
+ "type": int,
167
+ "ultimates": ["Chart"],
168
+ },
169
+ "frequency" : {
170
+ "default_value": None,
171
+ "type": None, #Cant check this one
172
+ "ultimates": ["Table"],
173
+ },
174
+ "styles": {
175
+ "default_value": default_styles(),
176
+ "type": None, # TODO: change to Dict later on
177
+ "ultimates": ["Report", "Chapter", "TableSection", "ChartSeries", "TableSeries", "Table", "Chart", "Grid", "Text"],
178
+ },
179
+ "logo": {
180
+ "default_value": "",
181
+ "type": str,
182
+ "ultimates": ["Report"],
183
+ }
184
+ }
File without changes
File without changes
@@ -0,0 +1,8 @@
1
+ """
2
+ Generic settings container.
3
+ Encapsulates all settings for a specific object.
4
+ """
5
+ class SettingsContainer:
6
+ def __init__(self, **kwargs):
7
+ for key, value in kwargs.items():
8
+ setattr(self, key, value)
@@ -0,0 +1,44 @@
1
+ import copy
2
+ from typing import Optional, Union, List
3
+
4
+ from rephorm.object_mappers.chapter_mapper import ChapterMapper
5
+ from rephorm.objects.chart import Chart
6
+ from rephorm.objects.page_break import PageBreak
7
+ from rephorm.objects.grid import Grid
8
+ from rephorm.objects._utilities.settings_container import SettingsContainer
9
+ from rephorm.objects.table import Table
10
+ from rephorm.objects.text import Text
11
+ from rephorm.decorators.settings_validation import validate_kwargs
12
+ from rephorm.utility.add_style_prefix import add_prefix_to_styles
13
+
14
+
15
+ class Chapter:
16
+ @validate_kwargs
17
+ def __init__(self, title: str = None, footnotes: Optional[List[str]] = None, **kwargs):
18
+ """
19
+ :param title: (str) Title of the chapter.
20
+ :key styles (Dict): Styles dictionary for additional customization (for details refer to report object).
21
+ """
22
+ self.title = title
23
+ self.footnotes = footnotes
24
+ self.CHILDREN = []
25
+ # if "styles" in kwargs:
26
+ # kwargs["styles"]=adjust_styles(kwargs["styles"], caller)
27
+ self.settings = SettingsContainer(**kwargs)
28
+ if hasattr(self.settings, "styles"):
29
+ self.settings.styles = add_prefix_to_styles("chapter", self.settings.styles)
30
+
31
+ def add(
32
+ self,
33
+ chapter_child: Union[Grid, Table, Text, PageBreak, Chart] = None,
34
+ ):
35
+ if chapter_child is not None and isinstance(chapter_child, (Grid, Table, Text, PageBreak, Chart)):
36
+ copy_chapter_child = copy.deepcopy(chapter_child)
37
+ self.CHILDREN.append(copy_chapter_child)
38
+ else: raise Exception("Chapter: chapter child of wrong type or None")
39
+
40
+ def _get_mapper(self):
41
+ return ChapterMapper(self)
42
+
43
+ def __repr__(self):
44
+ return f"{type(self).__name__}"
@@ -0,0 +1,70 @@
1
+ import copy
2
+ import plotly
3
+ from rephorm.object_mappers.chart_mapper import ChartMapper
4
+ from rephorm.objects.chart_series import ChartSeries
5
+ from rephorm.objects._utilities.settings_container import SettingsContainer
6
+ from rephorm.utility.add_style_prefix import add_prefix_to_styles
7
+
8
+ from rephorm.utility.report.range_utility import get_span, get_highlight
9
+ from rephorm.decorators.settings_validation import validate_kwargs
10
+
11
+ class Chart:
12
+
13
+ @validate_kwargs
14
+ def __init__(self, title: str = None, figure: plotly.graph_objs.Figure = None, **kwargs):
15
+ """
16
+ :args title (str): title of the chart
17
+ :args figure (plotly.graph_objs.Figure): Plotly figure object. If provided, it will plot the given figure object.
18
+ :args span (ir.Span): Span of the chart
19
+ :key apply_report_layout (bool): If True, applies the standard report layout to the provided figure (can only be used for a custom Plotly figure).
20
+ :key highlight (ir.Span): Span of the highlight.
21
+ :key show_legend (bool): to show/hide the legend.
22
+ :key show_grid (bool): to show/hide the grid.
23
+ :key axis_border (bool): enable/disable axis borders.
24
+ :key xaxis_title (str): The title for the X-axis.
25
+ :key yaxis_title (str): The title for the Y-axis.
26
+ :key yaxis2_title (str): The title for the second Y-axis.
27
+ :key legend_orientation (str): legend orientation. "v" or "h".
28
+ :key legend_position (str): Position of the legend. e.g. "SO" - South Outside. "S" - South Inside.
29
+ :key series_type (str): Type of series to display - "line" for line charts, "bar" for bar charts,
30
+ "bar_contribution" for contribution bar charts; use "line" with markers_mode="markers" for marker-based charts.
31
+ :key markers_mode (str): Display style for data points - "lines+markers" (lines with symbols/dots),
32
+ "lines" (lines only), or "markers" (symbols/dots only).
33
+ :key legend (tuple): Specifies the legend labels for the series. For multivariate series, provide multiple labels like ("Label 1", "Label 2", ...).
34
+ :key marker_symbol (str): Symbol name for markers, default is "asterisk".
35
+ :key zeroline (bool): If True, displays a horizontal line at Y=0 to help indicate the zero baseline.
36
+ :key styles (Dict): Styles dictionary for additional customization (for details refer to report object).
37
+ """
38
+ self.CHILDREN = []
39
+ self.title = title
40
+ self.figure = figure
41
+ self.settings = SettingsContainer(**kwargs)
42
+
43
+ if hasattr(self.settings, "styles"):
44
+ self.settings.styles = add_prefix_to_styles("chart", self.settings.styles)
45
+
46
+ def add(
47
+ self,
48
+ chart_child: ChartSeries = None):
49
+ # Todo: add docstring later on.
50
+ """
51
+ :param chart_child: (ChartSeries) Child of the chart.
52
+ """
53
+
54
+ if chart_child is not None and isinstance(chart_child, ChartSeries):
55
+ copy_chart_child = copy.deepcopy(chart_child)
56
+ self.CHILDREN.append(copy_chart_child)
57
+
58
+ else: raise Exception("CHART: Chart child of wrong type or None")
59
+
60
+ def __repr__(self):
61
+ return f"{type(self).__name__}"
62
+
63
+ def _get_mapper(self):
64
+ return ChartMapper(self)
65
+
66
+ def _get_span(self):
67
+ return get_span(self)
68
+
69
+ def _get_highlight(self):
70
+ return get_highlight(self)