Hey everyone – I just wanted share a really cool project that we came across today: GitHub - aftertheflood/sparks: A typeface for creating sparklines in text without code.
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” GitHub - Misfits-Rebels-Outcasts/Blazor-Sparkline: Sparkline Charts for Blazor using Fonts. 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: dash-docs/index.py at master · plotly/dash-docs · GitHub
Enjoy! And if you make something with these fonts, please do share