Hi,
I’m trying to display a series of geo TIFF images, which would be components of a ColumnDataSource. I am struggling on how to pass the source so that it can retrieve the right image.
Step 1) Create several rasters (TIF) from my original geopandas dataframe
Step 2) Create ColumnDataSource
Step 3) Show different rasters using a slider *Need the CDS and CDSView to work and pass the information to image.
##################################################
import pandas as pd
import geopandas as gpd
import rasterio
from geocube.api.core import make_geocube
import os
from bokeh.plotting import figure, show, output_file, save
from bokeh.models import ColumnDataSource, HoverTool, ColorMapper, ColorBar,Ticker,OpenURL, TapTool, Circle, LogTicker, LabelSet,FixedTicker, Button, Dropdown, CheckboxButtonGroup, RadioButtonGroup, GeoJSONDataSource, Patches
from bokeh.models import widgets, CustomJS, Slider, Label, LinearColorMapper, LogColorMapper, ContinuousTicker, CategoricalColorMapper, axes,CDSView,GroupFilter, BooleanFilter
from bokeh.models import Range1d, CDSView, Div, Paragraph, LogAxis, Select
from bokeh.models import MultiLine, Scatter, Rect, Line, LegendItem, Legend, PrintfTickFormatter, CheckboxGroup, CustomJSFilter
from bokeh.layouts import gridplot
from bokeh.models.glyphs import Quad
from bokeh.layouts import layout, column, row, gridplot
from bokeh.tile_providers import get_provider, Vendors
from bokeh.palettes import Spectral8, magma
from bokeh.transform import linear_cmap, factor_cmap, factor_mark
from bokeh.models import ColorBar
#import pyodbc
import bokeh as bk
import numpy as np
####################################################
#%% STEP 1 - Data Generation
####################################################
#Note: rasters don't have the same size
data = [[1,1,1,2],[1,2,1,2],[1,2,2,2],[1,1,2,2],\
[2,1,1,4],[2,2,1,4],[2,2,2,4],[2,1,2,4],[2,1,3,4],[2,3,3,4]]
df = pd.DataFrame(data,columns=['rasterID','X','Y','col'])
adf = df[df['rasterID']==1]
gdf1 = gpd.GeoDataFrame(adf, geometry=gpd.points_from_xy(adf.X, adf.Y), crs="EPSG:3857")
out_grid = make_geocube(
vector_data=gdf1,
measurements=['col'],
resolution=(-0.5, 0.5))
#Save my TIFF1
out_grid['col'].rio.to_raster("Raster1.TIF")
bdf = df[df['rasterID']==2]
gdf2 = gpd.GeoDataFrame(bdf, geometry=gpd.points_from_xy(bdf.X, bdf.Y), crs="EPSG:3857")
out_grid = make_geocube(
vector_data=gdf2,
measurements=['col'],
resolution=(-0.5, 0.5),
)
#Save my TIFF2
out_grid['col'].rio.to_raster("Raster2.TIF")
####################################################
#%% STEP 2 - Data Source
####################################################
DataSource = []
raster1 = rasterio.open('Raster1.TIF')
raster2 = rasterio.open('Raster2.TIF')
DataSource.append(['1', raster1])
DataSource.append(['2', raster2])
df_DS = pd.DataFrame(DataSource,columns=['ID','raster'])
####################################################
#%% STEP 3 - Bokeh
####################################################
pv = figure(tools=['wheel_zoom','box_zoom','reset','pan','lasso_select','box_select']
,match_aspect=True,x_axis_type='mercator',y_axis_type='mercator'
,width=1000,height=700)
#Specified the map extent to start with.
pv.x_range = Range1d(start=1,end=5)
pv.y_range = Range1d(start=1,end=5)
#This is where I would like to use the DS_source and DS_view, but can't figure it out. Just ploting first raster instead.
#DS_source = ColumnDataSource(data=df_DS)
#DS_view = CDSView(source=DS_source,filters=[GroupFilter(column_name='ID',group='1')])
info = df_DS.iloc[1]['raster']
DS_rend = pv.image(image = [np.flipud(info.read(1))],
x=info.bounds[0],
y=info.bounds[1],
dw=info.bounds[2]-info.bounds[0],
dh=info.bounds[3]-info.bounds[1],
legend_label="Value",
palette = 'RdYlGn11',
alpha=0.5
)
DS_hover = HoverTool(renderers=[DS_rend],tooltips=[('Value','@image{0.0}')])
pv.add_tools(DS_hover)
pv.legend.click_policy='hide'
#Simple slider to change the raster
slider = Slider(start=0, end=1, width=400
, value=0, step=1, title="ID: Raster1"
, sizing_mode="fixed")
slider.show_value = True
slider.tooltips = True
slider_dict = {'0':'Raster1', '1':'Raster2'}
cb = bk.models.CustomJS(args=dict(
slider=slider
,slider_dict=slider_dict
#,DS_source=DS_source
),
code="""
console.log(cb_obj.value);
//SLIDER
var id = slider.value;
slider.title = 'ID: ' + slider_dict[id]
//DS_source.filters[0].group = slider_dict[id]
""")
slider.js_on_change('value',cb)
lo = layout([[slider]
,[pv]]
,sizing_mode="fixed")
save(lo,r'Bokeh_discourse.20240609.html')