Commit 809b9327 authored by Sanjay Yadav's avatar Sanjay Yadav

ENH: Enhancements in bar with circle styles.

parent 358198a4
Pipeline #32078 failed with stage
in 52 seconds
...@@ -14,9 +14,10 @@ import matplotlib.cm ...@@ -14,9 +14,10 @@ import matplotlib.cm
from . import fontwidth from . import fontwidth
import matplotlib.colors import matplotlib.colors
from . import color as _color from . import color as _color
from collections import OrderedDict
from pptx.dml.color import RGBColor from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN from pptx.enum.text import PP_ALIGN
from collections import OrderedDict
from orderedattrdict import AttrDict
from tornado.template import Template from tornado.template import Template
from tornado.escape import to_unicode from tornado.escape import to_unicode
from pptx.chart.data import ChartData from pptx.chart.data import ChartData
...@@ -205,7 +206,7 @@ def rect_css(shape, **kwargs): ...@@ -205,7 +206,7 @@ def rect_css(shape, **kwargs):
chart_css(fill, kwargs, rectcss) chart_css(fill, kwargs, rectcss)
def add_text_to_shape(shape, text, **kwargs): def add_text_to_shape(shape, textval, **kwargs):
"""Function to add text to shape.""" """Function to add text to shape."""
min_inc = 13000 min_inc = 13000
pixel_inch = 10000 pixel_inch = 10000
...@@ -214,7 +215,7 @@ def add_text_to_shape(shape, text, **kwargs): ...@@ -214,7 +215,7 @@ def add_text_to_shape(shape, text, **kwargs):
paragraph = shape.text_frame.paragraphs[0] paragraph = shape.text_frame.paragraphs[0]
paragraph.add_run() paragraph.add_run()
for run in paragraph.runs: for run in paragraph.runs:
run.text = text run.text = textval
shape_txt = run.font shape_txt = run.font
shape_txt = run.font.fill shape_txt = run.font.fill
shape_txt.solid() shape_txt.solid()
...@@ -1005,23 +1006,47 @@ def bar_circle(shape, spec, data): ...@@ -1005,23 +1006,47 @@ def bar_circle(shape, spec, data):
"""Function to plot bar chart with circles.""" """Function to plot bar chart with circles."""
spec = copy.deepcopy(spec['bar_circle']) spec = copy.deepcopy(spec['bar_circle'])
handler = data.pop('handler') if 'handler' in data else None handler = data.pop('handler') if 'handler' in data else None
csskeys = ['bar-y', 'circle-y', 'circle-size', 'bar-category', # Getting CSS
'circle-category', 'opacity', 'stroke'] style = AttrDict()
for key in csskeys: common_css = copy.deepcopy(spec.get('style', {}))
if isinstance(spec.get(key), (dict,)) and 'function' in spec[key]: for csskey in ['bar', 'circle']:
spec[key] = compile_function(spec, key, data, handler) _style = common_css.pop(csskey, {})
for key, val in _style.items():
if isinstance(val, (dict,)) and 'function' in val:
_style[key] = compile_function(_style, key, data, handler)
style[csskey] = _style
for csskey in ['bar', 'circle']:
update_css = copy.deepcopy(common_css)
update_css.update(style[csskey])
for key, val in update_css.items():
if isinstance(val, (dict,)) and 'function' in val:
update_css[key] = compile_function(update_css, key, data, handler)
style[csskey] = update_css
# Loading data # Loading data
bar_data = compile_function(spec, 'bardata', data, handler) bar_conf = copy.deepcopy(spec['bar'])
circle_data = compile_function(spec, 'circledata', data, handler) bar_data = compile_function(bar_conf, 'data', data, handler)
bary = spec['bar-y']
circley = spec['circle-y'] circle_conf = copy.deepcopy(spec['circle'])
circ_size = spec['circle-size'] circle_data = compile_function(circle_conf, 'data', data, handler)
bar_category = spec['bar-category']
circle_category = spec['circle-category'] for key in ['y', 'size', 'x', 'text']:
style = copy.deepcopy(spec.get('style', {})) for config in [bar_conf, circle_conf]:
for csskey in ['font-color', 'font-family', 'color', 'fill', 'font-size']: if isinstance(config.get(key), (dict,)) and 'function' in config[key]:
if isinstance(style.get(csskey), (dict,)) and 'function' in style[csskey]: config[key] = compile_function(config, key, data, handler)
style[csskey] = compile_function(style, csskey, data, handler)
bary = bar_conf['y']
circley = circle_conf['y']
circ_size = circle_conf['size']
bar_category = bar_conf['x']
circle_category = circle_conf['x']
txt_props = ['font-color', 'font-family', 'color', 'fill',
'font-size', 'text', 'stroke', 'opacity']
for csskey in txt_props:
for key in ['bar', 'circle']:
if isinstance(style[key].get(csskey), (dict,)) and 'function' in style[key][csskey]:
style[key][csskey] = compile_function(style[key], csskey, data, handler)
scale = bar_data[bary].fillna(0).tolist() + circle_data[circley].fillna(0).tolist() scale = bar_data[bary].fillna(0).tolist() + circle_data[circley].fillna(0).tolist()
ymax = max(scale) ymax = max(scale)
...@@ -1057,23 +1082,40 @@ def bar_circle(shape, spec, data): ...@@ -1057,23 +1082,40 @@ def bar_circle(shape, spec, data):
left + row['x'] + row['width'] / 4.0, left + row['x'] + row['width'] / 4.0,
top + shape.height, top + shape.height,
row['width'] - row['width'] / 4.0, row['width'] - row['width'] / 2.0) row['width'] - row['width'] / 4.0, row['width'] - row['width'] / 2.0)
add_text_to_shape(txt, row['category'], **style)
txt = parent.add_textbox( _barcss = copy.deepcopy(style['bar'])
left + row['x'] + row['width'] / 4.0, add_text_to_shape(txt, '{}'.format(row['category']), **_barcss)
top + row['y'],
row['width'] - row['width'] / 4.0, row['width'] - row['width'] / 4.0) for _barkey in txt_props:
add_text_to_shape(txt, '{}%'.format(row[bary]), **style) if callable(_barcss.get(_barkey)):
d = circle_data[circle_data[circle_category] == row['category']] _barcss[_barkey] = _barcss[_barkey](row)
for i, circle in d.iterrows():
if bar_conf.get('text'):
txt = parent.add_textbox(
left + row['x'] + row['width'] / 4.0,
top + row['y'],
row['width'] - row['width'] / 4.0, row['width'] - row['width'] / 4.0)
bar_txt = '{}%'.format(row[bary])
bar_txt = bar_conf['text'](row) if callable(bar_conf['text']) else bar_txt
add_text_to_shape(txt, bar_txt, **_barcss)
map_circ_data = circle_data[circle_data[circle_category] == row['category']]
for i, circle in map_circ_data.iterrows():
y = top + scale_data(circle[circley], 0, ymax, factor=row['width']) y = top + scale_data(circle[circley], 0, ymax, factor=row['width'])
y = y - (row['width'] / 2.0) y = y - (row['width'] / 2.0)
sz = scale_data(circle[circ_size], 0, d[circ_size].max(), factor=row['width'] / 2.0) circle_size = scale_data(
xaxis = left + row['x'] + (row['width'] / 2.0) - (sz / 2.0) circle[circ_size], 0, map_circ_data[circ_size].max(),
factor=row['width'] / 2.0)
xaxis = left + row['x'] + (row['width'] / 2.0) - (circle_size / 2.0)
cir = parent.add_shape( cir = parent.add_shape(
MSO_SHAPE.OVAL, xaxis, y, sz, sz) MSO_SHAPE.OVAL, xaxis, y, circle_size, circle_size)
rect_css(cir, **{'fill': '#00441B', 'stroke': '#00441B', 'opacity': 0.7}) circle_style = copy.deepcopy(style['circle'])
rect_css(_rect, **{'fill': '#cccccc', 'stroke': '#cccccc'}) for _key in ['fill', 'stroke', 'opacity']:
if callable(circle_style.get(_key)):
circle_style[_key] = circle_style[_key](circle)
rect_css(cir, **circle_style)
rect_css(_rect, **_barcss)
rect_css(shape, **{'fill': '#FBFBFB', 'stroke': '#FBFBFB'}) rect_css(shape, **{'fill': '#FBFBFB', 'stroke': '#FBFBFB'})
......
...@@ -7,13 +7,27 @@ data: ...@@ -7,13 +7,27 @@ data:
barcircle-config: barcircle-config:
bar-circle: bar-circle:
bar_circle: bar_circle:
bardata: data['bardata'] bar:
circledata: data['circledata'] data: data['bardata']
bar-y: FTE y: FTE
circle-y: "Y" x: Region
circle-size: Size text:
bar-category: Region function: "lambda v: '{:.2f}'.format(v['FTE'])"
circle-category: Category circle:
data: data['circledata']
y: "Y"
size: Size
x: Category
style: style:
font-size: 14 bar:
color: '#000000' font-size: 14
color: '#ff0000'
fill: '#1A9850'
stroke: '#cccccc'
opacity: 0.3
circle:
font-size: 14
opacity: 0.7
fill: '#FE9929'
stroke: '#00441B'
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment