Commit 9f86690e authored by Sanjay Yadav's avatar Sanjay Yadav

ENH: Added CSS like properties to shapes.

parent aa675975
Pipeline #31579 failed with stage
in 52 seconds
......@@ -205,14 +205,12 @@ def rect_css(shape, **kwargs):
chart_css(fill, kwargs, rectcss)
def add_text_to_shape(shape, text, font_size, txt_fill):
def add_text_to_shape(shape, text, **kwargs):
"""Function to add text to shape."""
min_inc = 13000
pixel_inch = 10000
font_size = max(font_size * pixel_inch, min_inc)
if font_size > min_inc:
txt_fill = txt_fill.rsplit('#')[-1].lower()
txt_fill = txt_fill + (txt_fill[0] * (6 - len(txt_fill)))
# kwargs['font-size'] = max(kwargs.get('font-size', 16), min_inc)
if (kwargs.get('font-size', 14) * pixel_inch) > min_inc:
paragraph = shape.text_frame.paragraphs[0]
paragraph.add_run()
for run in paragraph.runs:
......@@ -220,8 +218,7 @@ def add_text_to_shape(shape, text, font_size, txt_fill):
shape_txt = run.font
shape_txt = run.font.fill
shape_txt.solid()
run.font.size = '{:.0f}'.format(font_size)
run.font.color.rgb = RGBColor.from_string(txt_fill)
utils.apply_text_css(run, paragraph, **kwargs)
def scale_data(data, lo, hi, factor=None):
......@@ -507,7 +504,7 @@ def sankey(shape, spec, data):
sankey_conf['color'] = compile_function(spec, 'color', data, handler)
sankey_conf['attrs'] = spec.get('attrs', {})
sankey_conf['sort'] = spec.get('sort')
stroke = spec.get('stroke', '#ffffff')
stroke = spec.get('style', {}).get('stroke', '#ffffff')
# Delete rectangle after geting width, height, x-position and y-position
shape._sp.delete()
elem_schema = utils.make_element()
......@@ -522,8 +519,10 @@ def sankey(shape, spec, data):
MSO_SHAPE.RECTANGLE, row['x'], y, row['width'], thickness)
rectstyle = {"fill": row['fill'], 'stroke': stroke}
rect_css(shp, **rectstyle)
txt_fill = _color.contrast(row['fill'])
add_text_to_shape(shp, row['text'], spec.get('font-size', 18), txt_fill)
text_style = {}
text_style['color'] = _color.contrast(row['fill'])
text_style.update(spec.get('style', {}))
add_text_to_shape(shp, row['text'], **text_style)
# Sankey Connection Arcs.
for ibar, (group1, group2) in enumerate(zip(groups[:-1], groups[1:])):
......@@ -617,10 +616,13 @@ def treemap(shape, spec, data):
text = '{}'.format(v[1])
rectstyle = {"fill": rect_color, 'stroke': stroke}
rect_css(shp, **rectstyle)
txt_fill = _color.contrast(rect_color)
font_size = min(h, w * font_aspect / fontwidth.fontwidth('{}'.format(text)), pd.np.Inf)
text_style = {}
text_style['color'] = _color.contrast(rect_color)
text_style.update(spec.get('style', {}))
text_style['font-size'] = font_size / pixel_inch
# Adding text inside rectangles
add_text_to_shape(shp, text, font_size / pixel_inch, txt_fill)
add_text_to_shape(shp, text, **text_style)
def calendarmap(shape, spec, data):
......@@ -653,10 +655,10 @@ def calendarmap(shape, spec, data):
default_color = '#ffffff'
default_line_color = '#787C74'
default_txt_color = '#000000'
font_size = spec.get('font-size', 12)
stroke = spec.get('stroke', '#ffffff')
fill_rect = spec.get('fill', '#cccccc')
text_color = spec.get('text-color', '#000000')
font_size = spec.get('style', {}).get('font-size', 12)
stroke = spec.get('style', {}).get('stroke', '#ffffff')
fill_rect = spec.get('style', {}).get('fill', '#cccccc')
text_color = spec.get('style', {}).get('color', '#000000')
# Treat infinities as nans when calculating scale
scaledata = pd.Series(data).replace([pd.np.inf, -pd.np.inf], pd.np.nan)
lo_data = spec.get('lo', scaledata.min())
......@@ -695,7 +697,14 @@ def calendarmap(shape, spec, data):
sizes[i], sizes[i])
rectstyle = {"fill": fill, 'stroke': stroke}
rect_css(shp, **rectstyle)
add_text_to_shape(shp, '%02d' % d.day, font_size, _color.contrast(fill))
text_style = {}
text_style['color'] = _color.contrast(fill)
text_style['font-size'] = font_size
text_style['bold'] = spec.get('style', {}).get('bold')
text_style['italic'] = spec.get('style', {}).get('italic')
text_style['underline'] = spec.get('style', {}).get('underline')
text_style['font-family'] = spec.get('style', {}).get('font-family')
add_text_to_shape(shp, '%02d' % d.day, **text_style)
# Draw the boundary lines between months
if i >= 7 and d.day == 1 and ny > 0:
......@@ -715,13 +724,15 @@ def calendarmap(shape, spec, data):
if i < 7:
txt = shapes.add_textbox(
x0 - (width / 2), y0 + (width * ny) + (width / 2), width, width)
add_text_to_shape(txt, d.strftime('%a')[0], font_size, default_txt_color)
text_style['color'] = default_txt_color
add_text_to_shape(txt, d.strftime('%a')[0], **text_style)
# Adding months text to the chart (top)
if d.day <= 7 and ny == 0:
txt = shapes.add_textbox(
x0 + (width * nx), y0 - (width / 2), width, width)
add_text_to_shape(txt, d.strftime('%b %Y'), font_size, default_txt_color)
text_style['color'] = default_txt_color
add_text_to_shape(txt, d.strftime('%b %Y'), **text_style)
if label_top:
lo_weekly = spec.get('lo', weekly_mean.min())
......@@ -735,8 +746,8 @@ def calendarmap(shape, spec, data):
rectstyle = {"fill": fill_rect, 'stroke': stroke}
rect_css(top_bar, **rectstyle)
top_txt = shapes.add_textbox(px, shape_top - width, width, width)
add_text_to_shape(
top_txt, weekly_format.format(weekly_mean[nx]), font_size, text_color)
text_style['color'] = text_color
add_text_to_shape(top_txt, weekly_format.format(weekly_mean[nx]), **text_style)
if label_left:
lo_weekday = spec.get('lo', weekday_mean.min())
......@@ -749,8 +760,8 @@ def calendarmap(shape, spec, data):
rectstyle = {"fill": fill_rect, 'stroke': stroke}
rect_css(bar, **rectstyle)
left_txt = shapes.add_textbox(shape_left - width, y0 + (width * ny), w, width)
add_text_to_shape(
left_txt, weekday_format.format(weekday_mean[ny]), font_size, text_color)
text_style['color'] = text_color
add_text_to_shape(left_txt, weekday_format.format(weekday_mean[ny]), **text_style)
def bullet(shape, spec, data):
......@@ -786,6 +797,19 @@ def bullet(shape, spec, data):
hi = spec.get('hi', np.nanmax([spec['data'], spec['target'], spec['poor'],
spec['average'], spec['good']]))
default_font = 18
style = {}
common_style = copy.deepcopy(spec.get('style', {}))
css = {'data': common_style.pop('data', {}), 'target': common_style.pop('target', {}),
'poor': common_style.pop('poor', {}), 'good': common_style.pop('good', {}),
'average': common_style.pop('average', {})}
for key, val in css.items():
_style = copy.deepcopy(common_style)
_style.update(val)
if 'font-size' not in _style:
_style['font-size'] = default_font
style[key] = _style
gradient = matplotlib.cm.get_cmap(gradient)
percentage = {'good': 0.125, 'average': 0.25, 'poor': 0.50}
for index, metric in enumerate(['good', 'average', 'poor']):
......@@ -795,9 +819,10 @@ def bullet(shape, spec, data):
_hight = height if orient == 'horizontal' else scaled
yaxis = y if orient == 'horizontal' else y + (width - scaled)
_rect = rect(shapes, x, yaxis, _width, _hight)
rectstyle = {'fill': matplotlib.colors.to_hex(gradient(percentage[metric])),
'stroke': matplotlib.colors.to_hex(gradient(percentage[metric]))}
rect_css(_rect, **rectstyle)
fill = style.get(metric, {})
stroke = fill.get('stroke')
fill = fill.get('fill', matplotlib.colors.to_hex(gradient(percentage[metric])))
rect_css(_rect, **{'fill': fill, 'stroke': stroke or fill})
scaled = scale_data(spec['data'], lo, hi, factor=width)
_width = scaled if orient == 'horizontal' else height / 2.0
......@@ -805,9 +830,10 @@ def bullet(shape, spec, data):
xaxis = x if orient == 'horizontal' else x + height / 4.0
_hight = height / 2.0 if orient == 'horizontal' else scaled
data_rect = rect(shapes, xaxis, yaxis, _width, _hight)
rectstyle = {'fill': matplotlib.colors.to_hex(gradient(1.0)),
'stroke': matplotlib.colors.to_hex(gradient(1.0))}
rect_css(data_rect, **rectstyle)
fill = style.get('data', {})
stroke = fill.get('stroke')
fill = fill.get('fill', matplotlib.colors.to_hex(gradient(1.0)))
rect_css(data_rect, **{'fill': fill, 'stroke': stroke or fill})
if text:
data_text = text(spec['data'])
......@@ -816,9 +842,9 @@ def bullet(shape, spec, data):
text_width_height = _width if orient == 'vertical' else _hight
_xaxis = x + (_width / 4.0) if orient == 'vertical' else x + scaled - (_hight * _factor)
parent = parent.add_textbox(_xaxis, yaxis, text_width_height, text_width_height)
add_text_to_shape(
parent, data_text, spec.get('fontsize', default_font),
_color.contrast(matplotlib.colors.to_hex(gradient(1.0))))
data_txt_style = style.get('data', {})
data_txt_style['color'] = data_txt_style.get('color', _color.contrast(fill))
add_text_to_shape(parent, data_text, **data_txt_style)
if not np.isnan(spec['target']):
line_hight = 10000
......@@ -828,9 +854,10 @@ def bullet(shape, spec, data):
yaxis = y if orient == 'horizontal' else (width - scaled) + y
xaxis = x + scaled if orient == 'horizontal' else x
target_line = rect(shapes, xaxis, yaxis, _width, _hight)
rectstyle = {'fill': matplotlib.colors.to_hex(gradient(1.0)),
'stroke': matplotlib.colors.to_hex(gradient(1.0))}
rect_css(target_line, **rectstyle)
fill = style.get('target', {})
stroke = fill.get('stroke')
fill = fill.get('fill', matplotlib.colors.to_hex(gradient(1.0)))
rect_css(target_line, **{'fill': fill, 'stroke': stroke or fill})
if text:
handler = data.get('handler')
target_text = text(spec['target'])
......@@ -838,9 +865,9 @@ def bullet(shape, spec, data):
yaxis = yaxis - (_width / 2) if orient == 'vertical' else yaxis + (_hight / 5.0)
text_width_height = _width if orient == 'vertical' else _hight
parent = parent.add_textbox(xaxis, yaxis, text_width_height, text_width_height)
add_text_to_shape(
parent, target_text, spec.get('fontsize', default_font),
_color.contrast(matplotlib.colors.to_hex(gradient(percentage['good']))))
target_txt_style = style.get('target', {})
target_txt_style['color'] = target_txt_style.get('color', _color.contrast(fill))
add_text_to_shape(parent, target_text, **target_txt_style)
def rectangle(shape, spec, data):
......@@ -1018,15 +1045,14 @@ def bar_circle(shape, spec, data):
row['width'] - row['width'] / 4.0, row['width'] - row['width'] / 2.0)
font_size = 16
default_txt_color = '#000000'
add_text_to_shape(txt, row['Category'], font_size, default_txt_color)
style = {'font-size': font_size, 'color': default_txt_color}
add_text_to_shape(txt, row['Category'], **style)
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)
font_size = 16
default_txt_color = '#000000'
add_text_to_shape(txt, '{}%'.format(row[bary]), font_size, default_txt_color)
add_text_to_shape(txt, '{}%'.format(row[bary]), **style)
d = circle_data[circle_data['Category'] == row['Category']]
for i, circle in d.iterrows():
......@@ -1068,7 +1094,8 @@ def heatgrid(shape, spec, data):
top - height - height_padding, ((width - twenty_percent) / len(hours)), height)
font_size = 14
default_txt_color = '#000000'
add_text_to_shape(txt, '{}'.format(hour).zfill(2), font_size, default_txt_color)
style = {'font-size': font_size, 'color': default_txt_color}
add_text_to_shape(txt, '{}'.format(hour).zfill(2), **style)
width_padding = 5
width_padding = width_padding * pixel_inch
......@@ -1085,7 +1112,8 @@ def heatgrid(shape, spec, data):
w + twenty_percent, height)
font_size = 14
default_txt_color = '#000000'
add_text_to_shape(txt, name, font_size, default_txt_color)
style = {'font-size': font_size, 'color': default_txt_color}
add_text_to_shape(txt, name, **style)
cmdlist = {
......
......@@ -188,6 +188,23 @@ def conver_color_code(colorcode):
# Custom Charts Functions below(Sankey, Treemap, Calendarmap).
def apply_text_css(run, paragraph, **kwargs):
"""Apply css."""
pixcel_to_inch = 10000
if kwargs.get('color'):
rows_text = run.font.fill
rows_text.solid()
run.font.color.rgb = RGBColor.from_string(conver_color_code(kwargs['color']))
if kwargs.get('font-family'):
run.font.name = kwargs['font-family']
if kwargs.get('font-size'):
run.font.size = pixcel_to_inch * kwargs['font-size']
if kwargs.get('text-align'):
paragraph.alignment = getattr(PP_ALIGN, kwargs['text-align'].upper())
for prop in {'bold', 'italic', 'underline'}:
setattr(run.font, prop, kwargs.get(prop))
def make_element():
"""Function to create element structure."""
nsmap = {
......@@ -595,20 +612,8 @@ class TableProperties():
def apply_table_css(self, cell, paragraph, run, info):
"""Apply Table style."""
pixcel_to_inch = 10000
if info.get('fill'):
cell_fill = cell.fill
cell_fill.solid()
cell_fill.fore_color.rgb = RGBColor.from_string(conver_color_code(info['fill']))
if info.get('color'):
rows_text = run.font.fill
rows_text.solid()
run.font.color.rgb = RGBColor.from_string(conver_color_code(info['color']))
if info.get('font-family'):
run.font.name = info['font-family']
if info.get('font-size'):
run.font.size = pixcel_to_inch * info['font-size']
if info.get('text-align'):
paragraph.alignment = getattr(PP_ALIGN, info['text-align'].upper())
for prop in {'bold', 'italic', 'underline'}:
setattr(run.font, prop, info.get(prop))
apply_text_css(run, paragraph, **info)
......@@ -14,6 +14,9 @@ draw-bullet:
orient: horizontal
text:
function: "lambda v: '%.1f' % v"
style:
font-size: 10
color: '#ff0000'
bullet-chart-vertical:
bullet:
......@@ -26,3 +29,15 @@ draw-bullet:
gradient: 'Oranges'
text:
function: "lambda v: '%.1f' % v"
style:
data:
font-size: 16
color: '#ff00ff'
bold: True
fill: '#ff0000'
stroke: '00ff00'
target:
font-size: 20
color: '#0000ff'
bold: False
fill: '#00ff00'
\ No newline at end of file
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