在 Altair 图表中自定义工具提示

Customize tooltip in Altair chart

我正在使用 Google Colab 进行学习 Python。在这个Google Colab notebook I've built for demostration, I was able to get some JSON data and visualize it with Altair.

这是我目前得到的图表图像 - 您可以与 linked Google Colab notebook or directly in the vega-editor ready with the sample data:

中的数据进行交互

下面是我所拥有的数据和我想展示的内容的解释:

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.

一张正常JSON怪物卡的结构(-为此目的-具有ATK和DEF)具有以下 JSON 结构:

{
   "id":89631139,
   "name":"Blue-Eyes White Dragon",
   "type":"Normal Monster",
   "atk":3000,
   "def":2500,
   "level":8,
   "race":"Dragon",
   "attribute":"LIGHT",
   "archetype":"Blue-Eyes"
}

但是,非怪物卡(即法术卡)在ATK和DEF属性上都没有值:

示例:

{
   "id":35261759,
   "name":"Pot of Desires",
   "type":"Spell Card",
   "race":"Normal",
   "archetype":"Greed"
}

我想在图表中可视化卡片组中的每张卡片,并且-当光标在一个点上时(悬停),它将显示卡片的详细信息卡片,(名称、攻击力、防御力(如果有)和卡片类型)。

所需工具提示的示例:

经过反复试验、研究和阅读文档后,我遇到了以下问题,想知道我正在寻找的结果是否可行:

图片 1:

在“图片 1”中,名为“Pot of Desires”的卡片是一张符卡 = 它没有 ATK 或 DEF,我用 [=23= 配置了图表] 对于显示的 Nulll / None / NaN 值)和 Altair 将 0 作为默认值设置为那些缺失值 .

对于非怪物卡)的预期输出为:

Name: Pot of Desires

Type: Spell Card

对于怪物卡)的预期输出为:

Name: Blue-Eyes White Dragon

ATK: 3000 - DEF: 2500

Type: Normal Monster

for a link monster card = has ATK, but no DEF)的预期输出是:

Name: Proxy Dragon

ATK: 3000

Type: Link Monster

我想调节在这些场景中如何构建工具提示,这可能吗?

我认为这是不可能的,请参阅 https://github.com/vega/vega-tooltip/issues/251. In summary it seems like Vega and VegaTooltip does remove fields with Undefined form the tooltip, but VegaLite forces these to be shown in the tooltip (compare this VegaLite spec with this Vega one)。他们似乎正在寻求帮助来实现您想要的功能。

以下是您的数据示例,说明了 nullUndefined 值如何显示在工具提示中:

df = pd.DataFrame([{
   "id":89631139,
   "name":"Blue-Eyes White Dragon",
   "type":"Normal Monster",
   "atk":3000,
   "def":2500,
   "level":8,
   "race":"Dragon",
   "attribute":"LIGHT",
   "archetype":"Blue-Eyes"
},
{
   "id":35261759,
   "name":"Pot of Desires",
   "type":"Spell Card",
   "race":"Normal",
   "archetype":"Greed"
}])

alt.Chart(df).mark_point(tooltip={'content': 'data'}).encode(
    x='name',
    y='type'
).transform_calculate(
   A = "isValid(datum.atk) ? datum.atk : 'Undefined'",
   D = "isValid(datum.def) ? datum.def : 'Undefined'"
)

感谢, 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

同时,接受的答案是:不可能,但是,我会检查新的答案和可能的解决方案。


话虽如此,我决定进一步检查并在此处分享我的发现:

  • 使用 Vega Expressions,我尝试自定义工具提示数据,我得到了很好的结果,恕我直言,但是,没有我预期的那么接近。

这是我提到的结果:

上图的Python代码如下:

# 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()
  • 由于 tooltip={'content': 'data'} 配置,其余数据已添加。 如果有一种方法可以声明仅在工具提示中使用的字段,那么 Vega/Altair.
  • 就可以实现这种情况

在这里,我分享,代码你可以copy/paste在Vega Editor中自己尝试一下。

N.B。这是 direct vega-editor link with the sample data.

VEGA-LITE 代码:

{
  "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
      }
    ]
  }
}

配置:

{}