Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Belangrijk
Deze functie bevindt zich in openbare preview-versie.
Met aangepaste visualisaties kunt u grafieken aanpassen in AI/BI-dashboards, behalve de ingebouwde visualisatietypen. Aangepaste visualisaties maken gebruik van de Vega-Lite-bibliotheek om grafieken uit een JSON-specificatie weer te geven.
Een aangepaste visualisatie maken
- Selecteer een gegevensset.
- Selecteer in het deelvenster Visualisatieconfiguratie de optie Custom Viz onder de sectie Geavanceerde visualisatie.
- Voeg in de sectie Velden de velden toe die u wilt gebruiken. Elk veld heeft een unieke naam. Verwijs naar velden in je Vega-Lite-specificatie met deze namen.
- Voer uw Vega-Lite JSON-specificatie in de Vega-Lite specificatie-editor in.
Voorbeeld: Gelaagd diagram met een doorlopend gemiddelde
Dit voorbeeld maakt een gelaagde grafiek waarin ruwe temperatuurdatapunten worden uitgezet met een lijn als overlay voor het voortschrijdend gemiddelde, op basis van weergegevens uit de Databricks-voorbeelddatasets.
Maak een gegevensset met de volgende query:
SELECT date, temperature AS temp_max FROM samples.accuweather.historical_hourly_imperial WHERE city_name = 'singapore' ORDER BY dateSelecteer in het deelvenster Visualisatieconfiguratie onder Geavanceerd de optie Aangepaste Viz.
Selecteer de gegevensset die u in de vorige stap hebt gemaakt.
Voeg in de sectie Velden een veld toe voor de datumkolom en stel de naam in op
date.Voeg een veld voor de temperatuurkolom toe en stel de naam in op
temp_max.Kopieer de volgende specificatie naar de Vega-Lite specificatie-editor . Als de x-as is geknipt, raadpleegt u Het formaat van een grafiek automatisch wijzigen.
JSON-specificatie
{ "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "width": "container", "height": "container", "config": { "autosize": { "type": "fit", "contains": "padding" } }, "data": { "name": "databricks_query" }, "transform": [ { "window": [{ "field": "temp_max", "op": "mean", "as": "rolling_mean" }], "frame": [-15, 15] } ], "encoding": { "x": { "field": "date", "type": "temporal", "title": "Date" }, "y": { "type": "quantitative", "scale": { "zero": false }, "axis": { "title": "Max temperature and rolling mean" } } }, "layer": [ { "mark": { "type": "point", "opacity": 0.3 }, "encoding": { "y": { "field": "temp_max", "title": "Max temperature" } } }, { "mark": { "type": "line", "color": "red", "size": 3 }, "encoding": { "y": { "field": "rolling_mean", "title": "Rolling mean of max temperature" } } } ] }
Kolommen van de referentiegegevensset
Er zijn twee manieren om te verwijzen naar kolommen in een Vega-Lite specificatie:
Gebruik
"field": "{columnName}". In het volgende voorbeeld wordt dexFieldkolom toegewezen aan de x-as:"encoding": { "x": { "field": "xField", "type": "quantitative" } }Gebruik in expressies
datum["{columnName}"]ofdatum.{columnName}. In het volgende voorbeeld wordt een nieuwexkolom uit derenanglekolommen gedefinieerd:{ "calculate": "datum.r * cos(datum.angle)", "as": "x" }
Zie datum de documentatie over Vega-expressies voor meer informatie.
Het dashboardthema overnemen
Aangepaste visualisaties worden automatisch aangepast aan het thema van het dashboard, inclusief de lichte en donkere modus. De volgende grafiekelementen nemen themawaarden over zonder wijzigingen in uw specificatie:
- As-, legenda-, titel- en koptekstlettertypen komen overeen met de geconfigureerde lettertypen van het dashboard.
- Asrasterlijnen komen overeen met de rasterlijnkleur van het dashboard voor de actieve modus.
- De achtergrond van de grafiek is transparant ten opzichte van de thematische achtergrond van de widget.
Instellingen die u in het blok van config uw specificatie definieert, hebben voorrang op de overgenomen standaardwaarden.
Referentiethemawaarden in expressies
Als u markeringen met themabewuste waarden wilt markeren, verwijst u naar de volgende signalen in een Vega-Lite expressie ({ "expr": "..." }):
| Signaal | Beschrijving |
|---|---|
colors |
Vooraf opgeloste kleurtokens voor de actieve modus. Gebruik deze voor algemene waarden, zoals colors.textPrimary.default, colors.gridColoren colors.markHighlightColor. Indexeer deze niet met [mode]; ze zijn al opgelost. |
mode |
De actieve kleurmodus, ofwel 'light''dark'. Gebruik deze om velden te indexeren dashboardTheme die varianten per modus bieden. |
dashboardTheme |
Het volledige thema dat is geconfigureerd door de eigenaar van het dashboard, inclusief lettertypen (resolvedFontSettings), het categorische palet (visualizationColors) en kleuren per modus (gridLineColor). Voor velden met varianten per modus is de [mode] index vereist. |
De colors en dashboardTheme signalen zijn onafhankelijk.
colors biedt gebruiksvriendelijke tokens die zijn afgestemd op de actieve modus, terwijl dashboardTheme het volledig door de eigenaar geconfigureerde thema beschikbaar stelt. Gebruik colors eerst, en gebruik dashboardTheme voor fonts, het volledige palet of een waarde die colors niet biedt.
In de volgende voorbeelden ziet u hoe u naar themawaarden verwijst:
Gebruik het hoofdlettertype van het dashboard voor een tekstmarkering:
{ "expr": "dashboardTheme.resolvedFontSettings.fieldValue.fontFamily" }Gebruik de titelkleur van het dashboard voor de actieve modus:
{ "expr": "dashboardTheme.resolvedFontSettings.fieldTitle.fontColor[mode]" }Gebruik een kleur uit het categorische palet van het dashboard:
{ "expr": "dashboardTheme.visualizationColors[0]" }
Note
Omdat colors tokens al zijn omgezet voor de actieve modus, moet u ze niet indexeren met [mode]. Gebruik colors.markHighlightColor, niet colors.markHighlightColor[mode]. Voor velden onder dashboardTheme die varianten per modus bevatten, zoals dashboardTheme.gridLineColor[mode], is de [mode] index vereist.
Andere widgets filteren bij selectie
Een aangepaste visualisatie kan fungeren als een kruisfilterbron: wanneer een gebruiker op een markering klikt, filtert de selectie de andere widgets op het dashboard. Als u dit wilt inschakelen, voegt u een puntselectieparameter toe met de gereserveerde naam databricks_mark_selection. De renderer detecteert deze naam en verbindt de selectie met de kruisfilterstatus van het dashboard.
"params": [
{
"name": "databricks_mark_selection",
"select": { "type": "point", "fields": ["categoryName"] }
}
]
De volgende vereisten zijn van toepassing:
- De parameter
namemoet preciesdatabricks_mark_selectionzijn. Elke andere naam wordt behandeld als een reguliere parameter en zorgt niet voor kruislings filteren. -
select.typemoet zijn:point. Intervalselecties (selectiepenseel) worden niet ondersteund als bronnen voor kruislings filteren. -
select.fieldsmoet de veldnamen weergeven die zijn gedefinieerd in de sectie Velden van de widgetconfiguratie, niet de onbewerkte kolomnamen. - Alleen dimensievelden (groeperen) weergeven in
select.fields. Geaggregeerde metingen, zoalsSUM(...)ofAVG(...), kunnen geen kruisfilter aandrijven. - Als u meerdere velden wilt selecteren, moet u ze samen weergeven:
"fields": ["categoryName", "regionName"].
Geselecteerde markeringen markeren
Als u geselecteerde markeringen wilt accentueren, gebruikt u stroke- en strokeWidth-voorwaarden op een markering met vulling (zoals bar, arc of rect) en laat u de color-codering aan uw veld gebonden. Gebruik { "expr": "colors.markHighlightColor" } voor de contour, zodat de markering in zowel de lichte als de donkere modus leesbaar blijft.
In het volgende voorbeeld wordt de rest van het dashboard door categoryName gefilterd wanneer op een balk wordt geklikt. Geselecteerde balken krijgen een omlijning in het thema, terwijl niet-geselecteerde balken worden gedimd met behoud van hun kleurcodering.
JSON-specificatie
{
"$schema": "https://vega.github.io/schema/vega-lite/v6.json",
"data": { "name": "databricks_query" },
"width": "container",
"height": "container",
"config": { "autosize": { "type": "fit", "contains": "padding" } },
"params": [
{
"name": "databricks_mark_selection",
"select": { "type": "point", "fields": ["categoryName"] }
}
],
"mark": { "type": "bar", "stroke": null },
"encoding": {
"x": { "field": "categoryName", "type": "nominal" },
"y": { "field": "salesValue", "type": "quantitative" },
"color": { "field": "categoryName", "type": "nominal" },
"fillOpacity": {
"condition": { "param": "databricks_mark_selection", "value": 1 },
"value": 0.3
},
"stroke": {
"condition": {
"param": "databricks_mark_selection",
"empty": false,
"value": { "expr": "colors.markHighlightColor" }
},
"value": null
},
"strokeWidth": {
"condition": { "param": "databricks_mark_selection", "empty": false, "value": 2 },
"value": 0
}
}
}
Het formaat van een grafiek automatisch wijzigen
Als u de grootte van een grafiek wilt aanpassen aan de container, voegt u de volgende instellingen toe op het hoogste niveau van uw specificatie:
"width": "container",
"height": "container",
"config": {
"autosize": {
"type": "fit",
"contains": "padding"
}
}
Voorbeeldgrafiekspecificaties
In de volgende specificaties ziet u grafieken die niet beschikbaar zijn als ingebouwde visualisatietypen. Zie de Vega-Lite voorbeeldgalerieƫn voor meer voorbeelden.
Kogelgrafiek
Definieer categoryField, currentField, paceField en targetField in de sectie Velden.
JSON-specificatie
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": "container",
"height": "container",
"data": { "name": "databricks_query" },
"config": {
"autosize": { "type": "fit", "contains": "padding" }
},
"transform": [
{
"fold": ["targetField", "paceField", "currentField"],
"as": ["measure_name", "measure_value"]
},
{
"calculate": "toNumber(datum.measure_value)",
"as": "measure_value"
},
{
"calculate": "{ \"targetField\": \"Target\", \"paceField\": \"Pace\", \"currentField\": \"Current\" }[datum.measure_name]",
"as": "measure_label"
},
{
"calculate": "indexof([\"Target\", \"Pace\", \"Current\"], datum.measure_label)",
"as": "measure_order"
}
],
"layer": [
{
"mark": "bar",
"params": [
{
"name": "legend_click",
"select": { "type": "point", "fields": ["measure_label"] },
"bind": "legend"
}
],
"encoding": {
"color": { "field": "measure_label" },
"opacity": { "value": 0 }
}
},
{
"transform": [{ "filter": { "param": "legend_click" } }],
"layer": [
{
"layer": [
{
"mark": { "type": "bar", "tooltip": true },
"encoding": { "color": { "field": "measure_label", "legend": null } },
"transform": [{ "filter": { "field": "measure_label", "oneOf": ["Pace"] } }]
},
{
"mark": { "type": "bar", "height": 7, "tooltip": true },
"encoding": { "color": { "field": "measure_label", "legend": null } },
"transform": [{ "filter": { "field": "measure_label", "oneOf": ["Current"] } }]
},
{
"mark": { "type": "tick", "tooltip": true, "thickness": 3 },
"encoding": { "color": { "field": "measure_label", "legend": null } },
"transform": [{ "filter": { "field": "measure_label", "oneOf": ["Target"] } }]
}
],
"encoding": {
"x": {
"field": "measure_value",
"type": "quantitative",
"stack": null,
"title": "Value",
"axis": { "orient": "bottom" }
},
"color": {
"scale": {
"domain": ["Target", "Pace", "Current"],
"range": ["#000000", "#bcbcbc", "#A66BBF"]
}
},
"order": {
"field": "measure_order",
"type": "quantitative",
"sort": "descending"
}
}
}
],
"encoding": {
"y": {
"field": "categoryField",
"type": "ordinal",
"title": "Category",
"axis": { "labelOverlap": true }
},
"tooltip": [
{ "field": "categoryField", "type": "nominal", "title": "Category" },
{ "field": "currentField", "type": "quantitative", "title": "Current" },
{ "field": "paceField", "type": "quantitative", "title": "Pace" },
{ "field": "targetField", "type": "quantitative", "title": "Target" }
]
}
}
]
}
Meter
Definieer $valueField en $totalField in het gedeelte Velden.
JSON-specificatie
{
"$schema": "https://vega.github.io/schema/vega-lite/v6.json",
"width": "container",
"height": "container",
"data": { "name": "databricks_query" },
"config": {
"concat": { "spacing": 0 },
"autosize": { "type": "fit", "contains": "padding" }
},
"params": [
{ "name": "ring_max", "expr": "min(width, height) / 2 - 16" },
{ "name": "ring_width", "expr": "max(12, (min(width, height) / 2) * 0.12)" },
{ "name": "ring_gap", "expr": "max(4, (min(width, height) / 2) * 0.03)" },
{ "name": "label_color", "value": "#000000" },
{ "name": "ring_background_opacity", "value": 0.3 },
{ "name": "ring0_percent", "value": 100 },
{ "name": "ring0_outer", "expr": "ring_max + 2" },
{ "name": "ring0_inner", "expr": "ring_max + 1" },
{ "name": "ring1_outer", "expr": "ring0_inner - ring_gap" },
{ "name": "ring1_inner", "expr": "ring1_outer - ring_width" },
{ "name": "ring1_middle", "expr": "(ring1_outer + ring1_inner) / 2" },
{ "name": "arc_size", "expr": "220" }
],
"transform": [
{ "as": "ratio", "calculate": "datum['$valueField'] / datum['$totalField']" },
{ "as": "_arc_start_degrees", "calculate": "360 - ( arc_size / 2 )" },
{ "as": "_arc_end_degrees", "calculate": "0 + ( arc_size / 2 )" },
{ "as": "_arc_start_radians", "calculate": "2 * 3.14 * ( datum['_arc_start_degrees'] - 360 ) / 360" },
{ "as": "_arc_end_radians", "calculate": "2 * 3.14 * datum['_arc_end_degrees'] / 360" },
{ "as": "_arc_total_radians", "calculate": "datum['_arc_end_radians'] - datum['_arc_start_radians']" },
{ "as": "_ring_start_radians", "calculate": "datum['_arc_start_radians']" },
{
"as": "_ring_end_radians",
"calculate": "datum['_arc_start_radians'] + ( datum['_arc_total_radians'] * datum['ratio'] )"
}
],
"layer": [
{
"mark": {
"type": "arc",
"color": "lightgrey",
"theta": { "expr": "datum['_arc_start_radians']" },
"radius": { "expr": "ring1_outer" },
"theta2": { "expr": "datum['_arc_end_radians']" },
"radius2": { "expr": "ring1_inner" },
"cornerRadius": 10
}
},
{
"name": "RING",
"mark": {
"type": "arc",
"theta": { "expr": "datum['_ring_start_radians']" },
"radius": { "expr": "ring1_outer" },
"theta2": { "expr": "datum['_ring_end_radians']" },
"radius2": { "expr": "ring1_inner" },
"cornerRadius": 10
},
"encoding": {
"color": {
"value": "#307E31",
"condition": [
{ "test": "datum['ratio'] < 0.33", "value": "#880808" },
{ "test": "datum['ratio'] < 0.66", "value": "#E49B0F" }
]
}
}
},
{
"mark": { "type": "text", "fontSize": 40 },
"encoding": {
"text": { "field": "$valueField" },
"color": {
"value": "#307E31",
"condition": [
{ "test": "datum['ratio'] < 0.33", "value": "#880808" },
{ "test": "datum['ratio'] < 0.66", "value": "#E49B0F" }
]
}
}
}
]
}
Radardiagram
Definieer $key en $value in het gedeelte Velden.
JSON-specificatie
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": "container",
"height": "container",
"config": {
"autosize": { "type": "fit", "contains": "padding" }
},
"data": { "name": "databricks_query" },
"transform": [
{ "window": [{ "op": "row_number", "as": "category" }] },
{ "calculate": "datum.category - 1", "as": "category" },
{
"joinaggregate": [
{ "op": "count", "as": "numCategories" },
{ "op": "max", "field": "$value", "as": "maxValue" }
]
},
{ "calculate": "2 * PI * datum.category / datum.numCategories", "as": "angle" },
{ "calculate": "100 * datum['$value'] / datum.maxValue", "as": "r" },
{ "calculate": "datum.r * cos(datum.angle)", "as": "x" },
{ "calculate": "datum.r * sin(datum.angle)", "as": "y" },
{ "calculate": "110 * cos(datum.angle)", "as": "label_x" },
{ "calculate": "110 * sin(datum.angle)", "as": "label_y" }
],
"layer": [
{
"transform": [
{ "joinaggregate": [{ "op": "count", "as": "numCategories" }] },
{ "aggregate": [{ "op": "max", "field": "numCategories", "as": "numCategories" }] },
{ "calculate": "[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]", "as": "cats" },
{ "flatten": ["cats"], "as": ["cat"] },
{ "filter": "datum.cat <= datum.numCategories" },
{ "calculate": "2 * PI * datum.cat / datum.numCategories", "as": "angle" },
{ "calculate": "100 * cos(datum.angle)", "as": "x" },
{ "calculate": "100 * sin(datum.angle)", "as": "y" }
],
"mark": { "type": "line", "color": "#ddd", "strokeWidth": 1 },
"encoding": {
"x": { "field": "x", "type": "quantitative", "scale": { "domain": [-120, 120] }, "axis": null },
"y": { "field": "y", "type": "quantitative", "scale": { "domain": [-120, 120] }, "axis": null },
"order": { "field": "cat" }
}
},
{
"transform": [
{ "joinaggregate": [{ "op": "count", "as": "numCategories" }] },
{ "aggregate": [{ "op": "max", "field": "numCategories", "as": "numCategories" }] },
{ "calculate": "[20,40,60,80,100]", "as": "levels" },
{ "flatten": ["levels"], "as": ["level"] },
{ "calculate": "[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]", "as": "cats" },
{ "flatten": ["cats"], "as": ["cat"] },
{ "filter": "datum.cat <= datum.numCategories" },
{ "calculate": "2 * PI * datum.cat / datum.numCategories", "as": "angle" },
{ "calculate": "datum.level", "as": "r" },
{ "calculate": "datum.r * cos(datum.angle)", "as": "x" },
{ "calculate": "datum.r * sin(datum.angle)", "as": "y" }
],
"mark": { "type": "line", "color": "#ddd", "strokeWidth": 1 },
"encoding": {
"x": { "field": "x", "type": "quantitative" },
"y": { "field": "y", "type": "quantitative" },
"detail": { "field": "level" },
"order": { "field": "cat" }
}
},
{
"mark": { "type": "line", "color": "#9467bd", "strokeWidth": 2, "interpolate": "linear-closed" },
"encoding": {
"x": { "field": "x", "type": "quantitative" },
"y": { "field": "y", "type": "quantitative" },
"order": { "field": "category" }
}
},
{
"mark": { "type": "point", "filled": true, "size": 50, "color": "#9467bd" },
"encoding": {
"x": { "field": "x", "type": "quantitative" },
"y": { "field": "y", "type": "quantitative" }
}
},
{
"mark": { "type": "text", "fontSize": 14, "fontWeight": "bold" },
"encoding": {
"x": { "field": "label_x", "type": "quantitative" },
"y": { "field": "label_y", "type": "quantitative" },
"text": { "field": "$key", "type": "nominal" }
}
}
],
"view": { "stroke": null }
}
Radiaaldiagram
Definieer $valueField en $colorField in het gedeelte Velden.
JSON-specificatie
{
"$schema": "https://vega.github.io/schema/vega-lite/v6.json",
"width": "container",
"height": "container",
"config": {
"autosize": { "type": "fit", "contains": "padding" }
},
"data": { "name": "databricks_query" },
"transform": [
{
"aggregate": [{ "op": "sum", "field": "$valueField", "as": "total" }],
"groupby": ["$colorField"]
},
{
"window": [{ "op": "rank", "as": "rank" }],
"sort": [{ "field": "total", "order": "descending" }]
}
],
"layer": [
{
"mark": { "type": "arc", "innerRadius": 20, "stroke": "#fff" }
}
],
"encoding": {
"theta": {
"field": "total",
"type": "quantitative",
"scale": { "type": "sqrt" },
"stack": true,
"sort": "descending"
},
"radius": { "field": "total", "scale": { "type": "sqrt", "zero": true } },
"color": {
"field": "$colorField",
"type": "nominal",
"title": "Sub-Category",
"sort": { "field": "total", "order": "descending" },
"legend": { "orient": "right" }
},
"tooltip": [
{ "field": "$colorField", "type": "nominal", "title": "Sub-Category" },
{ "field": "total", "type": "quantitative", "title": "Sales" }
]
},
"view": { "stroke": null }
}
Zonnestraaldiagram
Definieer outerGroupField, innerGroupFielden sizeField in de sectie Velden .
JSON-specificatie
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": "container",
"height": "container",
"data": { "name": "databricks_query" },
"config": {
"autosize": { "type": "fit", "contains": "padding" }
},
"transform": [
{ "calculate": "datum['outerGroupField']", "as": "OUTSIDE" },
{ "calculate": "datum['innerGroupField']", "as": "INSIDE" },
{ "calculate": "datum.OUTSIDE + '-' + datum.INSIDE", "as": "OUT_IN" },
{ "calculate": "toNumber(datum['sizeField'])", "as": "SIZE" }
],
"resolve": {
"scale": { "color": "independent" },
"legend": { "color": "independent" }
},
"layer": [
{
"mark": {
"type": "arc",
"tooltip": true,
"innerRadius": { "expr": "min(width, height)/9" },
"outerRadius": { "expr": "min(width, height)/3" }
},
"encoding": {
"theta": { "field": "SIZE", "type": "quantitative", "stack": true },
"color": {
"field": "OUT_IN",
"type": "ordinal",
"sort": "ascending",
"title": "Inner Grouping",
"scale": {
"range": [
"#1DF9B9",
"#1DE5B9",
"#1DD1B9",
"#1DBDB9",
"#1DA9B9",
"#3DF23B",
"#3DDA3B",
"#3DC23B",
"#3DAA3B",
"#3D923B"
]
}
},
"order": { "field": "OUT_IN", "sort": "ascending" },
"tooltip": [
{ "field": "OUTSIDE", "type": "nominal", "title": "Outer Grouping" },
{ "field": "INSIDE", "type": "nominal", "title": "Inner Grouping" },
{ "field": "SIZE", "type": "quantitative", "title": "Count" }
]
}
},
{
"transform": [
{
"aggregate": [{ "op": "sum", "field": "SIZE", "as": "total_users" }],
"groupby": ["OUTSIDE"]
}
],
"mark": {
"type": "arc",
"tooltip": true,
"innerRadius": { "expr": "min(width, height)/3" }
},
"encoding": {
"theta": {
"field": "total_users",
"type": "quantitative",
"stack": true,
"sort": "ascending",
"title": "Users Count"
},
"color": {
"field": "OUTSIDE",
"type": "ordinal",
"sort": "ascending",
"title": "Outer Grouping",
"scale": { "range": ["#1DD1B9", "#3DC23B"] }
},
"order": { "field": "OUTSIDE", "sort": "ascending" },
"tooltip": [
{ "field": "OUTSIDE", "type": "nominal", "title": "Outer Grouping" },
{ "field": "total_users", "type": "quantitative", "title": "Count" }
]
}
}
]
}
Limitations
- Treemapgrafieken worden niet ondersteund. Vega-Lite biedt geen ondersteuning voor treemaps.
- Afbeeldingsmarkeringen ondersteunen alleen inline base64-afbeeldings-URL's
data:(bijvoorbeelddata:image/png;base64,...) van 37 kB of minder, in PNG-, JPEG- of WebP-indeling. Externe afbeeldings-URL's (https:ofhttp:), relatieve URL's, SVG-afbeeldingen en veld- of expressiegestuurde afbeeldings-URL's worden niet ondersteund.