Geoshape#

The mark_geoshape represents an arbitrary shapes whose geometry is determined by specified spatial data.

Basic Map#

Its most convenient to use a GeoDataFrame as input. Here we load the Natural Earth dataset and create a basic map using the geoshape mark:

import altair as alt
from vega_datasets import data
import geopandas as gpd

fp = gpd.datasets.get_path('naturalearth_lowres')
gdf_ne = gpd.read_file(fp)  # shapefile

alt.Chart(gdf_ne).mark_geoshape()

In the example above, Altair applies a default blue color and uses a default map projection (equalEarth). We can customize the colors and boundary stroke widths using standard mark properties. Using the project method we can also define the map projection manually:

alt.Chart(gdf_ne).mark_geoshape(
    fill='lightgray', stroke='white', strokeWidth=0.5
).project(
    type='equalEarth'
)

Focus & Filtering#

By default Altair automatically adjusts the projection so that all the data fits within the width and height of the chart. Multiple approaches can be used to focus on specific regions of your spatial data.

The following examples show different approaches to focus on continental Africa:

  1. Filter the source data within your GeoDataFrame:

gdf_sel = gdf_ne[gdf_ne.continent == 'Africa']

alt.Chart(gdf_sel).mark_geoshape().project(
    type='equalEarth'
)
  1. Filter the source data using a transorm_filter:

alt.Chart(gdf_ne).mark_geoshape().project(
    type='equalEarth'
).transform_filter(
    alt.datum.continent == 'Africa'
)
  1. Specify projection parameters, such as scale (zoom level) and translate (panning):

alt.Chart(gdf_ne).mark_geoshape().project(
    type='equalEarth',
    scale=200,
    translate=[160, 160]  # lon, lat rotation
)

Cartesian coordinates#

The default projection of Altair is equalEarth. This default assumes that your geometries are in degrees and referenced by longitude and latitude values. Another widely used coordinate system for data visualization is the 2d cartesian coordinate system. This coordinate system does not take into account the curvature of the Earth.

In the following example the input geometry is not projected and is instead rendered directly in raw coordinates using the identity transformation. We have to define the reflectY as well since Canvas and SVG treats postive y as pointing down.

alt.Chart(gdf_sel).mark_geoshape().project(
    type='identity',
    reflectY=True
)

Mapping Polygons#

The following example maps the visual property of the name column using the color encoding.

alt.Chart(gdf_sel).mark_geoshape().encode(
    color='name:N'
).project(
    type='identity',
    reflectY=True
)

Since each country is represented by a (multi)polygon, one can separate the stroke and fill defintions as such:

alt.Chart(gdf_sel).mark_geoshape(
    stroke='white',
    strokeWidth=1.5
).encode(
    fill='name:N'
).project(
    type='identity',
    reflectY=True
)

Mapping Lines#

By default Altair assumes for mark_geoshape that the mark’s color is used for the fill color instead of the stroke color. This means that if your source data contain (multi)lines, you will have to explicitly define the filled value as False.

Compare:

gs_line = gpd.GeoSeries.from_wkt(['LINESTRING (0 0, 1 1, 0 2, 2 2, -1 1, 1 0)'])
alt.Chart(gs_line).mark_geoshape().project(
    type='identity',
    reflectY=True
)

With:

gs_line = gpd.GeoSeries.from_wkt(['LINESTRING (0 0, 1 1, 0 2, 2 2, -1 1, 1 0)'])
alt.Chart(gs_line).mark_geoshape(
    filled=False
).project(
    type='identity',
    reflectY=True
)

Using this approach one can also style Polygons as if they are Linestrings:

alt.Chart(gdf_sel).mark_geoshape(
    filled=False,
    strokeWidth=1.5
).encode(
    stroke='name:N'
).project(
    type='identity',
    reflectY=True
)

Mapping Points#

Points can be drawn when they are defined as Points within a GeoDataFrame using mark_geoshape. We first assign the centroids of Polygons as Point geometry and plot these:

gdf_centroid = gpd.GeoDataFrame(
    data=gdf_sel.drop('geometry', axis=1),
    geometry=gdf_sel.geometry.centroid
)

alt.Chart(gdf_centroid).mark_geoshape().project(
    type='identity',
    reflectY=True
)

But to use the size encoding for the Points you will need to use the mark_circle plus defining the latitude and longitude encoding channels.

gdf_centroid['lon'] = gdf_centroid['geometry'].x
gdf_centroid['lat'] = gdf_centroid['geometry'].y

alt.Chart(gdf_centroid).mark_circle().encode(
    latitude='lat:Q',
    longitude='lon:Q',
    size="pop_est:Q"
).project(
    type='identity',
    reflectY=True
)

You could skip the extra assingment to the lon and lat column in the GeoDataFrame and use the coordinates directly. We combine the chart with a basemap to bring some perspective to the points:

basemap = alt.Chart(gdf_sel).mark_geoshape(
    fill='lightgray', stroke='white', strokeWidth=0.5
)

bubbles = alt.Chart(gdf_centroid).mark_circle(
    stroke='black'
).encode(
    latitude='geometry.coordinates[1]:Q',
    longitude='geometry.coordinates[0]:Q',
    size="pop_est:Q"
)

(basemap + bubbles).project(
    type='identity',
    reflectY=True
)

Altair also contains expressions related to geographical features. One could for example define the centroids using a geoCentroid expression:

from altair.expr import datum, geoCentroid

bubbles = alt.Chart(gdf_sel).transform_calculate(
    centroid=geoCentroid(None, datum)
).mark_circle(
    stroke='black'
).encode(
    longitude='centroid[0]:Q',
    latitude='centroid[1]:Q',
    size="pop_est:Q"
)

(basemap + bubbles).project(
    type='identity', reflectY=True
)

Lookup datasets#

Sometimes your data is separated in two datasets. One DataFrame with the data and one GeoDataFrame with the geometries. In this case you can use the lookup transform to connect related information in the other dataset.

You can use the lookup transform in two directions.

  1. Use a GeoDataFrame with geometries as source and lookup related information in another DataFrame.

  2. Use a DataFrame as source and lookup related geometries in a GeoDataFrame.

Depending on your usecase one or the other is more favorable.

First show an example of the first approach. Here we lookup the field rate from the us_unemp DataFrame, where the us_counties GeoDataFrame is used as source:

import altair as alt
from vega_datasets import data
import geopandas as gpd

us_counties = gpd.read_file(data.us_10m.url, driver='TopoJSON', layer='counties')
us_unemp = data.unemployment()

alt.Chart(us_counties).mark_geoshape().transform_lookup(
    lookup='id',
    from_=alt.LookupData(data=us_unemp, key='id', fields=['rate'])
).encode(
    alt.Color('rate:Q')
).project(
    type='albersUsa'
)

Next, we show an example of the second approach. Here we lookup the geometries through the fields geometry and type from the us_counties GeoDataFrame, where the us_unemp DataFrame is used as source.

alt.Chart(us_unemp).mark_geoshape().transform_lookup(
    lookup='id',
    from_=alt.LookupData(data=us_counties, key='id', fields=['geometry', 'type'])
).encode(
    alt.Color('rate:Q')
).project(
    type='albersUsa'
)

Chloropleth Classification#

Choropleth maps provide an easy way to visualize how a variable varies across a geographic area or show the level of variability within a region.

Take for example the following example of unemployment statistics of 2018 of US counties (we define a utility function (classify() that we will use later again):

import altair as alt
from vega_datasets import data
import geopandas as gpd

def classify(scale_type, breaks=None, nice=False, title=None, size='small'):

    if size =='default':
        width=400
        height=300
    else:
        width=200
        height=150

    us_counties = gpd.read_file(data.us_10m.url, driver='TopoJSON', layer='counties')
    us_states = gpd.read_file(data.us_10m.url, driver='TopoJSON', layer='states')
    us_unemp = data.unemployment()

    if title is None:
        title=scale_type

    if 'threshold' in scale_type:
        scale = alt.Scale(type=scale_type, domain=breaks, scheme='turbo')
    else:
        scale = alt.Scale(type=scale_type, nice=nice, scheme='turbo')

    fill = alt.Fill(
        'rate:Q',
        scale=scale,
        legend=alt.Legend(direction='horizontal', orient='bottom', format='.1%')
    )

    distrib_square = alt.Chart(
        us_unemp,
        height=20,
        width=width
    ).mark_square(
        size=3,
        opacity=1
    ).encode(
        x=alt.X('rate:Q', title=None, axis=alt.Axis(format='.0%')),
        y=alt.Y('jitter:Q', title=None, axis=None),
        fill=fill
    ).transform_calculate(
        jitter='random()'
    )

    distrib_geoshape = alt.Chart(
        us_counties,
        width=width,
        height=height,
        title=title
    ).mark_geoshape().transform_lookup(
        lookup='id',
        from_=alt.LookupData(data=us_unemp, key='id', fields=['rate'])
    ).encode(
        fill=fill
    ).project(
        type='albersUsa'
    )

    states_geoshape = alt.Chart(
        us_states,
        width=width,
        height=height
    ).mark_geoshape(filled=False, stroke='white', strokeWidth=0.75).project(
        type='albersUsa'
    )

    return (distrib_geoshape + states_geoshape) & distrib_square

classify('linear', size='default')

We visualise the unemployment rate in percentage of 2018 with a linear scale range using a mark_geoshape() to present the spatial patterns on a map and a _jitter_ plot (using mark_square()) to visualise the distribution of the rate values. Each value/ county has defined an unique color. This gives a bit of insight, but often we like to group the distribution into classes.

By grouping values in classes, you can classify the dataset so all values/geometries in each class get assigned the same color.

Here we present a number of scale methods how Altair can be used: - _quantile_, this type will divide your dataset (domain) into intervals of similar sizes. Each class contains more or less the same number of values/geometries (equal counts). The scale definition will look as follow:

`python alt.Scale(type='quantile') `

  • _quantize_, this type will divide the extent of your dataset (range) in equal

intervals. Each class contains different number of values, but the step size is equal (equal range). The scale definition will look as follow:

`python alt.Scale(type='quantize') `

The quantize methode can also be used in combination with nice. This will “nice” the domain before applying quantization. As such:

`python alt.Scale(type='quantize', nice=True) `

  • _threshold_, this type will divide your dataset in separate classes by manually

specifying the cut values. Each class is separated by defined classes. The scale definition will look as follow:

`python alt.Scale(type='quantize', range=[0.05, 0.20]) `

This definition above will create 3 classes. One class with values below 0.05, one class with values from 0.05 to 0.20 and one class with values higher than 0.20.

So which method provides the optimal data classification for chloropleths maps? As usual, it depends. There is another popular method that aid in determining class breaks. This method will maximize the similarity of values in a class while maximizing the distance between the classes (natural breaks). The method is also known by as the Fisher-Jenks algorithm and is similar to _k_-Means in 1D: - By using the external Python package jenskpy we can derive these _optimim_ breaks as such:

`python >>> from jenkspy import JenksNaturalBreaks >>> jnb = JenksNaturalBreaks(5) >>> jnb.fit(us_unemp['rate']) >>> jnb.inner_breaks_ [0.061, 0.088, 0.116, 0.161] ` So when applying these different classification schemes to the county unemployment dataset, we get the following overview:

alt.concat(
    classify('linear'),
    classify('quantile', title=['quantile','equal counts']),
    classify('quantize', title=['quantize', 'equal range']),
    classify('quantize', nice=True, title=['quantize', 'equal range nice']),
    classify('threshold', breaks=[0.05, 0.20]),
    classify('threshold', breaks=[0.061, 0.088, 0.116, 0.161],
            title=['threshold Jenks','natural breaks']
    ),
    columns=3
)

Caveats:

  • For the type quantize and quantile scales we observe that the default number of

classes is 5. It is currently not possible to define a different number of classes in Altair in combination with a predefined color scheme. Track the following issue at the Vega-Lite repository: https://github.com/vega/vega-lite/issues/8127 - To define custom colors for each class, one should specify the domain and range. Where the range contains +1 values than the classes specified in the domain For example: alt.Scale(type=’threshold’, domain=[0.05, 0.20], range=[‘blue’,’white’,’red’]) In this blue is the class for all values below 0.05, white for all values between 0.05 and 0.20 and red for all values above 0.20. - The natural breaks method will determine the optimal class breaks given the required number of classes. But how many classes should one pick? One can investigate usage of goodness of variance fit (GVF), aka Jenks optimization method, to determine this.

Repeat a Map#

The RepeatChart pattern, accessible via the Chart.repeat() method provides a convenient interface for a particular type of horizontal or vertical concatenation of a multi-dimensional dataset.

In the following example we have a dataset referenced as source from which we use three columns defining the population, engineers and hurricanes of each US state.

The states is defined by making use of topo_feature() using url and feature as parameters. This is a convenience function for extracting features from a topojson url.

These variables we provide as list in the .repeat() operator, which we refer to within the color encoding as alt.repeat(‘row’)

import altair as alt
from vega_datasets import data

states = alt.topo_feature(data.us_10m.url, 'states')
source = data.population_engineers_hurricanes.url
variable_list = ['population', 'engineers', 'hurricanes']

alt.Chart(states).mark_geoshape(tooltip=True).encode(
    alt.Color(alt.repeat('row'), type='quantitative')
).transform_lookup(
    lookup='id',
    from_=alt.LookupData(source, 'id', variable_list)
).project(
    type='albersUsa'
).repeat(
    row=variable_list
).resolve_scale(
    color='independent'
)

Facet a Map#

The FacetChart pattern, accessible via the Chart.facet() method provides a convenient interface for a particular type of horizontal or vertical concatenation of a dataset where one field contain multiple variables.

Unfortuantely, the following open issue https://github.com/altair-viz/altair/issues/2369 will make the following not work for geographic visualization:

source = data.population_engineers_hurricanes().melt(id_vars=['state', 'id'])
us_states = gpd.read_file(data.us_10m.url, driver='TopoJSON', layer='states')
gdf_comb = gpd.GeoDataFrame(source.join(us_states, on='id', rsuffix='_y'))

alt.Chart(gdf_comb).mark_geoshape().encode(
    color=alt.Color('value:Q'),
    facet=alt.Facet('variable:N', columns=3)
).properties(
    width=200,
    height=200
).resolve_scale('independent')

For now, the following workaround can be adopted to facet a map, manually filter the data in pandas, and create a small multiples chart via concatenation. For example:

alt.concat(*(
    alt.Chart(gdf_comb[gdf_comb.variable == var], title=var).mark_geoshape().encode(
    color='value:Q',
    ).properties(
    width=200
    )
    for var in gdf_comb.variable.unique()
), columns=3
).resolve_scale(color='independent')

Interaction#

Often a map does not come alone, but is used in combination with another chart. Here we provide an example of an interactive visualization of a bar chart and a map.

The data shows the states of the US in combination with a bar chart showing the 15 most populous states.

import altair as alt
from vega_datasets import data
import geopandas as gpd

# load the data
us_states = gpd.read_file(data.us_10m.url, driver='TopoJSON', layer='states')
us_population = data.population_engineers_hurricanes()[['state', 'id', 'population']]

# define a pointer selection
click_state = alt.selection_point(fields=['state'])

# create a chloropleth map using a lookup transform
# define a condition on the opacity encoding depending on the selection
choropleth = alt.Chart(us_states).mark_geoshape().transform_lookup(
    lookup='id',
    from_=alt.LookupData(us_population, 'id', ['population', 'state'])
).encode(
    color='population:Q',
    opacity=alt.condition(click_state, alt.value(1), alt.value(0.2)),
    tooltip=['state:N', 'population:Q']
).project(type='albersUsa').add_parameter(click_state)

# create a bar chart with a similar condition on the opacity encoding.
bars = alt.Chart(
    us_population.nlargest(15, 'population'),
    title='Top 15 states by population').mark_bar(
).encode(
    x='population',
    opacity=alt.condition(click_state, alt.value(1), alt.value(0.2)),
    color='population',
    y=alt.Y('state', sort='-x')
).add_parameter(click_state)


choropleth & bars

Expression#

Altair expressions can be used within a geographical visualization. The following example visualize earthquakes on the globe using an orthographic projection. Where we can rotate the earth on a single-axis. (rotate0). The utility function :func:sphere is adopted to get a disk of the earth as background.

The earthquakes are displayed using a mark_geoshape and filtered once out of sight of the the visible part of the world.

An hover highlighting is added to get more insight of each earthquake.

import altair as alt
from vega_datasets import data
import geopandas as gpd

# load data
gdf_quakies = gpd.read_file(data.earthquakes.url, driver='GeoJSON')
gdf_world = gpd.read_file(data.world_110m.url, driver='TopoJSON')

# define parameters
range0 = alt.binding_range(min=-180, max=180, step=5)
rotate0 = alt.parameter(value=120, bind=range0, name='rotate0')
hover = alt.selection_point(on='mouseover', clear='mouseout')

# world disk
sphere = alt.Chart(alt.sphere()).mark_geoshape(
    fill='aliceblue',
    stroke='black',
    strokeWidth=1.5
)

# countries as shapes
world = alt.Chart(gdf_world).mark_geoshape(
    fill='mintcream',
    stroke='black',
    strokeWidth=0.35
)

# earthquakes as circles with fill for depth and size for magnitude
# the hover param is added on the mar_circle only
quakes = alt.Chart(gdf_quakies).mark_circle(
    opacity=0.35,
    tooltip=True,
    stroke='black'
).transform_calculate(
    lon="datum.geometry.coordinates[0]",
    lat="datum.geometry.coordinates[1]",
    depth="datum.geometry.coordinates[2]"
).transform_filter('''
    (rotate0 * -1) - 90 < datum.lon && datum.lon < (rotate0 * -1) + 90
    '''
).encode(
    longitude='lon:Q',
    latitude='lat:Q',
    strokeWidth=alt.condition(hover, alt.value(1, empty=False), alt.value(0)),
    size=alt.Size('mag:Q', scale=alt.Scale(type='pow', range=[1,1000], domain=[0,6], exponent=4)),
    fill=alt.Fill('depth:Q', scale=alt.Scale(scheme='lightorange', domain=[0,400]))
).add_parameter(hover)

# define projection and add the rotation param for all layers
comb = alt.layer(sphere, world, quakes).project(
    'orthographic',
    rotate=[90, 0, 0]
).add_parameter(rotate0)

# temporary changing params to top-level
# and defining the rotate reference expression on compiled VL directly
chart_vl = comb.to_dict()
chart_vl['params'] =  chart_vl['layer'][0].pop('params')
chart_vl['projection']['rotate'] = {'expr':'[rotate0, 0, 0]'}
alt.Chart().from_dict(chart_vl)

Geoshape Options#

Additional arguments to mark_geoshape() method are passed along to an associated MarkDef instance, which supports the following attributes:

Property

Type

Description

align

anyOf(Align, ExprRef)

The horizontal alignment of the text or ranged marks (area, bar, image, rect, rule). One of "left", "right", "center".

Note: Expression reference is not supported for range marks.

angle

anyOf(number, ExprRef)

aria

anyOf(boolean, ExprRef)

ariaRole

anyOf(string, ExprRef)

ariaRoleDescription

anyOf(string, ExprRef)

aspect

anyOf(boolean, ExprRef)

bandSize

number

The width of the ticks.

Default value: 3/4 of step (width step for horizontal ticks and height step for vertical ticks).

baseline

anyOf(TextBaseline, ExprRef)

For text marks, the vertical text baseline. One of "alphabetic" (default), "top", "middle", "bottom", "line-top", "line-bottom", or an expression reference that provides one of the valid values. The "line-top" and "line-bottom" values operate similarly to "top" and "bottom", but are calculated relative to the lineHeight rather than fontSize alone.

For range marks, the vertical alignment of the marks. One of "top", "middle", "bottom".

Note: Expression reference is not supported for range marks.

binSpacing

number

Offset between bars for binned field. The ideal value for this is either 0 (preferred by statisticians) or 1 (Vega-Lite default, D3 example style).

Default value: 1

blend

anyOf(Blend, ExprRef)

clip

boolean

Whether a mark be clipped to the enclosing group’s width and height.

color

anyOf(Color, Gradient, ExprRef)

Default color.

Default value: "#4682b4"

Note:

  • This property cannot be used in a style config.

  • The fill and stroke properties have higher precedence than color and will override color.

continuousBandSize

number

The default size of the bars on continuous scales.

Default value: 5

cornerRadius

anyOf(number, ExprRef)

cornerRadiusBottomLeft

anyOf(number, ExprRef)

cornerRadiusBottomRight

anyOf(number, ExprRef)

cornerRadiusEnd

anyOf(number, ExprRef)

  • For vertical bars, top-left and top-right corner radius.

  • For horizontal bars, top-right and bottom-right corner radius.

cornerRadiusTopLeft

anyOf(number, ExprRef)

cornerRadiusTopRight

anyOf(number, ExprRef)

cursor

anyOf(Cursor, ExprRef)

description

anyOf(string, ExprRef)

dir

anyOf(TextDirection, ExprRef)

discreteBandSize

anyOf(number, RelativeBandSize)

The default size of the bars with discrete dimensions. If unspecified, the default size is step-2, which provides 2 pixel offset between bars.

dx

anyOf(number, ExprRef)

dy

anyOf(number, ExprRef)

ellipsis

anyOf(string, ExprRef)

fill

anyOf(Color, Gradient, null, ExprRef)

Default fill color. This property has higher precedence than config.color. Set to null to remove fill.

Default value: (None)

fillOpacity

anyOf(number, ExprRef)

filled

boolean

Whether the mark’s color should be used as fill color instead of stroke color.

Default value: false for all point, line, and rule marks as well as geoshape marks for graticule data sources; otherwise, true.

Note: This property cannot be used in a style config.

font

anyOf(string, ExprRef)

fontSize

anyOf(number, ExprRef)

fontStyle

anyOf(FontStyle, ExprRef)

fontWeight

anyOf(FontWeight, ExprRef)

height

anyOf(number, ExprRef, RelativeBandSize)

Height of the marks. One of:

  • A number representing a fixed pixel height.

  • A relative band size definition. For example, {band: 0.5} represents half of the band

href

anyOf(URI, ExprRef)

innerRadius

anyOf(number, ExprRef)

The inner radius in pixels of arc marks. innerRadius is an alias for radius2.

Default value: 0

interpolate

anyOf(Interpolate, ExprRef)

invalid

[‘filter’, None]

Defines how Vega-Lite should handle marks for invalid values (null and NaN).

  • If set to "filter" (default), all data items with null values will be skipped (for line, trail, and area marks) or filtered (for other marks).

  • If null, all data items are included. In this case, invalid values will be interpreted as zeroes.

limit

anyOf(number, ExprRef)

line

anyOf(boolean, OverlayMarkDef)

A flag for overlaying line on top of area marks, or an object defining the properties of the overlayed lines.

  • If this value is an empty object ({}) or true, lines with default properties will be used.

  • If this value is false, no lines would be automatically added to area marks.

Default value: false.

lineBreak

anyOf(string, ExprRef)

lineHeight

anyOf(number, ExprRef)

opacity

anyOf(number, ExprRef)

The overall opacity (value between [0,1]).

Default value: 0.7 for non-aggregate plots with point, tick, circle, or square marks or layered bar charts and 1 otherwise.

order

[null, boolean]

For line and trail marks, this order property can be set to null or false to make the lines use the original order in the data sources.

orient

Orientation

The orientation of a non-stacked bar, tick, area, and line charts. The value is either horizontal (default) or vertical.

  • For bar, rule and tick, this determines whether the size of the bar and tick should be applied to x or y dimension.

  • For area, this property determines the orient property of the Vega output.

  • For line and trail marks, this property determines the sort order of the points in the line if config.sortLineBy is not specified. For stacked charts, this is always determined by the orientation of the stack; therefore explicitly specified value will be ignored.

outerRadius

anyOf(number, ExprRef)

The outer radius in pixels of arc marks. outerRadius is an alias for radius.

Default value: 0

padAngle

anyOf(number, ExprRef)

point

anyOf(boolean, OverlayMarkDef, string)

A flag for overlaying points on top of line or area marks, or an object defining the properties of the overlayed points.

  • If this property is "transparent", transparent points will be used (for enhancing tooltips and selections).

  • If this property is an empty object ({}) or true, filled points with default properties will be used.

  • If this property is false, no points would be automatically added to line or area marks.

Default value: false.

radius

anyOf(number, ExprRef)

For arc mark, the primary (outer) radius in pixels.

For text marks, polar coordinate radial offset, in pixels, of the text from the origin determined by the x and y properties.

Default value: min(plot_width, plot_height)/2

radius2

anyOf(number, ExprRef)

The secondary (inner) radius in pixels of arc marks.

Default value: 0

radius2Offset

anyOf(number, ExprRef)

Offset for radius2.

radiusOffset

anyOf(number, ExprRef)

Offset for radius.

shape

anyOf(anyOf(SymbolShape, string), ExprRef)

size

anyOf(number, ExprRef)

Default size for marks.

  • For point/circle/square, this represents the pixel area of the marks. Note that this value sets the area of the symbol; the side lengths will increase with the square root of this value.

  • For bar, this represents the band size of the bar, in pixels.

  • For text, this represents the font size, in pixels.

Default value:

  • 30 for point, circle, square marks; width/height’s step

  • 2 for bar marks with discrete dimensions;

  • 5 for bar marks with continuous dimensions;

  • 11 for text marks.

smooth

anyOf(boolean, ExprRef)

stroke

anyOf(Color, Gradient, null, ExprRef)

Default stroke color. This property has higher precedence than config.color. Set to null to remove stroke.

Default value: (None)

strokeCap

anyOf(StrokeCap, ExprRef)

strokeDash

anyOf(array(number), ExprRef)

strokeDashOffset

anyOf(number, ExprRef)

strokeJoin

anyOf(StrokeJoin, ExprRef)

strokeMiterLimit

anyOf(number, ExprRef)

strokeOffset

anyOf(number, ExprRef)

strokeOpacity

anyOf(number, ExprRef)

strokeWidth

anyOf(number, ExprRef)

style

anyOf(string, array(string))

A string or array of strings indicating the name of custom styles to apply to the mark. A style is a named collection of mark property defaults defined within the style configuration. If style is an array, later styles will override earlier styles. Any mark properties explicitly defined within the encoding will override a style default.

Default value: The mark’s name. For example, a bar mark will have style "bar" by default. Note: Any specified style will augment the default style. For example, a bar mark with "style": "foo" will receive from config.style.bar and config.style.foo (the specified style "foo" has higher precedence).

tension

anyOf(number, ExprRef)

text

anyOf(Text, ExprRef)

theta

anyOf(number, ExprRef)

  • For arc marks, the arc length in radians if theta2 is not specified, otherwise the start arc angle. (A value of 0 indicates up or “north”, increasing values proceed clockwise.)

  • For text marks, polar coordinate angle in radians.

theta2

anyOf(number, ExprRef)

The end angle of arc marks in radians. A value of 0 indicates up or “north”, increasing values proceed clockwise.

theta2Offset

anyOf(number, ExprRef)

Offset for theta2.

thetaOffset

anyOf(number, ExprRef)

Offset for theta.

thickness

number

Thickness of the tick mark.

Default value: 1

timeUnitBandPosition

number

Default relative band position for a time unit. If set to 0, the marks will be positioned at the beginning of the time unit band step. If set to 0.5, the marks will be positioned in the middle of the time unit band step.

timeUnitBandSize

number

Default relative band size for a time unit. If set to 1, the bandwidth of the marks will be equal to the time unit band step. If set to 0.5, bandwidth of the marks will be half of the time unit band step.

tooltip

anyOf(number, string, boolean, TooltipContent, ExprRef, null)

The tooltip text string to show upon mouse hover or an object defining which fields should the tooltip be derived from.

  • If tooltip is true or {"content": "encoding"}, then all fields from encoding will be used.

  • If tooltip is {"content": "data"}, then all fields that appear in the highlighted data point will be used.

  • If set to null or false, then no tooltip will be used.

See the tooltip documentation for a detailed discussion about tooltip in Vega-Lite.

Default value: null

type

Mark

The mark type. This could a primitive mark type (one of "bar", "circle", "square", "tick", "line", "area", "point", "geoshape", "rule", and "text") or a composite mark type ("boxplot", "errorband", "errorbar").

url

anyOf(URI, ExprRef)

width

anyOf(number, ExprRef, RelativeBandSize)

Width of the marks. One of:

  • A number representing a fixed pixel width.

  • A relative band size definition. For example, {band: 0.5} represents half of the band.

x

anyOf(number, string, ExprRef)

X coordinates of the marks, or width of horizontal "bar" and "area" without specified x2 or width.

The value of this channel can be a number or a string "width" for the width of the plot.

x2

anyOf(number, string, ExprRef)

X2 coordinates for ranged "area", "bar", "rect", and "rule".

The value of this channel can be a number or a string "width" for the width of the plot.

x2Offset

anyOf(number, ExprRef)

Offset for x2-position.

xOffset

anyOf(number, ExprRef)

Offset for x-position.

y

anyOf(number, string, ExprRef)

Y coordinates of the marks, or height of vertical "bar" and "area" without specified y2 or height.

The value of this channel can be a number or a string "height" for the height of the plot.

y2

anyOf(number, string, ExprRef)

Y2 coordinates for ranged "area", "bar", "rect", and "rule".

The value of this channel can be a number or a string "height" for the height of the plot.

y2Offset

anyOf(number, ExprRef)

Offset for y2-position.

yOffset

anyOf(number, ExprRef)

Offset for y-position.

Marks can also be configured globally using chart-level configurations; see Mark and Mark Style Configuration for details.