Public
Edited
May 30
Paused
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// https://data.ecb.europa.eu/help/data-examples
wechselkurs_data = d3.csv(
"https://data-api.ecb.europa.eu/service/data/EXR/D.AUD+THB+BRL+BGN+DKK+HUF+HKD+INR+ISK+CAD+MYR+MXN+ILS+NZD+NOK+GBP+PHP+ZAR+RON+IDR+SEK+CHF+SGD+CZK+TRY+USD+KRW+JPY+CNY+PLN.EUR.SP00.A?startPeriod=2023-10-01&format=csvdata"
)
Insert cell
wechselkurs = wechselkurs_data.map((d) => ({
date: new Date(d.TIME_PERIOD),
rate: +d.OBS_VALUE,
currency1: d.CURRENCY_DENOM,
currency2: d.CURRENCY
}))
Insert cell
wechselkurs
SELECT date, rate, currency1, currency2 FROM wechselkurs
WHERE currency2 = ${currency_code}
ORDER BY date DESC
LIMIT ${time}
Insert cell
currency_data = FileAttachment("wechselkurse_filtered@6.csv").csv()
Insert cell
currency_default = currency_data.filter((d) => d.Code == currency)[0].Währung
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
ymin = direction == first
? +d3.min(wechselkurs_filtered.map((d) => d.rate))
: +d3.min(wechselkurs_filtered.map((d) => 1 / d.rate))
Insert cell
Insert cell
function isoAlphaFlagImage(iso, type, width) {
let src = isoAlphaFlagURL(iso, type);
let w = width && width > 0 ? width : 100;
return direction == first
? htl.html`<div class="container"><img style="margin-right: 5px;" src="https://hatscripts.github.io/circle-flags/flags/eu.svg" width="${w}"><span>→</span><img style="margin-left: 5px;" src="${src}" width="${w}"></div>`
: htl.html`<div class="container"><img style="margin-right: 5px;" src="${src}" width="${w}"><span>→</span><img style="margin-left: 5px;" src="https://hatscripts.github.io/circle-flags/flags/eu.svg" width="${w}"></div>`;
}
Insert cell
Insert cell
Insert cell
function plotCustomTooltip(
data,
{ tooltipHeight, tooltipWidth, x, y, currency }
) {
return Plot.marks(
Plot.tip(
data,
Plot.pointerX({
x: x,
y: y,
// Extend the tip mark render function
render: (index, scales, values, dimensions, context) => {
const g = d3.select(context.ownerSVGElement).append("g");
const [i] = index;
if (i !== undefined) {
// const formatTime = d3.utcFormat("%d %b %Y");
const formatTime = (d) =>
d.toLocaleString("de", {
year: "numeric",
month: "numeric",
day: "numeric"
});
const priceDate = formatTime(values.channels.x.value[i]);
const closePrice = values.channels.y.value[i].toLocaleString("de", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
// The tooltip starts after the left margin in the x-axis to avoid blocking the y-axis labels
// We start to translate the tooltip when the pointer is halfway the initial tooltip location
// We stop moving the tooltip when there's not enough width available within the container
const currentXPosition = values.x[i];
const tooltipStartPosition = dimensions.marginLeft + 10;
const tooltipDefaultPosition = currentXPosition - tooltipWidth / 2;
const tooltipEndPosition =
dimensions.width - dimensions.marginRight - tooltipWidth;
g.attr(
"transform",
`translate(${Math.min(
currentXPosition <= tooltipWidth / 2 + dimensions.marginLeft
? tooltipStartPosition
: tooltipDefaultPosition,
tooltipEndPosition
)}, 0)`
).append(
() =>
svg`${htmlTooltip({
price: closePrice,
date: priceDate,
currency: currency,
width: tooltipWidth,
height: tooltipHeight
})}`
);
}
return g.node();
}
})
)
);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
style = html`

<div></div>

<style>

.tooltip {
background-color: #fff;
font-weight: 400;
font-size: 12px;
height: 28px;
line-height: 28px;
padding-left: 8px;
padding-right: 8px;
position: absolute;
top: 0px;
left: 0px;
border-radius: 2px;
box-shadow: 0 1px 3px rgba(0,0,0,.2), 0 1px 1px rgba(0,0,0,.14);
z-index: 2;
}

.tooltip-price {
margin-right: 5px;
}

.tooltip-time {
color: #99AFC2;
}

.container {
display: flex;
align-items: center;
margin-bottom: 15px;
}

text, p, span, label, .${ns} select, .${ns} input, .legend {
line-height: 125%;
font-weight: 400;
font-size: 12px;
color: #0f151a;
font-family: InterRegular;
background-color: #ffffff;
}

@font-face {
font-family: Source Serif Pro;
src: url(https://static.rndtech.de/share/rnd/jchrist/SourceSerifPro-Regular.ttf);
}

@font-face {
font-display: swap;
font-family: 'DIN Next LT Pro';
font-style: normal;
font-weight: 700;
src: url(https://static.rndtech.de/share/rnd/jchrist/DINNextLTPro-Bold.woff2) format("woff2"),
url(https://static.rndtech.de/share/rnd/jchrist/DINNextLTPro-Bold.woff) format("woff"),
url(https://static.rndtech.de/share/rnd/jchrist/DINNextLTPro-Bold.ttf) format("truetype")
}
@font-face {
font-display: swap;
font-family: 'InterRegular';
font-style: normal;
font-weight: 400;
src: url(https://static.rndtech.de/share/rnd/jchrist/Inter-Regular.woff2) format("woff2"),
url(https://static.rndtech.de/share/rnd/jchrist/Inter-Regular.woff) format("woff"),
url(https://static.rndtech.de/share/rnd/jchrist/Inter-Regular.ttf) format("truetype")
}

@font-face {
font-display: swap;
font-family: 'InterMedium';
font-style: normal;
font-weight: 500;
src: url(https://static.rndtech.de/share/rnd/jchrist/Inter-Medium.woff2) format("woff2"),
url(https://static.rndtech.de/share/rnd/jchrist/Inter-Medium.woff) format("woff"),
url(https://static.rndtech.de/share/rnd/jchrist/Inter-Medium.ttf) format("truetype")
}

@font-face {
font-display: swap;
font-family: 'InterBold';
font-style: normal;
font-weight: 700;
src: url(https://static.rndtech.de/share/rnd/jchrist/Inter-Bold.woff2) format("woff2"),
url(https://static.rndtech.de/share/rnd/jchrist/Inter-Bold.woff) format("woff"),
url(https://static.rndtech.de/share/rnd/jchrist/Inter-Bold.ttf) format("truetype")
}

h2 {
color: rgb(15, 21, 26);
font-family: "DIN Next LT Pro", sans-serif;
font-weight: 700;
font-size: 22px;
margin: 0px 0px 0px 0px;
}

.subtitle {
font-family: "Source Serif Pro", serif;
font-size: 17px;
font-weight: 400;
color: rgb(41, 56, 69);
letter-spacing: 0px;
line-height: 26px;
}

.credits {
font-size: 12px;
color: #99AFC2;
font-family: InterRegular, sans-serif;
font-weight: 400;
position:relative;
}

@media (prefers-color-scheme: dark) {

svg {
background-color: #293845 !important;
color: white !important;
}

.mode {
color: #ffffff;
background-color: #293845;
}
.subtitle {
font-family: "Source Serif Pro", serif;
font-size: 17px;
font-weight: 400;
color: #ffffff;
}

.tooltip {
background-color: #293845;
box-shadow: 0 1px 3px rgba(255,255,255,.2), 0 1px 1px rgba(255,255,255,.14);
}

text, p, span, label, .${ns} select, .legend, .${ns} input {
line-height: 125%;
font-weight: 400;
font-size: 12px;
color: #ffffff;
font-family: InterRegular;
background-color: #293845;
}

}

</style>`
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more