Hey everyone – I just wanted share a really cool project that we came across today: https://github.com/aftertheflood/sparks
That project creates custom font families that render sets of numbers as simple bar chart and line charts. We’re not affiliated with the project, but huge fans of the approach!
Rendering simple charts like this as fonts is really great for Dash because it means that you can embed these sparklines almost anywhere in your apps. I immediately thought of the DataTable, especially after embedding things like emojis in cells in the conditional formatting chapter.
Here’s an example of a simple app:
import dash
import dash_html_components as html
import dash_table
import dash_core_components as dcc
app = dash.Dash(__name__)
app.layout = html.Div([
html.H1(
className='sparks dotline-extrathick',
children='123{30,60,90,60,100,50,45,20}456'
),
html.Div(className='sparks dotline-extrathick', children=[
dash_table.DataTable(
columns=[
{'id': 'Summary', 'name': 'Summary'},
{'id': 'Overview', 'name': 'Overview'},
],
data=[
{
'Summary': '123{30,60,90,60,100,50,45,20}456',
'Overview': i
} for i in range(20)
],
style_data_conditional=[
{
'if': {'column_id': 'Summary'},
'width': 100
}
]
),
]),
])
app.run_server(debug=True)
Which uses this CSS (note these font familes are hosted by a third party, so don’t use this in any production apps! You never know when aftertheflood.com might go down and we should respect their bandwidth)
@font-face {
font-family: 'Sparks-Bar-Narrow';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Bar-Narrow.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Bar-Narrow.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Bar-Narrow.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Bar-Narrow.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Bar-Narrow.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Bar-Narrow.svg#Sparks-Bar-Narrow') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Bar-Medium';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Bar-Medium.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Bar-Medium.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Bar-Medium.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Bar-Medium.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Bar-Medium.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Bar-Medium.svg#Sparks-Bar-Medium') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Bar-Wide';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Bar-Wide.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Bar-Wide.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Bar-Wide.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Bar-Wide.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Bar-Wide.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Bar-Wide.svg#Sparks-Bar-Wide') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Bar-Extrawide';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Bar-Extrawide.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Bar-Extrawide.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Bar-Extrawide.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Bar-Extrawide.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Bar-Extrawide.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Bar-Extrawide.svg#Sparks-Bar-Extrawide') format('svg');
font-weight: normal;
font-style: normal;
}
/* Dots */
@font-face {
font-family: 'Sparks-Dot-Extrasmall';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dot-Extrasmall.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dot-Extrasmall.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Dot-Extrasmall.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Dot-Extrasmall.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Dot-Extrasmall.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Dot-Extrasmall.svg#Sparks-Dot-Extrasmall') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Dot-Small';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dot-Small.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dot-Small.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Dot-Small.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Dot-Small.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Dot-Small.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Dot-Small.svg#Sparks-Dot-Small') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Dot-Medium';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dot-Medium.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dot-Medium.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Dot-Medium.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Dot-Medium.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Dot-Medium.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Dot-Medium.svg#Sparks-Dot-Medium') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Dot-Large';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dot-Large.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dot-Large.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Dot-Large.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Dot-Large.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Dot-Large.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Dot-Large.svg#Sparks-Dot-Large') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Dot-Extralarge';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dot-Extralarge.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dot-Extralarge.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Dot-Extralarge.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Dot-Extralarge.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Dot-Extralarge.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Dot-Extralarge.svg#Sparks-Dot-Extralarge') format('svg');
font-weight: normal;
font-style: normal;
}
/* Dot-lines */
@font-face {
font-family: 'Sparks-Dotline-Extrathin';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dotline-Extrathin.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dotline-Extrathin.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Dotline-Extrathin.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Dotline-Extrathin.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Dotline-Extrathin.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Dotline-Extrathin.svg#Sparks-Dotline-Extrathin') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Dotline-Thin';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dotline-Thin.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dotline-Thin.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Dotline-Thin.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Dotline-Thin.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Dotline-Thin.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Dotline-Thin.svg#Sparks-Dotline-Thin') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Dotline-Medium';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dotline-Medium.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dotline-Medium.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff/2Sparks-Dotline-Medium.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Dotline-Medium.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Dotline-Medium.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Dotline-Medium.svg#Sparks-Dotline-Medium') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Dotline-Thick';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dotline-Thick.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dotline-Thick.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Dotline-Thick.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Dotline-Thick.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Dotline-Thick.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Dotline-Thick.svg#Sparks-Dotline-Thick') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sparks-Dotline-Extrathick';
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dotline-Extrathick.eot');
src: url('https://tools.aftertheflood.com/sparks/output/eot/Sparks-Dotline-Extrathick.eot?#iefix') format('embedded-opentype'),
url('https://tools.aftertheflood.com/sparks/output/woff2/Sparks-Dotline-Extrathick.woff2') format('woff2'),
url('https://tools.aftertheflood.com/sparks/output/woff/Sparks-Dotline-Extrathick.woff') format('woff'),
url('https://tools.aftertheflood.com/sparks/output/ttf/Sparks-Dotline-Extrathick.ttf') format('truetype'),
url('https://tools.aftertheflood.com/sparks/output/svg/Sparks-Dotline-Extrathick.svg#Sparks-Dotline-Extrathick') format('svg');
font-weight: normal;
font-style: normal;
}
.sparks {
font-variant-ligatures: normal;
}
.bar-narrow {
font-family: Sparks-Bar-Medium;
}
.bar-medium {
font-family: Sparks-Bar-Medium;
}
.bar-wide {
font-family: Sparks-Bar-Wide;
}
.bar-extrawide {
font-family: Sparks-Bar-Wide;
}
.dot-extrasmall {
font-family: Sparks-Dot-Extrasmall;
}
.dot-small {
font-family: Sparks-Dot-Small;
}
.dot-medium {
font-family: Sparks-Dot-Medium;
}
.dot-large {
font-family: Sparks-Dot-Large;
}
.dot-extralarge {
font-family: Sparks-Dot-Extralarge;
}
.dotline-extrathin {
font-family: Sparks-Dotline-Extrathin;
}
.dotline-thin {
font-family: Sparks-Dotline-Thin;
}
.dotline-medium {
font-family: Sparks-Dotline-Medium;
}
.dotline-thick {
font-family: Sparks-Dotline-Thick;
}
.dotline-extrathick {
font-family: Sparks-Dotline-Extrathick;
}
.final-value{
color:#F00;
}
It’s a very cool approach and there some other projects out there that do similar things, like “Blazor Sparklines” https://github.com/Misfits-Rebels-Outcasts/Blazor-Sparkline. For more, try googling “Sparklines as fonts”
It would be great to get some helpful examples of this approach into the conditional formatting documentation. If anyone would like to contribute to Dash, here is the source code to that chapter: https://github.com/plotly/dash-docs/blob/master/dash_docs/chapters/dash_datatable/conditional_formatting/index.py
Enjoy! And if you make something with these fonts, please do share
1 post - 1 participant