Reputation: 2024
I am using pydeck to render a visualization using spatial data. I was hoping to use a custom color scale and apply the gradient to the hexagons based on counts.
here's some json
data:
[{"count": "12", "hexIds": ["82beeffffffffff"]}, {"count": "35", "hexIds": ["82be77fffffffff"]}, {"count": "51", "hexIds": ["82b917fffffffff"]}, {"count": "32", "hexIds": ["82bf4ffffffffff"]}, {"count": "93", "hexIds": ["82be67fffffffff"]}, {"count": "51", "hexIds": ["82c997fffffffff"]}, {"count": "13", "hexIds": ["82be5ffffffffff"]}, {"count": "11", "hexIds": ["82bed7fffffffff"]}, {"count": "52", "hexIds": ["82be47fffffffff"]}, {"count": "9", "hexIds": ["82c987fffffffff"]}, {"count": "13", "hexIds": ["82b9a7fffffffff"]}, {"count": "26", "hexIds": ["82a737fffffffff"]}, {"count": "38", "hexIds": ["82be8ffffffffff"]}, {"count": "3", "hexIds": ["829d77fffffffff"]}, {"count": "85", "hexIds": ["82be0ffffffffff"]}, {"count": "12", "hexIds": ["82b9b7fffffffff"]}, {"count": "23", "hexIds": ["82be6ffffffffff"]}, {"count": "2", "hexIds": ["82b84ffffffffff"]}, {"count": "6", "hexIds": ["829d4ffffffffff"]}, {"count": "6", "hexIds": ["82b85ffffffffff"]}, {"count": "7", "hexIds": ["82bec7fffffffff"]}, {"count": "32", "hexIds": ["82be57fffffffff"]}, {"count": "2", "hexIds": ["82a7affffffffff"]}, {"count": "30", "hexIds": ["82a727fffffffff"]}, {"count": "6", "hexIds": ["82a787fffffffff"]}, {"count": "21", "hexIds": ["82bee7fffffffff"]}, {"count": "10", "hexIds": ["82b847fffffffff"]}, {"count": "5", "hexIds": ["82a617fffffffff"]}, {"count": "6", "hexIds": ["82a6a7fffffffff"]}, {"count": "7", "hexIds": ["8294effffffffff"]}, {"count": "17", "hexIds": ["82bef7fffffffff"]}, {"count": "1", "hexIds": ["8294e7fffffffff"]}, {"count": "6", "hexIds": ["82a78ffffffffff"]}, {"count": "13", "hexIds": ["82a79ffffffffff"]}, {"count": "3", "hexIds": ["82b877fffffffff"]}, {"count": "5", "hexIds": ["82a797fffffffff"]}, {"count": "28", "hexIds": ["82be4ffffffffff"]}, {"count": "7", "hexIds": ["829487fffffffff"]}, {"count": "4", "hexIds": ["82bedffffffffff"]}, {"count": "2", "hexIds": ["82945ffffffffff"]}, {"count": "10", "hexIds": ["82b997fffffffff"]}, {"count": "4", "hexIds": ["82b9affffffffff"]}, {"count": "9", "hexIds": ["829c27fffffffff"]}, {"count": "16", "hexIds": ["82a707fffffffff"]}, {"count": "3", "hexIds": ["829d07fffffffff"]}, {"count": "8", "hexIds": ["82c9b7fffffffff"]}, {"count": "2", "hexIds": ["8294affffffffff"]}, {"count": "5", "hexIds": ["829d5ffffffffff"]}, {"count": "5", "hexIds": ["829d57fffffffff"]}, {"count": "1", "hexIds": ["82b80ffffffffff"]}, {"count": "11", "hexIds": ["82beaffffffffff"]}, {"count": "2", "hexIds": ["82b8b7fffffffff"]}, {"count": "1", "hexIds": ["829497fffffffff"]}, {"count": "7", "hexIds": ["829d27fffffffff"]}, {"count": "2", "hexIds": ["82a7a7fffffffff"]}, {"count": "6", "hexIds": ["82b887fffffffff"]}, {"count": "7", "hexIds": ["829457fffffffff"]}, {"count": "4", "hexIds": ["82c99ffffffffff"]}, {"count": "2", "hexIds": ["8294cffffffffff"]}, {"count": "4", "hexIds": ["82b88ffffffffff"]}, {"count": "3", "hexIds": ["82b98ffffffffff"]}, {"count": "7", "hexIds": ["82b837fffffffff"]}, {"count": "9", "hexIds": ["829d0ffffffffff"]}, {"count": "2", "hexIds": ["8294c7fffffffff"]}, {"count": "6", "hexIds": ["829d2ffffffffff"]}, {"count": "2", "hexIds": ["829d47fffffffff"]}, {"count": "3", "hexIds": ["82b867fffffffff"]}, {"count": "1", "hexIds": ["82b807fffffffff"]}, {"count": "5", "hexIds": ["82b8a7fffffffff"]}, {"count": "2", "hexIds": ["829d67fffffffff"]}, {"count": "1", "hexIds": ["82a717fffffffff"]}, {"count": "2", "hexIds": ["82b82ffffffffff"]}, {"count": "1", "hexIds": ["829c6ffffffffff"]}, {"count": "2", "hexIds": ["829c2ffffffffff"]}, {"count": "1", "hexIds": ["8294dffffffffff"]}, {"count": "1", "hexIds": ["82d897fffffffff"]}, {"count": "8", "hexIds": ["82b86ffffffffff"]}, {"count": "1", "hexIds": ["82b91ffffffffff"]}, {"count": "3", "hexIds": ["82948ffffffffff"]}, {"count": "3", "hexIds": ["829c4ffffffffff"]}, {"count": "5", "hexIds": ["82b897fffffffff"]}, {"count": "1", "hexIds": ["82b89ffffffffff"]}, {"count": "1", "hexIds": ["829c07fffffffff"]}, {"count": "1", "hexIds": ["82b937fffffffff"]}, {"count": "1", "hexIds": ["82949ffffffffff"]}, {"count": "1", "hexIds": ["82b99ffffffffff"]}, {"count": "1", "hexIds": ["82b987fffffffff"]}, {"count": "1", "hexIds": ["8294d7fffffffff"]}, {"count": "1", "hexIds": ["82b8dffffffffff"]}, {"count": "1", "hexIds": ["829ce7fffffffff"]}, {"count": "15", "hexIds": ["82becffffffffff"]}, {"count": "13", "hexIds": ["82be1ffffffffff"]}, {"count": "1", "hexIds": ["82b827fffffffff"]}]
import pandas as pd
import pydeck
df = pd.read_json('aus_h3.duckgl.json')
h3_layer = pydeck.Layer(
"H3ClusterLayer",
df,
pickable=True,
stroked=True,
filled=True,
extruded=False,
get_hexagons="hexIds",
get_fill_color="[255, (1 - count / 500) * 255, 0]",
get_line_color=[255, 255, 255],
line_width_min_pixels=2,
)
view_state = pydeck.ViewState(latitude=-25.7773677126431,
longitude=135.084939479828,
zoom=4,
bearing=0,
pitch=45)
pydeck.Deck(
layers=[h3_layer],
initial_view_state=view_state,
tooltip={"text": "Density: {count}"}
).to_html("aus_h3.duckgl.html")
How do I specify a custom color scale instead on [255, (1 - count / 500) * 255, 0]
in get_fill_color
? For example, I'd like to use 6-class color scale: https://colorbrewer2.org/#type=sequential&scheme=YlOrRd&n=6
Upvotes: 0
Views: 1716
Reputation: 96
According to the deck.gl documentation, get_fill_color
needs to be an RGB(A) array, or a function returning such an array. The pydeck documentation says that general functions are not allowed, but expressions using your data as parameters are allowed to be given as strings, so that gives at least two options:
Using the color scheme you provided: the brightest color expressed in RGB is [255,255,178]
and the darkest is [189,0,38]
.
A linear gradient that spans these colors can be constructed from your data such that the brightest color corresponds to lowest count
and darkest color to highest count
:
min_count = df['count'].min()
max_count = df['count'].max()
diff = max_count - min_count
color_scheme = f"""[
255 - (255-189) * (count - {min_count})/{diff},
255 - 255 * (count - {min_count})/{diff},
178 - (178-38) * (count - {min_count})/{diff}
]"""
This can be passed to the pydeck.Layer
as get_fill_color=color_scheme
and gives approximately the same scale as you provided.
Add a new column to the DataFrame
containing the exact color scheme you want to use. Then the value from that column can be passed as the get_fill_color
-parameter.
This can be done as such:
from math import floor
min_count = df['count'].min()
max_count = df['count'].max()
diff = max_count - min_count
color_scheme = [
[255,255,178],
[254,217,118],
[254, 178, 76],
[253, 141, 60],
[240,59,32],
[189,0,38]
]
def get_color(row):
number_of_colors = len(color_scheme)
index = floor(number_of_colors * (row['count'] - min_count) / diff)
# the index might barely go out of bounds, so correct for that:
if index == number_of_colors:
index = number_of_colors - 1
elif index == -1:
index = 0
return color_scheme[index]
df['color_column'] = df.apply(get_color, axis=1)
And pass this to the pydeck.Layer
as get_fill_color="color_column"
.
Upvotes: 2