简体   繁体   English

使用 Altair 在堆积面积图中堆积文本

[英]Stacked text in a stacked area chart using Altair

I wanted to know if it is possible to have text marks in the corresponding areas of a stacked area chart.我想知道是否可以在堆积面积图的相应区域中有文本标记。

I used median aggregate to get single X and Y axis values otherwise it shows text all through the edge of the chart.我使用median聚合来获取单个 X 和 Y 轴值,否则它会显示整个图表边缘的文本。 However, this aggregate is not foolproof, as if the chart is a little convoluted, then the X axis position may not be the best possible region for the text to be displayed into.但是,这个集合并不是万无一失的,好像图表有点复杂,那么 X 轴 position 可能不是显示文本的最佳区域。

This is as far as I have got -这是据我所知-

X=[1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9]
V=[1,1,1,2,4,8,6,4,2,1,2,3,4,5,6,7,6,5,1,1,1,1,4,8,4,2,1,1,1,3,4,5,6,6,5,4]
key=['a', 'b', 'c', 'd']
K = [y for x in key for y in (x)*9]

demo = pd.DataFrame({'X': X, 'V': V, 'K': K})
a = alt.Chart(demo).mark_area().encode(
    x='X:O',
    y='V:Q',
    color='K:N'
)
t = alt.Chart(demo).mark_text().encode(
    x='median(X):O',
    y='median(V):Q',
    text=alt.Text('K:N',)
)
a+t

在此处输入图像描述

Issue问题

  • The text is not in its proper region.文本不在其正确的区域。
  • The order of the text is also wrong.正文的顺序也错了。

It's not that I don't understand why I have these issues, I do actually(the Y position is not aggregating as "stacked" on top of each other), but I do not know how to solve it or if it is even doable as of now.并不是说我不明白为什么我会遇到这些问题,我实际上是这样做的(Y position 没有聚合为“堆叠”在彼此之上),但我不知道如何解决它,或者它是否可行截至目前。

I would just build a separate dataframe for the text and use that as source.我将为文本构建一个单独的 dataframe 并将其用作源。 It is much easier and customizable than doing all sorts of transformations in Altair if such a thing is even possible in this case.如果在这种情况下甚至有可能,它比在 Altair 中进行各种转换更容易和可定制。

import pandas as pd
import altair as alt

X=[1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9]
V=[1,1,1,2,4,8,6,4,2,1,2,3,4,5,6,7,6,5,1,1,1,1,4,8,4,2,1,1,1,3,4,5,6,6,5,4]
key=['a', 'b', 'c', 'd']
K = [y for x in key for y in (x)*9]

demo = pd.DataFrame({'X': X, 'V': V, 'K': K})

# find X position where the sum of V's of K's is the maximum (this is at X=6)
idxmax = demo.groupby(["X"]).sum().idxmax()[0]
# find the cumulative sum of V's at position idxmax and
# take away some offset (4) so the labels go down a bit
# iloc[::-1] reverses the order because we want cumulative to start from the bottom (from 'd')
ypos = demo.groupby(["X", "K"]).sum().loc[idxmax].iloc[::-1].cumsum()["V"] - 4
# crate a new dataframe for the text, X column=idmax, Y column=cumulative ypos, K=key
demotext = pd.DataFrame([[idxmax, y, k] for y,k in zip(ypos.tolist(), key[::-1])],
                        columns=["X", "Y", "K"])


a = (alt.Chart(demo).mark_area()
        .encode(
                x='X:O',
                y='V:Q',
                color='K:N')
    )
t = (alt.Chart(demotext).mark_text()
        .encode(
                x='X:O',
                y='Y:Q',
                text='K:N'
))

a+t

Output Output

带文字的 Altair 面积图

I have come to realize that it may not be possible to do it programmatically or maybe its not worth it because of the complexities involved like peaks that are not aligned.我开始意识到,可能无法以编程方式执行此操作,或者由于涉及的复杂性(例如未对齐的峰),它可能不值得。 Modifying the data given above slightly highlights this issue well -修改上面给出的数据稍微突出了这个问题——

import pandas as pd
import altair as alt

X=[1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9]
V=[1,1,1,2,4,8,6,4,2,1,2,3,4,5,6,7,6,5,1,1,1,1,4,8,4,2,1,1,5,9,5,3,1,1,1,1]
key=['a', 'b', 'c', 'd']
K = [y for x in key for y in (x)*9]

demo = pd.DataFrame({'X': X, 'V': V, 'K': K})

# get the x and y positions for max values of the graph
demo.groupby('K').max()

# crate a new dataframe for the text, X column=idmax, Y column=cumulative ypos, K=key
demotext = pd.DataFrame([[idxmax, y, k] for y,k in zip(ypos.tolist(), key[::-1])],
                        columns=["X", "Y", "K"])


a = (alt.Chart(demo).mark_area()
        .encode(
                x='X:O',
                y='V:Q',
                color='K:N')
    )
t = (alt.Chart(demotext).mark_text()
        .encode(
                x='X:O',
                y='Y:Q',
                text='K:N'
))
a+t

在此处输入图像描述

I think the best and easiest way it to manually construct the data for text if you have a very convoluted graph -如果您有一个非常复杂的图表,我认为手动构建文本数据的最佳和最简单的方法 -

a = (alt.Chart(demo).mark_area()
        .encode(
                x='X:O',
                y='V:Q',
                color='K:N')
    )
t = (alt.Chart(p).mark_text()
        .encode(
                x='X:O',
                y='csum:Q',
                text='K:N'
))
a+t

Where p is -其中p是 -

    K   V   X   csum
0   a   8   6   18
1   b   7   7   7
2   c   8   6   4
3   d   9   3   4

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM