Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default chart legibility #413

Merged
merged 10 commits into from Apr 5, 2022
1 change: 1 addition & 0 deletions documentation/changelog.rst
Expand Up @@ -8,6 +8,7 @@ v0.10.0 | April XX, 2022

New features
-----------
* Improve legibility of chart axes [see `PR #413 <http://www.github.com/FlexMeasures/flexmeasures/pull/413>`_]

Bugfixes
-----------
Expand Down
60 changes: 60 additions & 0 deletions flexmeasures/data/models/charts/defaults.py
Expand Up @@ -4,6 +4,7 @@
import altair as alt


FONT_SIZE = 16
HEIGHT = 300
WIDTH = 600
REDUCED_HEIGHT = REDUCED_WIDTH = 60
Expand Down Expand Up @@ -36,6 +37,29 @@
title="Time and date",
),
}
LEGIBILITY_DEFAULTS = dict(
config=dict(
axis=dict(
titleFontSize=FONT_SIZE,
labelFontSize=FONT_SIZE,
)
),
title=dict(fontSize=FONT_SIZE),
encoding=dict(
color=dict(
dict(
legend=dict(
titleFontSize=FONT_SIZE,
labelFontSize=FONT_SIZE,
)
)
)
),
)
vega_lite_field_mapping = {
"title": "text",
"mark": "type",
}


def apply_chart_defaults(fn):
Expand All @@ -60,6 +84,12 @@ def decorated_chart_specs(*args, **kwargs):
if "width" not in chart_specs:
chart_specs["width"] = WIDTH

# Improve default legibility
chart_specs = merge_vega_lite_specs(
LEGIBILITY_DEFAULTS,
chart_specs,
)

# Add transform function to calculate full date
if "transform" not in chart_specs:
chart_specs["transform"] = []
Expand All @@ -72,3 +102,33 @@ def decorated_chart_specs(*args, **kwargs):
return chart_specs

return decorated_chart_specs


def merge_vega_lite_specs(child: dict, parent: dict) -> dict:
"""Merge nested dictionaries, with child inheriting values from parent.

Child values are updated with parent values if they exist.
In case a field is a string and that field is updated with some dict,
the string is moved inside the dict under a field defined in vega_lite_field_mapping.
For example, 'title' becomes 'text' and 'mark' becomes 'type'.
"""
d = {}
for k in set().union(child, parent):
if k in parent and k in child:
if isinstance(child[k], str):
child[k] = {vega_lite_field_mapping.get(k, "type"): child[k]}
if isinstance(parent[k], str):
parent[k] = {vega_lite_field_mapping.get(k, "type"): parent[k]}
if (
k in parent
and isinstance(parent[k], dict)
and k in child
and isinstance(child[k], dict)
):
v = merge_vega_lite_specs(child[k], parent[k])
elif k in parent:
v = parent[k]
else:
v = child[k]
d[k] = v
return d
24 changes: 24 additions & 0 deletions flexmeasures/data/tests/test_chart_utils.py
@@ -0,0 +1,24 @@
import pytest

from flexmeasures.data.models.charts.defaults import merge_vega_lite_specs


@pytest.mark.parametrize(
"default_specs, custom_specs, expected_specs",
[
(
{"legend": {"titleFontSize": 16}},
{"title": "foo"},
{"legend": {"titleFontSize": 16}, "title": "foo"},
),
(
{"title": {"fontSize": 16}},
{"title": "foo"},
{"title": {"fontSize": 16, "text": "foo"}},
),
],
)
def test_merge_vega_lite_specs(
default_specs: dict, custom_specs: dict, expected_specs: dict
):
assert merge_vega_lite_specs(default_specs, custom_specs) == expected_specs
2 changes: 2 additions & 0 deletions flexmeasures/ui/static/css/flexmeasures.css
Expand Up @@ -504,3 +504,5 @@ i.icon-wind:hover:before {
.icon-buildings:before { content: '\e803'; } /* '' */
.icon-charging_stations:before { content: '\e805'; } /* '' */
.icon-bidirectional_charging_stations:before { content: '\e805'; } /* '' */

.litepicker { font-size: 14px;}
2 changes: 1 addition & 1 deletion flexmeasures/ui/templates/views/sensors.html
Expand Up @@ -71,7 +71,7 @@
numberOfMonths: 2,
numberOfColumns: 2,
inlineMode: true,
switchingMonths: 2,
switchingMonths: 1,
singleMode: false,
dropdowns: {
years: true,
Expand Down