'Customize tooltip in Altair chart
I'm using Google Colab for learning Python. In this Google Colab notebook I've built for demostration, I was able to get some JSON data and visualize it with Altair.
This is the chart image I got so far - you can interact with the data in the linked Google Colab notebook or directly in the vega-editor ready with the sample data:
Below is the explanation of the data I have and what I want to show:
In Yu-Gi-Oh! TCG, cards came from a certain card set. In each card set are Monster, Spell and Trap cards - as well another type of cards like: Link Monsters, XYZ monsters, etc.
A normal JSON structure of a monster card (- for this purpose - has ATK and DEF) has the following JSON structure:
{
"id":89631139,
"name":"Blue-Eyes White Dragon",
"type":"Normal Monster",
"atk":3000,
"def":2500,
"level":8,
"race":"Dragon",
"attribute":"LIGHT",
"archetype":"Blue-Eyes"
}
But, a non-monster card (i.e. a spell card) has no values neither in ATK and DEF attributes:
Example:
{
"id":35261759,
"name":"Pot of Desires",
"type":"Spell Card",
"race":"Normal",
"archetype":"Greed"
}
I want to visualize in the chart each card that comes in the card set and - while the cursor is on a point (hover), it will show the details of the card like, (Name, ATK, DEF (if any) and the Type of card).
Example of desired tooltip:
After some trial and error, research and read the documentation, I'm facing the following issues and wondering if the results I'm looking are possible:
- When you hover on a point that does not have ATK and DEF - (see image 1) = how to modify the settings of Altair chart for condition the build of the tooltip? - see image 1:
Image 1:
In "image 1", the card called "Pot of Desires" is a Spell Card = it doesn't have ATK or DEF, I've configured the chart with the invalid property for shown Nulll / None / NaN values) and Altair sets 0 as default to those missing values.
The expected output in (for a non-monster card) would be:
Name: Pot of Desires
Type: Spell Card
The expected output in (for a monster card) would be:
Name: Blue-Eyes White Dragon
ATK: 3000 - DEF: 2500
Type: Normal Monster
The expected output in (for a link monster card = has ATK, but no DEF) would be:
Name: Proxy Dragon
ATK: 3000
Type: Link Monster
I want to condition how to build the tooltip in these scenarios, it is possible?
Solution 1:[1]
Thanks to @joelostblom's answer, my case scenario is not possible - yet - let's hope this scenario could be more common in order to raise more attention of the pull request/feature I've created - https://github.com/vega/vega-lite/issues/7811.
Meanwhile, the accepted answer is: is not possible, but, I'll checking for new answers and possible solutions.
That being said, I decide to check further and share my findings here:
- Using Vega Expressions, I tried to customize the tooltip data and I got pretty good results, IMHO, but, not as close as I intended.
Here are the results I mentioned:
The Python code of the previous chart is as follows:
# V.2 of the chart/graph:
alt.Chart(df).mark_point(size=200, filled=True, invalid=None, tooltip={'content': 'data'}).encode(
x={"field": "def", "type": "quantitative", "title": "DEF"},
y={"field": "atk", "type": "quantitative", "title": "ATK"},
color={"field": "type", "type": "nominal", "title": "Types of cards"},
shape="type"
).properties(
title={
"text": ["Cardset: " + cardSetName],
"subtitle": ["Here is shown the " + str(len(df.index)) + " card" + ('s' if len(df.index) > 1 or str(len(df.index)) == 0 else '') + " contained in the cardset."]
}
).transform_calculate(
Name = "datum.name",
Type = "datum.race + ' ' + ((substring(datum.type, datum.type.length-1, datum.type.length) == 's') ? substring(datum.type, 2, datum.type.length-1) : substring(datum.type, 2, datum.type.length))",
ATK_DEF = "isValid(datum.atk) ? '' + datum.atk + (isValid(datum.def) ? '/' + datum.def : '') : 'N/A'"
).interactive()
- The rest of the data is added thanks to
tooltip={'content': 'data'}configuration. If there would be a way to declare the fields to use only in the tooltip, this scenario would be possible with Vega/Altair.
Here, I share, the code you can copy/paste in the Vega Editor for try it yourself.
N.B. This is the direct vega-editor link with the sample data.
VEGA-LITE Code:
{
"config": {"view": {"continuousWidth": 400, "continuousHeight": 300}},
"data": {"name": "data-5583486ec9c6448394a7b9390873045c"},
"mark": {
"type": "point",
"filled": true,
"invalid": null,
"size": 200,
"tooltip": {"content": "data"}
},
"encoding": {
"color": {"type": "nominal", "field": "type", "title": "Types of cards"},
"shape": {"type": "nominal", "field": "type"},
"x": {"type": "quantitative", "field": "def", "title": "DEF"},
"y": {"type": "quantitative", "field": "atk", "title": "ATK"}
},
"selection": {
"selector149": {
"type": "interval",
"bind": "scales",
"encodings": ["x", "y"]
}
},
"title": {
"text": ["Cardset: 2017 Mega-Tins"],
"subtitle": ["Here is shown the 8 cards contained in the cardset."]
},
"transform": [
{"calculate": "datum.name", "as": "Name"},
{
"calculate": "datum.race + ' ' + ((substring(datum.type, datum.type.length-1, datum.type.length) == 's') ? substring(datum.type, 2, datum.type.length-1) : substring(datum.type, 2, datum.type.length))",
"as": "Type"
},
{
"calculate": "isValid(datum.atk) ? '' + datum.atk + (isValid(datum.def) ? '/' + datum.def : '') : 'N/A'",
"as": "ATK_DEF"
}
],
"$schema": "https://vega.github.io/schema/vega-lite/v4.8.1.json",
"datasets": {
"data-5583486ec9c6448394a7b9390873045c": [
{
"id": 89631139,
"name": "Blue-Eyes White Dragon",
"type": "2 Normal Monsters",
"desc": "This legendary dragon is a powerful engine of destruction. Virtually invincible, very few have faced this awesome creature and lived to tell the tale.",
"atk": 3000,
"def": 2500,
"level": 8,
"race": "Dragon",
"attribute": "LIGHT",
"archetype": "Blue-Eyes"
},
{
"id": 46986414,
"name": "Dark Magician",
"type": "2 Normal Monsters",
"desc": "The ultimate wizard in terms of attack and defense.",
"atk": 2500,
"def": 2100,
"level": 7,
"race": "Spellcaster",
"attribute": "DARK",
"archetype": "Dark Magician"
},
{
"id": 26920296,
"name": "Dreamland",
"type": "2 Spell Cards",
"desc": "This card can activate these effects depending on the monster card types on the field.\n? Fusion: Once per turn, if a monster(s) is sent from your hand or field to the GY by a card effect (except during the Damage Step): You can draw 1 card.\n? Synchro: When a monster(s) is Normal or Special Summoned (except during the Damage Step): You can increase their Levels by 1.\n? Xyz: Once per turn, during your End Phase: Destroy the monster(s) on the field with the highest Level.\nYou can only activate 1 \"Dreamland\" per turn.",
"atk": null,
"def": null,
"level": null,
"race": "Field",
"attribute": null,
"archetype": null
},
{
"id": 80532587,
"name": "Elder Entity N'tss",
"type": "1 Fusion Monster",
"desc": "1 Synchro Monster + 1 Xyz Monster\nMust be Special Summoned (from your Extra Deck) by sending the above cards you control to the GY. (You do not use \"Polymerization\".) Once per turn: You can Special Summon 1 Level 4 monster from your hand. If this card is sent to the GY: You can target 1 card on the field; destroy it. You can only Special Summon \"Elder Entity N'tss(s)\" once per turn.",
"atk": 2500,
"def": 1200,
"level": 4,
"race": "Fairy",
"attribute": "LIGHT",
"archetype": null
},
{
"id": 23085002,
"name": "Number 68: Sanaphond the Sky Prison",
"type": "2 XYZ Monsters",
"desc": "2 Level 8 monsters\nGains 100 ATK and DEF for each monster in the GYs. Once per turn: You can detach 1 material from this card; until the end of your opponent's next turn, this card cannot be destroyed by card effects, also neither player can Special Summon monsters from the GYs.",
"atk": 2100,
"def": 2700,
"level": 8,
"race": "Rock",
"attribute": "DARK",
"archetype": null
},
{
"id": 59479050,
"name": "Number 71: Rebarian Shark",
"type": "2 XYZ Monsters",
"desc": "2 Level 3 monsters\nOnce per turn, if this card has material: You can target 1 \"Number\" Xyz Monster in your GY, except \"Number 71: Rebarian Shark\"; Special Summon it, and if you do, attach 1 material from this card to it. If this card is sent to the GY: You can choose 1 \"Rank-Up-Magic\" Spell from your Deck and place it on top of your Deck.",
"atk": 0,
"def": 2000,
"level": 3,
"race": "Dragon",
"attribute": "WATER",
"archetype": null
},
{
"id": 35261759,
"name": "Pot of Desires",
"type": "2 Spell Cards",
"desc": "Banish 10 cards from the top of your Deck, face-down; draw 2 cards. You can only activate 1 \"Pot of Desires\" per turn.",
"atk": null,
"def": null,
"level": null,
"race": "Normal",
"attribute": null,
"archetype": "Greed"
},
{
"id": 22862454,
"name": "Proxy Dragon",
"type": "1 Link Monster",
"desc": "2 monsters\r\nIf a card(s) you control would be destroyed by battle or card effect, you can destroy 1 of your monsters this card points to, instead.",
"atk": 1400,
"def": null,
"level": null,
"race": "Cyberse",
"attribute": "LIGHT",
"archetype": null
}
]
}
}
CONFIG:
{}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |




