-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #56 from smplrspace/feat/pt-970/heatmaps
[PT-970] heatmaps
- Loading branch information
Showing
15 changed files
with
490 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"label": "Color", | ||
"position": 3 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- | ||
sidebar_position: 1 | ||
sidebar_label: Overview | ||
slug: overview | ||
--- | ||
|
||
# Working with colors on floor plans | ||
|
||
One of the core usage for Smplrspace is data visualization. As such, good utilization of color theory is an advantage to create a great user experience. With the `Color` class, we wrap the knowledge we collected through years of building visualizations to help you get going quickly. | ||
|
||
## A little context | ||
|
||
A fundamental in our approach, not with visualization at large, but specifically with visualization **on a floor plan**, is that you're doing spatial data visualization. This opens the door to bringing in knowledge from the well researched areas of cartography and geospatial data visualization. One of the most respected names in the industry is [Dr. Cynthia Brewer](https://en.wikipedia.org/wiki/Cynthia_Brewer), American cartographer, who studied the psychological perception of colors used in infographics on maps, and more specifically on [choropleth maps](https://en.wikipedia.org/wiki/Choropleth_map). Her online tool, [ColorBrewer](https://colorbrewer2.org) is where we extracted the great majority of the color scales we suggest here. | ||
|
||
Another aspect of color utilization with Smplrspace, is that you're manipulating colors in Javascript. Having at hand tools that let you programmatically manipulate colors easily, and in a way that is aligned with common data visualization patterns, is a strong advantage. We highly recommend using [chroma.js](https://gka.github.io/chroma.js/) by Gregor Aisch ([homepage](https://driven-by-data.net/)), a former graphics editor at The New York Times ([work](https://www.nytimes.com/by/gregor-aisch)) and co-founder of [Datawrapper](https://www.datawrapper.de/), an online tool to create charts, maps, and tables. Chroma.js is the underlying color utility used in the Smplrspace codebase and our color scales come loaded with options powered directly by the library. | ||
|
||
## Color tools we provide | ||
|
||
### Scales and legend | ||
|
||
The `Color` class in smplr.js provides a few color tools to help you get going quickly. The main part is color scales. We provide numerical scales based of [ColorBrewer](https://colorbrewer2.org), including sequential single hue, sequential multi-hue, and diverging scales. We also provide a categorical scale that helps you quickly map categories to colors, and a RAG (red/amber/green) scale. | ||
|
||
We also have a `Legend` component suitable for numerical scale, which works with our scales and your custom scales as well. This component is available for React, as well as vanilla Javascript. | ||
|
||
### Color mapping | ||
|
||
Finally, as the Smplrspace viewer is a 3D scene, colors are affected by a number of parameters like lighting, materials, shadows, etc. So colors in the viewer do not behave like clean CSS colors. You can actually see how a single sphere does not have the same color on its whole surface. | ||
|
||
![sphere color](/img/api-reference/sphere-color.png) | ||
|
||
To make colors more predictable, we provide two utility methods to convert colors between their CSS value and their **approximate perceived** value in the viewer. As explained, their is no clear one to one mapping, but we generally found that this works quite well. You could for example use this to render a custom legend for categorical scales. | ||
|
||
### Next pages | ||
|
||
Explore these tools on their respective API reference pages: | ||
|
||
- [Color scales](./scales) | ||
- [Legend](./legend) | ||
- [Utilities](./utils) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
--- | ||
sidebar_position: 3 | ||
sidebar_label: Legend | ||
slug: legend | ||
--- | ||
|
||
import Legend from '@site/src/components/Legend'; | ||
|
||
# Legend | ||
|
||
## React component | ||
|
||
To render the legend of a numerical color scale, you can use the `<Legend>` component as follow: | ||
|
||
```tsx | ||
interface LegendProps { | ||
colorScale: (n: number | null | undefined) => string | ||
domain?: [number, number] | ||
ticks?: Record<number, number | string> | ||
barStyle?: CSSProperties | ||
labelStyle?: CSSProperties | ||
correctColor?: boolean | ||
} | ||
<Legend {...props: LegendProps}> | ||
|
||
// example usage with Color from smplr | ||
<div width={200}> | ||
<smplr.Color.Legend | ||
colorScale={Color.numericScale({ | ||
name: Color.NumericScale.RdYlBu, | ||
domain: [10, 30], | ||
})} | ||
domain={[10, 30]} | ||
ticks={{ | ||
10: '10°C', | ||
20: '20°C', | ||
30: '30°C', | ||
}} | ||
/> | ||
</div> | ||
``` | ||
|
||
- `colorScale` is the numerical color scale for which the legend is rendered. It can come from our [`numericScale`](./scales#numerical-scales), or be a custom function that takes a numerical value and returns a color string. | ||
- `domain` - _optional_ - is the range of values to render the scale for. _Default value: `[0,1]`._ | ||
- `ticks` - _optional_ - are the values to label at the bottom of the legend. It is defined as an object where the keys are the numerical values where the tick should be and the value are the labels. By default, there is one tick at each end of the legend with the numerical value displayed without formatting. | ||
- `barStyle` - _optional_ - react style object that will be applied to the bar containing the colors. | ||
- `labelStyle` - _optional_ - react style object that will be applied to the container of the labels. It is merged with ours: `{ fontSize: '0.8em', opacity: 0.5, height: 18 }`. We set the height manually as the labels are absolutely positioned. You may need to change the height if you change the font or its size. | ||
- `correctColor` - _optional_ - lets you choose if the colors of the legend should be corrected to match the ones from the viewer as per the explanation in the [color mapping section](./overview#color-mapping). We correct them by default. _Default value: true._ | ||
|
||
Note that the Legend will fill the width of its container. [Get in touch](mailto:[email protected]) if you have ideas on improvements or pragmatic options we may have missed. | ||
|
||
## Vanilla javascript | ||
|
||
For non-react codebases, we provide a vanilla Javascript function that wraps this component and renders it into a container. | ||
|
||
```ts | ||
smplr.Color.drawLegend({ | ||
containerId: string | ||
...legendProps: LegendProps // see above | ||
}) | ||
|
||
// example usage | ||
smplr.Color.drawLegend({ | ||
containerId: 'smplr-legend', | ||
colorScale: Color.numericScale({ | ||
name: Color.NumericScale.RdYlBu, | ||
domain: [10, 30], | ||
}), | ||
domain: [10, 30], | ||
ticks: { | ||
10: '10°C', | ||
20: '20°C', | ||
30: '30°C', | ||
}, | ||
}) | ||
``` | ||
|
||
- `containerId` is the "id" of the html container where smplr.js should render the legend, something like "smplr-legend" that can be found in your html. Only ids are supported, not classes. | ||
- `...legendProps` represents all other options as per the [react component section](#react-component). | ||
|
||
## Example legend | ||
|
||
<Legend /> | ||
|
||
was rendered with the code below: | ||
|
||
```ts | ||
smplr.Color.drawLegend({ | ||
containerId: "legend", | ||
colorScale: smplr.Color.numericScale({ | ||
name: smplr.Color.NumericScale.RdYlBu, | ||
domain: [10, 30], | ||
invert: true, | ||
}), | ||
domain: [10, 30], | ||
ticks: { | ||
10: "10°C", | ||
20: "20°C", | ||
30: "30°C", | ||
}, | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
--- | ||
sidebar_position: 2 | ||
sidebar_label: Scales | ||
slug: scales | ||
--- | ||
|
||
# Color scales | ||
|
||
## Numerical scales | ||
|
||
### numericScale | ||
|
||
This function lets you quickly create scales that map numerical values to colors, and comes with a number of [best practice](./overview#a-little-context) scales, as well as options to customize them. | ||
|
||
```ts | ||
smplr.Color.numericScale({ | ||
name: NumericScale | string | ||
domain?: [number, number] | ||
invert?: boolean | ||
padding?: number | [number, number] | ||
gamma?: number | ||
brighten?: number | ||
saturate?: number | ||
nodata?: string | ||
classes?: number | number[] | ||
}) => ((n: number | null | undefined) => string) | ||
|
||
// example | ||
smplr.Color.numericScale({ | ||
name: smplr.Color.NumericScale.RdYlBu, | ||
domain: [10, 30], | ||
invert: true, | ||
}) | ||
``` | ||
|
||
- `name` is the identifier of the scale. See below for the list of available scales. You can either pass it as a string - `'OrRd'`, or using our provided enum for typesafety and autocompletion - `smplr.Color.NumericScale.OrRd`. | ||
- `domain` - _optional_ - is typically the range of values that will be passed to the scale. It is an array of 2 numbers, where the first number is mapped to the start of the scale, and the second number is mapped to the end of the scale. Values lower than the domain will be mapped to the start of the scale, and values higher to the end. _Default value: `[0,1]`._ | ||
- `invert` - _optional_ - is a boolean used to invert the scale, or swap its start and end. _Default value: false._ | ||
- `padding` - _optional_ - reduces the color range by cutting off a fraction of the scale. A single number applies the same padding to both ends, while an array lets you pad differently on the start and the end of the scale. Negative values can be used to compress the scale and extend its extreme values. _Default value: 0._ | ||
- `gamma` - _optional_ - is used to "shift" a scale's center more the the beginning (gamma < 1) or end (gamma > 1). _Default value: 1._ | ||
- `brighten` - _optional_ - is used to change the lightness of the scale. Positive values brightens it, while negative values darkens it. _Default value: 0._ | ||
- `saturate` - _optional_ - is used to change the saturation of the scale. Positive values saturates it, while negative values desaturates it. _Default value: 0._ | ||
- `nodata` - _optional_ - is the color used when the value passed to the scale is not valid. _Default value: #6a6c6c._ | ||
- `classes` - _optional_ - is used to return a distinct set of colors instead of a continuous scale. A number generates a scale broken into equi-distant classes, while an array lets you choose the "breakpoints" to use for the classes. | ||
|
||
The scales available are: | ||
|
||
- single hue sequential scales: Oranges, Reds, Greens, Purples, Greys, Blues - from [ColorBrewer](https://colorbrewer2.org). | ||
- multi-hue sequential scales: OrRd, PuBu, BuPu, BuGn, YlOrBr, YlGn, RdPu, YlGnBu, GnBu, YlOrRd, PuRd, PuBuGn – from [ColorBrewer](https://colorbrewer2.org), and Viridi initially from [Matplotlib](https://bids.github.io/colormap/). | ||
- diverging scales: Spectral, RdYlGn, RdBu, PiYG, PRGn, RdYlBu, BrBG, RdGy, PuOr - from [ColorBrewer](https://colorbrewer2.org). | ||
|
||
The [air quality](/examples/air-quality) example uses `numericScale` and can be used as a code playground to test out the options. You can also chose and configure a color scale using our [colors playground](https://colors.smplrspace.io). | ||
|
||
:::tip | ||
|
||
Configure a numerical scale using our interactive [colors playground](https://colors.smplrspace.io) | ||
|
||
::: | ||
|
||
## Categorical scales | ||
|
||
### categoryScale | ||
|
||
This function lets you quickly map a discrete number of named categories to colors. It comes with fallback color built-in, as well as type safe categories. | ||
|
||
```ts | ||
smplr.Color.numericScale<C extends string>({ | ||
categories: Record<C, string> | ||
nodata?: string | ||
}): ((category: C) => string) | ||
|
||
// example | ||
smplr.Color.categoryScale({ | ||
categories: { | ||
sunny: 'yellow', | ||
rainy: 'blue', | ||
cloudy: 'grey' | ||
}, | ||
}) | ||
``` | ||
|
||
- `categories` is an object matching category names to colors. | ||
- `nodata` - _optional_ - is the color used when the value passed to the scale is not a known category. _Default value: #6a6c6c._ | ||
|
||
Typescript tip: You may disable category typesafety by passing a "loose" type hint to the function: `categoryScale<string>({...})`. | ||
|
||
### ragScale | ||
|
||
This function is built on top of `categoryScale` and provide a shortcut for red/amber/green scenarios. Here, the scale comes with pre-defined and optimized RAG colors, that can be customized. And the values "red", "amber", and "green" are always valid for quick testing. | ||
|
||
```ts | ||
smplr.Color.ragScale<C extends string | 'red' | 'amber' | 'green'>({ | ||
categories?: Partial<Record<'red' | 'amber' | 'green', C>> | ||
colors?: { | ||
red?: string | ||
amber?: string | ||
green?: string | ||
} | ||
nodata?: string | ||
}): ((category: C) => string) | ||
|
||
// example | ||
smplr.Color.ragScale({ | ||
categories: { | ||
red: 'vacant', | ||
amber: 'expiring', | ||
green: 'occupied', | ||
}, | ||
}) | ||
``` | ||
|
||
- `categories` - _optional_ - is an object matching category names to the RAG classes. _Default value: `{ red: 'red', amber: 'amber', green: 'green' }`._ | ||
- `colors` - _optional_ - is an object used to provide custom RAG colors. _Default value: `{ red: '#ff3f34', amber: '#c77a15', green: '#3aa655' }`._ | ||
- `nodata` - _optional_ - is the color used when the value passed to the scale is not a known category. _Default value: #6a6c6c._ | ||
|
||
Typescript tip: You may disable category typesafety by passing a "loose" type hint to the function: `ragScale<string>({...})`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
--- | ||
sidebar_position: 4 | ||
sidebar_label: Utilities | ||
slug: utils | ||
--- | ||
|
||
# Color utilities | ||
|
||
## cssToSmplrColor | ||
|
||
As explained in the [color mapping section](./overview#color-mapping), colors in the viewer are matching one to one to their CSS value. To convert a CSS color into its **approximate perceived** value in the viewer, you can call this function: | ||
|
||
```ts | ||
smplr.Color.cssToSmplrColor(c: string) => string | ||
``` | ||
|
||
where `c` is the color string in CSS. Accepted formats are the hexadecimal value (e.g. "#2393d4") or the name of the color (e.g. "pink"). | ||
|
||
## smplrToCssColor | ||
|
||
This is the opposite function of `cssToSmplrColor` and converts a color value as it is **approximately perceived** in the viewer, into its CSS equivalent. | ||
|
||
```ts | ||
smplr.Color.smplrToCssColor(c: string) => string | ||
``` |
Oops, something went wrong.