Search code examples
javascriptpythonjsonchartsaltair

Display text on bubble maps and dynamic re-scale for y-axis


I am currently trying to use Altair package in Python to plot charts, and I have two questions that I am unable to figure out:

  1. Is there an easy way to display a text on each circle in the below map when using mark_circle().encode() method?
  2. How to dynamically scale the vertical of a chart when two of them are placed on top of each other, so that the chart on the bottom has its x-axis labels displayed properly (see the color)?

Sample Data (market.json file)

[{"name":"X1, A1","type":"Small \/ City","lat":39.4,"lon":-76.3,"supply":1234,"rev":107.52},{"name":"X2, A2","type":"Small \/ City","lat":32.4,"lon":-99.5,"supply":1235.0,"rev":123},{"name":"X3, A3","type":"Mid City","lat":41,"lon":-81.2,"supply":7891,"rev":103.73},{"name":"X4, A4","type":"Rural \/Twin","lat":34.35,"lon":-87.3,"supply":6965.0,"rev":123.2},{"name":"X5, A5","type":"Rural \/Twin ","lat":31.23,"lon":-86.24,"supply":5617.2,"rev":123.87},{"name":"X6, A6","type":"Rural \/Twin","lat":61.27,"lon":-150.12,"supply":5182.0,"rev":128.3}]

Sample Code for 1st Figure

from vega_datasets import data

mkt = pd.read_json(market.json')
mkt_list = mkt['name'].unique().tolist()

# define selections
select_box = alt.binding_select(options=mkt_list, name='Make')
mkt_sel = alt.selection_single(fields=['name'], empty='none', bind=select_box,
                                    init={'name': 'X1, A1'})

regions = alt.topo_feature(data.us_10m.market.json, feature="states")
background = alt.Chart(regions).mark_geoshape(
    fill="#deebf7",
    stroke="white"
).project("albersUsa")

map = alt.Chart(mkt).mark_circle().encode(
    lat="lat:Q",
    lon="lon:Q",
    color=alt.Color('rev:Q', title='Rev',
                    scale=alt.Scale(scheme='blues', reverse=True)),
    size=alt.Size('supply:Q', title='Supply'),
    tooltip=[
        alt.Tooltip('name:N', title='Name'),
        alt.Tooltip('type:N', title='Type'),
        alt.Tooltip('rev:Q', format=".2f", title='Rev')
    ]
).add_selection(
    mkt_selector
).properties(
    width=200,
    height=100,
    title="Sample Map",
  )

)
country_map = alt.layer(background, map).resolve_legend(
        color="independent",
        size="independent"
        )

Sample Output

Country Map

enter image description here


Solution

  • You can use mark_text():

    from io import StringIO
    import pandas as pd
    from vega_datasets import data
    import altair as alt
    
    
    mkt = pd.read_json(
        StringIO("""[{"name":"X1, A1","type":"Small \/ City","lat":39.4,"lon":-76.3,"supply":1234,"rev":107.52},{"name":"X2, A2","type":"Small \/ City","lat":32.4,"lon":-99.5,"supply":1235.0,"rev":123},{"name":"X3, A3","type":"Mid City","lat":41,"lon":-81.2,"supply":7891,"rev":103.73},{"name":"X4, A4","type":"Rural \/Twin","lat":34.35,"lon":-87.3,"supply":6965.0,"rev":123.2},{"name":"X5, A5","type":"Rural \/Twin ","lat":31.23,"lon":-86.24,"supply":5617.2,"rev":123.87},{"name":"X6, A6","type":"Rural \/Twin","lat":61.27,"lon":-150.12,"supply":5182.0,"rev":128.3}]""")
    )
    mkt_list = mkt['name'].unique().tolist()
    
    regions = alt.topo_feature(data.us_10m.url, feature="states")
    background = alt.Chart(regions).mark_geoshape(
        fill="#deebf7",
        stroke="white"
    ).project("albersUsa")
    
    mkt_map = alt.Chart(mkt).mark_circle().encode(
        latitude="lat:Q",
        longitude="lon:Q",
        color=alt.Color('rev:Q', title='Rev',
                        scale=alt.Scale(scheme='blues', reverse=True)),
        size=alt.Size('supply:Q', title='Supply'),
        tooltip=[
            alt.Tooltip('name:N', title='Name'),
            alt.Tooltip('type:N', title='Type'),
            alt.Tooltip('rev:Q', format=".2f", title='Rev')
        ]
    ).properties(
        title="Sample Map",
    )
    
    background + mkt_map + mkt_map.mark_text().encode(
        size=alt.Size(),
        text='supply:Q',
        color=alt.value('black')
    )
    

    enter image description here