Component tag
<vgg-map>
Description
The Map component is used to tap into the local data scope
and render one of each of its direct child components for each row in the dataset.
In this sense, it is similar to using v-for. But it has some advantages over
using v-for:
The Map component has access to the domains of the data within the data scope in which it is located. It also has access to the extents of the coordinate system in which it is located. With this information, it can easily calculate appropriate coordinates for its child components.
It enables a concise syntax on its child components that can be used to quickly map data values to aesthetic values- for example, categories to colors.
Props
| Prop | Required | Types | Default | Description |
|---|---|---|---|---|
| unit | false | String | 'row' | What to loop over- by default rows, but can also be set to 'dataframe' |
For more information on how to use the unit prop, see
Mapping an entire dataframe.
Usage
Mappable components and props
The Map component can only be used to map mappable components. Mappable components are all Marks, all Glyphs, all Guides, and the Section component.
When placed within vgg-map tags, the mapping object
syntax will be enabled on all mappable props of the mappable components.
While many mappable props will work in similar ways, there are some differences
based on what type of prop is being mapped. For example, some props allow you to
use positioners, others scales, and others just getters. Make sure
to check the documentation of the components you want to map to, to see
which syntaxes are allowed for which types of props.
The mapping object
{
val: ...,
band: ...,
scale: ...,
scaleGeo: ...
}
| Property | Types | Description |
|---|---|---|
| val | [Number, String, Date, Object, Array] | Anything that could be passed to a prop directly |
| band | [String, Array, Object] | Column name, domain boundaries or scaling options object |
| scale | [String, Array, Object] | Column name, domain boundaries or scaling options object |
| scaleGeo | Object | Options object for scaling geographic coordinates |
In any case where scale or scaleGeo is used, val must also be specified.
val can also be used alone, as the examples below will illustrate. band
is used to calculate widths and heights and can only be used in w and h props.
For more information, see the scaling documentation.
Basic example using val and scale
One way to create a scatterplot using some dummy data and the Map component is
using the mapping object syntax with both val and scale:
<vgg-graphic
:width="500"
:height="500"
:data="{
a: [1, 2, 5, 3, 4],
b: [2, 7, 9, 10, 9],
c: ['apple', 'apple', 'banana', 'banana', 'apple']
}"
>
<vgg-map v-slot="{ row }">
<vgg-point
:x="{ val: row.a, scale: 'a' }"
:y="{ val: row.b, scale: 'b' }"
:fill="{ val: row.c, scale: 'c' }"
/>
</vgg-map>
</vgg-graphic>
Under the hood, the following is happening:
The domains for the data in the columns
a,bandcare calculated. These are respectively[1, 5],[2, 10]and['apple', 'banana']. When the data is in string format (or is 'categorical', in statistical terminology), the domain will be an array of all the unique values.The extents or 'ranges' of the local coordinate system are determined. In this case, the range of the x-dimension is
[0, 500], and the range of the y-dimension is[0, 500]too.Using this information, three scaling functions are generated: one to scale the data in column
ato the coordinates in the x-dimension, one to scale the data in columnbto the coordinates in the y-dimension, and one to map the data in columncto a set of colors.The values in the columns
a,bandcare mapped to the propsx,yandfillof thevgg-pointMark in two steps. First, the destructuring of the scope inv-slotprovides access to each row in the dataset. The data values contained in that row are mapped to the props of thevgg-pointusing thevalkey. Second, before being passed as a prop, the data values are transformed using the scale functions generated in step 3.
The Map component's scoped slot
The Map component utilises Vue's
scoped slots.
The way vue-gg uses scoped slots might seem a bit puzzling at first, but using
vgg-map with v-slot actually quite similar to using Vue's native v-for:
<!-- Using v-for -->
<vgg-point
v-for="(row, i) in data"
:x="row.a"
:y="row.b"
/>
<!-- Using vgg-map -->
<vgg-map v-slot="{ row, i }">
<vgg-point
:x="row.a"
:y="row.b"
/>
</vgg-map>
Besides the current row and the current row index i, the scope also provides
access to the previous and next rows through prevRow and nextRow. However,
when using prevRow and nextRow, be aware of the fact that prevRow will be
undefined for the first row, and nextRow will be undefined for the last row.
When using unit="dataframe", only dataframe will be available in the scope-
see Mapping an entire dataframe.
When to use scale
Sometimes, the data in a column will already be in the right format, and scaling
won't be necessary. This is the case when you have, for example, a column of
colors, and you just want to use the color directly. In this situation, you will
want to use val, but not scale. To return to the previous example:
<vgg-graphic
:width="500"
:height="500"
:data="{
a: [1, 2, 5, 3, 4],
b: [2, 7, 9, 10, 9],
c: ['red', 'red', 'blue', 'blue', 'red']
}"
>
<vgg-map v-slot="{ row }">
<vgg-point
:x="{ val: row.a, scale: 'a' }"
:y="{ val: row.b, scale: 'b' }"
:fill="{ val: row.c }"
/>
</vgg-map>
</vgg-graphic>
Leaving out scale is common when working with the Section component.
The Section component allows you to specify a local coordinate system. This
coordinate system can be defined as the domains of the columns in your dataset.
See the documentation of the Section component for more information on this topic.
To create the same scatterplot again, but using the local Section coordinate
system:
<vgg-graphic
:width="500"
:height="500"
:data="{
a: [1, 2, 5, 3, 4],
b: [2, 7, 9, 10, 9],
c: ['apple', 'apple', 'banana', 'banana', 'apple']
}"
>
<vgg-section
:x1="0"
:x2="500"
:y1="0"
:y2="500"
:scale-x="'a'"
:scale-y="'b'"
>
<vgg-map v-slot="{ row }">
<vgg-point
:x="{ val: row.a }"
:y="{ val: row.b }"
:fill="{ val: row.c, scale: 'c' }"
/>
</vgg-map>
</vgg-section>
</vgg-graphic>
Using band
// TODO
Using scaleGeo
TODO
Mapping an entire dataframe
In the examples above, vgg-map maps one row in the dataframe to one mark:
the vgg-point. But for many other graphics, like line graphs, the 'one mark per
row' relation does not hold. Where with the vgg-point mark you just give one value
to the :x prop, the vgg-multi-line expects a whole Array of values. So,
to draw a single vgg-multi-line with the data used in the examples above,
we need to map an entire dataframe to a single mark:
<vgg-data :data="{ a: [1, 2, 5, 3, 4], b: [2, 7, 9, 10, 9], }">
<vgg-map
v-slot="{ dataframe }"
unit="dataframe"
>
<vgg-multi-line
:x="{ val: dataframe.a, scale: 'a' }"
:y="{ val: dataframe.b, scale: 'b' }"
/>
</vgg-map>
</vgg-data>
Note that the scope object now only has a dataframe key.