8000 fix #901 : added the keyword arguments min_y, max_y, xticks_spacing, … · larray-project/larray@1b13e8e · GitHub
[go: up one dir, main page]

Skip to content

Commit 1b13e8e

Browse files
committed
fix #901 : added the keyword arguments min_y, max_y, xticks_spacing, customize_func and customize_kwargs to the add_graph() and add_graphs() methods
1 parent 85bd7ef commit 1b13e8e

File tree

3 files changed

+119
-9
lines changed

3 files changed

+119
-9
lines changed

doc/source/changes/version_0_33.rst.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ Miscellaneous improvements
5656

5757
* implemented :py:obj:`Axis.astype()` method (closes :issue:`880`).
5858

59+
* added `min_y`, `max_y` and `xticks_spacing` keyword arguments to the :py:obj:`ReportSheet.add_graph()` and
60+
:py:obj:`ReportSheet.add_graphs()` methods (closes :issue:`901`).
61+
5962
Fixes
6063
^^^^^
6164

larray/inout/xw_reporting.py

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,8 @@ def add_title(self, title, width=None, height=None, fontsize=11):
216216
"""
217217
pass
218218

219-
def add_graph(self, data, title=None, template=None, width=None, height=None):
219+
def add_graph(self, data, title=None, template=None, width=None, height=None, min_y=None, max_y=None,
220+
xticks_spacing=None, customize_func=None, customize_kwargs=None):
220221
r"""
221222
Add a graph item to the current sheet.
222223
Note that the current method only add a new item to the list of items to be generated.
@@ -241,6 +242,18 @@ def add_graph(self, data, title=None, template=None, width=None, height=None):
241242
height : int, optional
242243
height of the title item. The current default value is used if None
243244
(see :py:obj:`~ExcelReport.set_item_default_size`). Defaults to None.
245+
min_y: int, optional
246+
minimum value for the Y axis.
247+
max_y: int, optional
248+
maximum value for the Y axis.
249+
xticks_spacing: int, optional
250+
space interval between two ticks along the X axis.
251+
customize_func: function, optional
252+
user defined function to personalize the graph.
253+
The function must take the Chart object as first argument.
254+
All keyword arguments defined in customize_kwargs are passed to the function at call.
255+
customize_kwargs: dict, optional
256+
keywords arguments passed to the function `customize_func` at call.
244257
245258
Examples
246259
--------
@@ -262,6 +275,14 @@ def add_graph(self, data, title=None, template=None, width=None, height=None):
262275
>>> sheet_be.template = 'Line_Marker'
263276
>>> sheet_be.add_graph(demo.deaths['Belgium'], 'Deaths')
264277
278+
Specify the mininum and maximum values for the Y axis
279+
280+
>>> sheet_be.add_graph(demo.population['Belgium'], 'Population (min/max Y axis = 5/6 millions)', min_y=5e6, max_y=6e6)
281+
282+
Specify the interval between two ticks (X axis)
283+
284+
>>> sheet_be.add_graph(demo.population['Belgium'], 'Population (every 2 years)', xticks_spacing=2)
285+
265286
Dumping the report Excel file
266287
267288
>>> # do not forget to call 'to_excel' to create the report file
@@ -270,7 +291,8 @@ def add_graph(self, data, title=None, template=None, width=None, height=None):
270291
pass
271292

272293
def add_graphs(self, array_per_title, axis_per_loop_variable, template=None, width=None, height=None,
273-
graphs_per_row=1):
294+
graphs_per_row=1, min_y=None, max_y=None, xticks_spacing=None, customize_func=None,
295+
customize_kwargs=None):
274296
r"""
275297
Add multiple graph items to the current sheet. This method is mainly useful when multiple
276298
graphs are generated by iterating over one or several axes of an array (see examples below).
@@ -295,7 +317,18 @@ def add_graphs(self, array_per_title, axis_per_loop_variable, template=None, wid
295317
(see :py:obj:`~ExcelReport.set_item_default_size`). Defaults to None.
296318
graphs_per_row: int, optional
297319
Number of graphs per row. Defaults to 1.
298-
320+
min_y: int, optional
321+
minimum value for the Y axis.
322+
max_y: int, optional
323+
maximum value for the Y axis.
324+
xticks_spacing: int, optiona 9E88 l
325+
space interval between two ticks along the X axis.
326+
customize_func: function, optional
327+
user defined function to personalize the graph.
328+
The function must take the Chart object as first argument.
329+
All keyword arguments defined in customize_kwargs are passed to the function at call.
330+
customize_kwargs: dict, optional
331+
keywords arguments passed to the function `customize_func` at call.
299332
300333
Examples
301334
--------
@@ -311,6 +344,18 @@ def add_graphs(self, array_per_title, axis_per_loop_variable, template=None, wid
311344
... {'gender': population.gender, 'year': population.time},
312345
... template='line', width=450, height=250, graphs_per_row=2)
313346
347+
Specify the mininum and maximum values for the Y axis
348+
349+
>>> sheet_population.add_graphs({'Population of {gender} by country for the year {year}': population},
350+
... {'gender': population.gender, 'year': population.time},
351+
... template='line', width=450, height=250, graphs_per_row=2, min_y=0, max_y=50e6)
352+
353+
Specify the interval between two ticks (X axis)
354+
355+
>>> sheet_population.add_graphs({'Population of {gender} by country for the year {year}': population},
356+
... {'gender': population.gender, 'year': population.time},
357+
... template='line', width=450, height=250, graphs_per_row=2, xticks_spacing=2)
358+
314359
>>> # do not forget to call 'to_excel' to create the report file
315360
>>> report.to_excel('Demography_Report.xlsx')
316361
"""
@@ -499,7 +544,7 @@ def to_excel(self, filepath, data_sheet_name='__data__', overwrite=True):
499544

500545

501546
if xw is not None:
502-
from xlwings.constants import LegendPosition, HAlign, VAlign, ChartType, RowCol
547+
from xlwings.constants import LegendPosition, HAlign, VAlign, ChartType, RowCol, AxisType, Constants
503548
from larray.inout.xw_excel import open_excel
504549

505550
class ItemSize(object):
@@ -571,7 +616,8 @@ class ExcelGraphItem(ItemSize):
571616

572617
_default_size = ItemSize(427, 230)
573618

574-
def __init__(self, data, title, template, top, left, width, height):
619+
def __init__(self, data, title, template, top, left, width, height, min_y, max_y,
620+
xticks_spacing, customize_func, customize_kwargs):
575621
ItemSize.__init__(self, width, height)
576622
self.top = top
577623
self.left = left
@@ -583,6 +629,14 @@ def __init__(self, data, title, template, top, left, width, height):
583629
if template is not None and not os.path.isfile(template):
584630
raise ValueError(f"Could not find template file {template}")
585631
self.template = template
632+
self.min_y = min_y
633+
self.max_y = max_y
634+
self.xticks_spacing = xticks_spacing
635+
if customize_func is not None and not callable(customize_func):
636+
raise TypeError(f"Expected a function for the argument 'customize_func'. "
637+
f"Got object of type {type(customize_func).__name__} instead.")
638+
self.customize_func = customize_func
639+
self.customize_kwargs = customize_kwargs
586640

587641
def dump(self, sheet, data_sheet, row):
588642
data_range = data_sheet.Range
@@ -604,12 +658,28 @@ def dump(self, sheet, data_sheet, row):
604658
source = data_range(data_cells(row, 1), data_cells(last_row, last_col))
605659
obj_chart.SetSourceData(source)
606660
obj_chart.ChartType = ChartType.xlLine
661+
# title
607662
if self.title is not None:
608663
obj_chart.HasTitle = True
609664
obj_chart.ChartTitle.Caption = self.title
665+
# legend
610666
obj_chart.Legend.Position = LegendPosition.xlLegendPositionBottom
667+
# template
611668
if self.template is not None:
612669
obj_chart.ApplyChartTemplate(self.template)
670+
# min - max on Y axis
671+
if self.min_y is not None:
672+
obj_chart.Axes(AxisType.xlValue).MinimumScale = self.min_y
673+
if self.max_y is not None:
674+
obj_chart.Axes(AxisType.xlValue).MaximumScale = self.max_y
675+
# xticks_spacing
676+
if self.xticks_spacing is not None:
677+
obj_chart.Axes(AxisType.xlCategory).TickLabelSpacing = self.xticks_spacing
678+
obj_chart.Axes(AxisType.xlCategory).TickMarkSpacing = self.xticks_spacing
679+
obj_chart.Axes(AxisType.xlCategory).TickLabelPosition = Constants.xlLow
680+
# user's function (to apply on remaining kwargs)
681+
if self.customize_func is not None:
682+
self.customize_func(obj_chart, **self.customize_kwargs)
613683
# flagflip
614684
if nb_series > 1 and nb_xticks == 1:
615685
obj_chart.PlotBy = RowCol.xlRows
@@ -643,7 +713,8 @@ def add_title(self, title, width=None, height=None, fontsize=11):
643713
self.items.append(ExcelTitleItem(title, fontsize, self.top, 0, width, height))
644714
self.top += height
645715

646-
def add_graph(self, data, title=None, template=None, width=None, height=None):
716+
def add_graph(self, data, title=None, template=None, width=None, height=None, min_y=None, max_y=None,
717+
xticks_spacing=None, customize_func=None, customize_kwargs=None):
647718
if width is None:
648719
width = self.default_items_size['graph'].width
649720
if height is None:
@@ -653,13 +724,15 @@ def add_graph(self, data, title=None, template=None, width=None, height=None):
653724
template = self.template
654725
if self.graphs_per_row is not None and self.position_in_row > self.graphs_per_row:
655726
self.newline()
656-
self.items.append(ExcelGraphItem(data, title, template, self.top, self.left, width, height))
727+
self.items.append(ExcelGraphItem(data, title, template, self.top, self.left, width, height,
728+
min_y, max_y, xticks_spacing, customize_func, customize_kwargs))
657729
self.left += width
658730
self.curline_height = max(self.curline_height, height)
659731
self.position_in_row += 1
660732

661733
def add_graphs(self, array_per_title, axis_per_loop_variable, template=None, width=None, height=None,
662-
graphs_per_row=1):
734+
graphs_per_row=1, min_y=None, max_y=None, xticks_spacing=None, customize_func=None,
735+
customize_kwargs=None):
663736
loop_variable_names = axis_per_loop_variable.keys()
664737
axes = tuple(axis_per_loop_variable.values())
665738
titles = array_per_title.keys()
@@ -673,7 +746,8 @@ def add_graphs(self, array_per_title, axis_per_loop_variable, template=None, wid
673746
loop_variables_dict = dict(zip(loop_variable_names, loop_variable_values))
674747
for title_template, array_chunk in zip(titles, arrays_chunk):
675748
title = title_template.format(**loop_variables_dict)
676-
self.add_graph(array_chunk, title, template, width, height)
749+
self.add_graph(array_chunk, title, template, width, height, min_y, max_y, xticks_spacing,
750+
customize_func, customize_kwargs)
677751
if graphs_per_row is not None:
678752
self.graphs_per_row = previous_graphs_per_row
679753

larray/tests/test_excel.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,12 @@ def test_excel_report_arrays():
338338
population_be_nan = population_be.astype(float)
339339
population_be_nan[2013] = nan
340340

341+
# fake simple user defined function to test if any user defined function (and their arguments)
342+
# is actually called and correctly handled.
343+
def customize_func(obj_chart, alternative_title):
344+
obj_chart.HasTitle = True
345+
obj_chart.ChartTitle.Caption = alternative_title
346+
341347
# test dumping arrays
342348
sheet_graphs = excel_report.new_sheet('Graphs')
343349
# 1) default
@@ -357,6 +363,13 @@ def test_excel_report_arrays():
357363
template_name = 'Line_Marker'
358364
sheet_graphs.add_title(f'Template = {template_name}')
359365
sheet_graphs.add_graph(population_be, f'Template = {template_name}', template_name)
366+
# 5) specify min_y and max_y
367+
sheet_graphs.add_graph(population_be, 'min (max) Y axis is 5e6 (6e6)', min_y=5e6, max_y=6e6)
368+
# 6) specify the space between 2 ticks
369+
sheet_graphs.add_graph(population_be, 'periodicity = every 2 years', xticks_spacing=2)
370+
# 7) pass a user defined function
371+
sheet_graphs.add_graph(population_be, customize_func=customize_func,
372+
customize_kwargs={'alternative_title': 'alternative title'})
360373

361374
# test setting default size
362375
# 1) pass a not registered kind of item
@@ -379,10 +392,30 @@ def test_excel_report_arrays():
379392

380393
# testing add_graphs
381394
sheet_graphs = excel_report.new_sheet('Graphs3')
395+
# 1) default
382396
sheet_graphs.add_title('add_graphs')
383397
sheet_graphs.add_graphs({'Population for {country} - {gender}': population},
384398
{'gender': population.gender, 'country': population.country},
385399
template='line', width=350, height=250, graphs_per_row=3)
400+
# 2) specify min_y and max_y
401+
sheet_graphs.add_title('min_y = 0 and max_y = 50e6')
402+
sheet_graphs.add_graphs({'Population for {country} - {gender}': population},
403+
{'gender': population.gender, 'country': population.country},
404+
template='line', width=350, height=250, graphs_per_row=3,
405+
min_y=0, max_y=50e6)
406+
# 3) specify the space between 2 ticks
407+
sheet_graphs.add_title('periodicity = every 2 years')
408+
sheet_graphs.add_graphs({'Population for {country} - {gender}': population},
409+
{'gender': population.gender, 'country': population.country},
410+
template='line', width=350, height=250, graphs_per_row=3,
411+
xticks_spacing=2)
412+
# 4) pass a user defined function
413+
sheet_graphs.add_title('user defined function')
414+
sheet_graphs.add_graphs({'Population for {country} - {gender}': population},
415+
{'gender': population.gender, 'country': population.country},
416+
template='line', width=350, height=250, graphs_per_row=3,
417+
customize_func=customize_func,
418+
customize_kwargs={'alternative_title': 'alternative title'})
386419

387420
# generate Excel file
388421
fpath = 'test_excel_report_arrays.xlsx'

0 commit comments

Comments
 (0)
0