diff --git a/cms/apexchart.py b/cms/apexchart.py new file mode 100644 index 0000000..97f93a7 --- /dev/null +++ b/cms/apexchart.py @@ -0,0 +1,185 @@ +import numpy as np +import pandas as pd + +class chart : + @staticmethod + def get(_data,_config) : + # r = {} + # for _key in _config : + # r[_key] = {'about':_config[_key]['about'],'chart':[]} + # _pointers = _config[_key]['apply'] + # _pointers = [_pointers] if type(_pointers) == str else _pointers + # r[_key]['chart'] += [getattr(chart,_name)(_data,_config[_key]) for _name in _pointers if hasattr(chart,_name)] + # return [r] + r = {} + for _key in _config : + _options = _config[_key]['options'] + r[_key] = {'about':_config[_key]['about'],'css':_config[_key]['css'],'charts':[]} + _charts = [] + for _itemOption in _options : + _type = _itemOption['type'] + if hasattr(chart,_type) : + _pointer = getattr(chart,_type) + + _chartOption = _pointer(_data,_itemOption) + _tag = 'options' if _type != 'scalar' else 'html' + if 'title' in _itemOption and _itemOption['type'] != 'scalar' : + _chartOption['title'] = {'text':_itemOption['title'],'align':'center'} + _chartOption['legend'] = {'position':'bottom','itemMargin':{'horizontal':4,'vertical':10}} + + _chartOption['chart']['height'] = 300 + # _chartOption['chart']['height'] = '100%' + # _chartOption['responsive'] = [{'breakpoint':480,'options':{'chart':{'width':300}}}] + _charts.append ({"type":_type,_tag:_chartOption}) + if _charts : + r[_key]['charts'] = _charts + + # for _pointer in _pointers : + # r[_key]['chart'].append(_pointer(_data,_config[_key])) + + # _pointers = [getattr(chart,_name) for _name in _config[_key]['options']['apply'] if hasattr(chart,_name)] + # r[_key] = {'about':_config[_key]['about'],'chart':[]} + # for _pointer in _pointers : + # r[_key]['chart'].append(_pointer(_data,_config[_key])) + + + return r + @staticmethod + def format_digit (value): + if value > 1000000 : + return np.divide(value,1000000).round(2).astype(str) + ' M' + elif value > 1000 : + return np.divide(value,1000).round(2).astype(str)+ ' K' + return value + @staticmethod + def scalar(_data,_config) : + """ + Only focusing on axis.y + """ + _columns = _config['axis']['y'] + if _data.shape[0] > 1 : + _apply = 'sum' if 'apply' not in _config else _config['apply'] + # values = _data[_columns].sum().values.tolist() + values = getattr(_data[_columns],_apply)().values.round(3).tolist() + else: + values = _data[_columns].values.tolist()[0] + + _html = [f'
{chart.format_digit(values[_index])}
{_columns[_index].replace("_"," ") }
' for _index in np.arange(len(values))] + return ' '.join(_html) + @staticmethod + def donut(_data,_config): + options = {"chart":{"type":"donut"}} + _yaxis = _config['axis']['y'] + _apply = 'sum' if 'apply' not in _config else _config['apply'] + # options['series'] = _data[_yaxis].sum().values.tolist() + options['series'] = getattr(_data[_yaxis],_apply)().values.round(3).tolist() + options['labels'] = [_name.replace('_',' ').upper() for _name in _yaxis] + options["dataLabels"]= { + "enabled": False + } + return options + @staticmethod + def column(_data,_config): + if 'apply' in _config : + _fn = _config['apply'] + _yaxis = _config['axis']['y'] + _values = getattr(_data[_yaxis],_fn)().values #.sum() + _data = (pd.DataFrame([dict(zip(_yaxis,_values))])) + + + + options = chart.barStacked(_data,_config) + options['chart'] = {'type':'bar'} + if 'title' in _config : + options['title'] = {'text':_config['title'],'align':'center','style':{'text-transform':'upperCase','fontSize':'18px'}} + pass + + options['stroke'] = {'show':True,'width':2,'colors':['transparent']} + if _data.shape[0] == 1: + options['xaxis']['categories'] = [_name.replace('_',' ').upper() for _name in _config['axis']['x']] + # options['plotOptions'] = {'bar':{'columnWidth':'55%'}} + return options + @staticmethod + def barStacked(_data,_config): + options = {"series":[], "chart": { + "type": 'bar','stacked':True} + } + # options['plotOptions'] = {'bar':{'horizontal':True}} + # options['legend'] = {'position':'bottom'} # {'position':'right','horizontalAlign':'left','offsetX':40} + + _xaxis = _data[_config['axis']['x']].values.tolist() + options["xaxis"]={"categories":_xaxis} + for _col in _config['axis']['y'] : + options['series'] += [{'name':_col.replace('_',' ').upper(), 'data':_data[_col].tolist()}] + return options + @staticmethod + def radialBar (_data,_config) : + + _options = { + "series": _config["axis"]["y"], + "labels": _config["axis"]["x"], + "chart": { + "type": 'radialBar', + "offsetY": -20, + "sparkline": { + "enabled": True + } + }, + # "plotOptions": { + # "radialBar": { + # "startAngle": -90, + # "endAngle": 90, + # "track": { + # "background": "#e7e7e7", + # "strokeWidth": '97%', + # "margin": 5, + # "dropShadow": { + # "enabled": True, + # "top": 2, + # "left": 0, + # "color": '#999', + # "opacity": 1, + # "blur": 2 + # } + # }, + # "dataLabels": { + + # "name": { + # "show": False + # }, + # "value": { + # "offsetY": -2, + # "fontSize": '18px' + # } + # } + # } + # }, + # "grid": { + # "padding": { + # "top":10 + # } + # }, + + + } + return _options + @staticmethod + def barGrouped (_data,_config): + """ + """ + options = {"series":[],"chart":{"type":"bar"},"plotOptions": { + "bar": { + "horizontal": True, + "dataLabels": { + "position": 'top', + }}}, + + } + _yaxis = _config["axis"]["y"] + for _name in _yaxis : + options["series"] += [{'name':_name.replace('_',' ').upper(),"data":_data[_name].tolist()}] + # + # _xaxis + _xaxis = _config['axis']['x'] + options['xaxis'] = {'categories':_data[_xaxis].values.tolist()} + return options