如何使用Altair创建嵌套的分组条形图? -添加了样本数据

时间:2018-11-28 10:16:10

标签: python altair

<table class="table table-bordered table-hover table-condensed">
<thead><tr><th title="Field #1">year</th>
<th title="Field #2">primary_type</th>
<th title="Field #3">Number_of_Incidents</th>
<th title="Field #4">number_of_arrests</th>
<th title="Field #5">percent_arrest</th>
<th title="Field #6">rank</th>
</tr></thead>
<tbody><tr>
<td align="right">2018</td>
<td>THEFT</td>
<td align="right">57330</td>
<td align="right">5503</td>
<td align="right">9.6</td>
<td align="right">1</td>
</tr>
<tr>
<td align="right">2018</td>
<td>BATTERY</td>
<td align="right">44667</td>
<td align="right">8886</td>
<td align="right">19.89</td>
<td align="right">2</td>
</tr>
<tr>
<td align="right">2018</td>
<td>CRIMINAL DAMAGE</td>
<td align="right">24889</td>
<td align="right">1498</td>
<td align="right">6.02</td>
<td align="right">3</td>
</tr>
<tr>
<td align="right">2018</td>
<td>ASSAULT</td>
<td align="right">18229</td>
<td align="right">2931</td>
<td align="right">16.08</td>
<td align="right">4</td>
</tr>
<tr>
<td align="right">2018</td>
<td>DECEPTIVE PRACTICE</td>
<td align="right">15879</td>
<td align="right">713</td>
<td align="right">4.49</td>
<td align="right">5</td>
</tr>
<tr>
<td align="right">2017</td>
<td>THEFT</td>
<td align="right">64334</td>
<td align="right">6459</td>
<td align="right">10.04</td>
<td align="right">1</td>
</tr>
<tr>
<td align="right">2017</td>
<td>BATTERY</td>
<td align="right">49213</td>
<td align="right">10060</td>
<td align="right">20.44</td>
<td align="right">2</td>
</tr>
<tr>
<td align="right">2017</td>
<td>CRIMINAL DAMAGE</td>
<td align="right">29040</td>
<td align="right">1747</td>
<td align="right">6.02</td>
<td align="right">3</td>
</tr>
<tr>
<td align="right">2017</td>
<td>ASSAULT</td>
<td align="right">19298</td>
<td align="right">3455</td>
<td align="right">17.9</td>
<td align="right">4</td>
</tr>
<tr>
<td align="right">2017</td>
<td>DECEPTIVE PRACTICE</td>
<td align="right">18816</td>
<td align="right">805</td>
<td align="right">4.28</td>
<td align="right">5</td>
</tr>
<tr>
<td align="right">2016</td>
<td>THEFT</td>
<td align="right">61600</td>
<td align="right">6518</td>
<td align="right">10.58</td>
<td align="right">1</td>
</tr>
<tr>
<td align="right">2016</td>
<td>BATTERY</td>
<td align="right">50292</td>
<td align="right">10328</td>
<td align="right">20.54</td>
<td align="right">2</td>
</tr>
<tr>
<td align="right">2016</td>
<td>CRIMINAL DAMAGE</td>
<td align="right">31018</td>
<td align="right">1668</td>
<td align="right">5.38</td>
<td align="right">3</td>
</tr>
<tr>
<td align="right">2016</td>
<td>ASSAULT</td>
<td align="right">18738</td>
<td align="right">3490</td>
<td align="right">18.63</td>
<td align="right">4</td>
</tr>
<tr>
<td align="right">2016</td>
<td>DECEPTIVE PRACTICE</td>
<td align="right">18733</td>
<td align="right">815</td>
<td align="right">4.35</td>
<td align="right">5</td>
</tr>
<tr>
<td align="right">2015</td>
<td>THEFT</td>
<td align="right">57335</td>
<td align="right">6771</td>
<td align="right">11.81</td>
<td align="right">1</td>
</tr>
<tr>
<td align="right">2015</td>
<td>BATTERY</td>
<td align="right">48918</td>
<td align="right">11558</td>
<td align="right">23.63</td>
<td align="right">2</td>
</tr>
<tr>
<td align="right">2015</td>
<td>CRIMINAL DAMAGE</td>
<td align="right">28675</td>
<td align="right">1835</td>
<td align="right">6.4</td>
<td align="right">3</td>
</tr>
<tr>
<td align="right">2015</td>
<td>NARCOTICS</td>
<td align="right">23883</td>
<td align="right">23875</td>
<td align="right">99.97</td>
<td align="right">4</td>
</tr>
<tr>
<td align="right">2015</td>
<td>OTHER OFFENSE</td>
<td align="right">17552</td>
<td align="right">4795</td>
<td align="right">27.32</td>
<td align="right">5</td>
</tr>
<tr>
<td align="right">2014</td>
<td>THEFT</td>
<td align="right">61561</td>
<td align="right">7415</td>
<td align="right">12.04</td>
<td align="right">1</td>
</tr>
<tr>
<td align="right">2014</td>
<td>BATTERY</td>
<td align="right">49447</td>
<td align="right">12517</td>
<td align="right">25.31</td>
<td align="right">2</td>
</tr>
<tr>
<td align="right">2014</td>
<td>NARCOTICS</td>
<td align="right">29116</td>
<td align="right">29000</td>
<td align="right">99.6</td>
<td align="right">3</td>
</tr>
<tr>
<td align="right">2014</td>
<td>CRIMINAL DAMAGE</td>
<td align="right">27798</td>
<td align="right">2095</td>
<td align="right">7.54</td>
<td align="right">4</td>
</tr>
<tr>
<td align="right">2014</td>
<td>OTHER OFFENSE</td>
<td align="right">16979</td>
<td align="right">4159</td>
<td align="right">24.49</td>
<td align="right">5</td>
</tr>
<tr>
<td align="right">2013</td>
<td>THEFT</td>
<td align="right">71530</td>
<td align="right">7727</td>
<td align="right">10.8</td>
<td align="right">1</td>
</tr>
<tr>
<td align="right">2013</td>
<td>BATTERY</td>
<td align="right">54002</td>
<td align="right">12927</td>
<td align="right">23.94</td>
<td align="right">2</td>
</tr>
<tr>
<td align="right">2013</td>
<td>NARCOTICS</td>
<td align="right">34127</td>
<td align="right">33819</td>
<td align="right">99.1</td>
<td align="right">3</td>
</tr>
<tr>
<td align="right">2013</td>
<td>CRIMINAL DAMAGE</td>
<td align="right">30853</td>
<td align="right">2107</td>
<td align="right">6.83</td>
<td align="right">4</td>
</tr>
<tr>
<td align="right">2013</td>
<td>OTHER OFFENSE</td>
<td align="right">17993</td>
<td align="right">3400</td>
<td align="right">18.9</td>
<td align="right">5</td>
</tr>
</tbody></table>

我有一个独特的处境。在我的数据中,我有年份,每年中有5个类别,它是对应的计数。我能够创建对应年份的这5个类别的堆叠条形图。但是,我想在我的x轴上每年显示5个相邻的条形图。对于y轴,每个条形应该显示一个对应的总数。

这是我当前的视区和代码:

import altair as alt


base = alt.Chart(q13a).encode(
alt.X('year:O',
    axis=alt.Axis(format='%b', title='Year'),
    scale=alt.Scale(zero=False)
),
tooltip = ['year']
)
bar = base.mark_bar().encode(
alt.Y('sum(Number_of_Incidents)',
    axis=alt.Axis(title='sum(Number_of_Incidents)'))
,color=alt.Color('primary_type')
#tooltip = ['primary_type']
)
line =  base.mark_line(color='red').encode(
#y='No_of_repos',
alt.Y('percent_arrest',
    axis=alt.Axis(title='percent_arrest')),
)
alt.layer(
bar
).resolve_scale(
y='independent'
).properties(
height=500,
width=1200
)

enter image description here

我的问题是,如何在x轴上每年创建5条相邻的条而不是堆叠的条?

谢谢您的帮助。

2 个答案:

答案 0 :(得分:2)

做并排条的唯一方法是在x编码旁边使用列编码。您可以从Altair的示例画廊中按照分组的条形图示例进行操作:https://altair-viz.github.io/gallery/grouped_bar_chart.html

您的数据结果将如下所示:

import altair as alt
import pandas as pd
import numpy as np

q13a = pd.DataFrame({
    'year': np.random.randint(2000, 2018, 100),
    'Number_of_Incidents': np.random.randint(0, 20, 100),
    'percent_arrest': np.random.rand(100),
    'primary_type': np.random.choice(['a', 'b', 'c', 'd', 'e'], 100)
})

alt.Chart(q13a).mark_bar().encode(
    x=alt.X('primary_type', scale=alt.Scale(rangeStep=8), title=None),
    y=alt.Y('sum(Number_of_Incidents)', title='sum(Number_of_Incidents)'),
    color='primary_type',
    column='year',
    tooltip=['year']
).configure_view(
    stroke='transparent'
)

enter image description here

答案 1 :(得分:1)

@jakevdp已经回答了,但是为了回答您的最后一个问题(即使您有几个问题也要问几个问题),您也可以使用alt.EncodingSortField对这些条进行排序。

import altair as alt

alt.Chart(q13a).mark_bar().encode(
    x=alt.X('primary_type:N', 
            scale=alt.Scale(rangeStep=8), 
            axis=None,
            sort=alt.EncodingSortField(field='Number_of_Incident', 
                                       op='sum', 
                                       order='ascending')
           ),
    y=alt.Y('sum(Number_of_Incidents):Q', title='sum(Number_of_Incidents)'),
    color='primary_type:N',
    tooltip=['primary_type:N', 
             'year:O', 
             alt.Tooltip('sum(Number_of_Incidents):Q',
                         title='Number of incidents')
            ]
).facet(
    column=alt.Column('year:O', 
                      header=alt.Header(title=None)),
).resolve_scale(
    x='independent'
).configure_view(
    stroke='transparent'
)

altair-sorted-grouped-bar-chart


数据

import pandas as pd
from io import StringIO

q13a = pd.read_table(StringIO("""year   primary_type    Number_of_Incidents number_of_arrests   percent_arrest  rank
2018    THEFT   57330   5503    9.6     1
2018    BATTERY     44667   8886    19.89   2
2018    CRIMINAL DAMAGE     24889   1498    6.02    3
2018    ASSAULT     18229   2931    16.08   4
2018    DECEPTIVE PRACTICE  15879   713     4.49    5
2017    THEFT   64334   6459    10.04   1
2017    BATTERY     49213   10060   20.44   2
2017    CRIMINAL DAMAGE     29040   1747    6.02    3
2017    ASSAULT     19298   3455    17.9    4
2017    DECEPTIVE PRACTICE  18816   805     4.28    5
2016    THEFT   61600   6518    10.58   1
2016    BATTERY     50292   10328   20.54   2
2016    CRIMINAL DAMAGE     31018   1668    5.38    3
2016    ASSAULT     18738   3490    18.63   4
2016    DECEPTIVE PRACTICE  18733   815     4.35    5
2015    THEFT   57335   6771    11.81   1
2015    BATTERY     48918   11558   23.63   2
2015    CRIMINAL DAMAGE     28675   1835    6.4     3
2015    NARCOTICS   23883   23875   99.97   4
2015    OTHER OFFENSE   17552   4795    27.32   5
2014    THEFT   61561   7415    12.04   1
2014    BATTERY     49447   12517   25.31   2
2014    NARCOTICS   29116   29000   99.6    3
2014    CRIMINAL DAMAGE     27798   2095    7.54    4
2014    OTHER OFFENSE   16979   4159    24.49   5
2013    THEFT   71530   7727    10.8    1
2013    BATTERY     54002   12927   23.94   2
2013    NARCOTICS   34127   33819   99.1    3
2013    CRIMINAL DAMAGE     30853   2107    6.83    4
2013    OTHER OFFENSE   17993   3400    18.9    5"""))

reprexpy package

创建于2018-11-28