如何使用redis缓存虚化地块?

问题描述 投票:0回答:1

我正在使用虚化服务器在地图上渲染一个时间序列图。 随着时间序列的发展,地图的焦点会移动。

下面的代码可以工作,但每一次进展都会创建一个调用,调用google api (GMAP)来获取背景。 这就需要时间来渲染。 在时间序列连续几次快速转移焦点的地方,背景还没有来得及渲染就被更新了。

我一直在尝试如何提前提出这些请求,并进行缓存(使用redis),使用户能够查看缓存中已经加载的所有数据,以满足时间序列上的每个刻度。

main.py

import settings
from bokeh.plotting import figure, gmap
from bokeh.embed import components
from bokeh.models import CustomJS, ColumnDataSource, Slider, GMapOptions, GMapPlot, Range1d, Button
from bokeh.models.widgets import DataTable, TableColumn, HTMLTemplateFormatter
from bokeh.layouts import column, row, gridplot, layout
from bokeh.io import show, export_png, curdoc

from filehandler import get_graph_data


"""
Get arguments from request
"""
try:
    args = curdoc().session_context.request.arguments
    pk = int(args.get('pk')[0])
except:
    pass
"""
get data for graph from file and initialise variables
"""
#load data into dictionary from file referenced by pk
data_dict = get_graph_data(pk)

no_of_markers = data_dict.get('markers') 
length_of_series = data_dict.get('length')
series_data = data_dict.get('data') #lat/lon position of each series at each point in time
series_names = series_data.get('series_names') #names of series
range_x_axis = data_dict.get('xaxis') #min/max lat co-ords
range_y_axis = data_dict.get('yaxis') #min/max lon co-ords


"""
Build data
"""
graph_source = ColumnDataSource(series_data)

"""
Build markers to show current location
"""
markers = ColumnDataSource(data=dict(lon=[], lat=[]))

"""
Build mapping layer
"""
def create_map_backdrop(centroid, zoom, tools):
    """
    Create the map backdrop, centered on the starting point
    Using GoogleMaps api
    """
    map_options = GMapOptions(lng=centroid[1],
                              lat=centroid[0],
                              map_type='roadmap',
                              zoom=zoom,
                              )

    return gmap(google_api_key=settings.MAP_KEY,
                map_options=map_options,
                tools=tools,
                )

#set map focus
centroid = (graph_source.data['lats'][0][0],
            graph_source.data['lons'][0][0],
            )


"""
Build Plot
"""

tools="pan, wheel_zoom, reset"
p = create_map_backdrop(centroid, 18, tools)
p.multi_line(xs='lons',
             ys='lats',
             source=graph_source,
             line_color='color',
             )
p.toolbar.logo = None
p.circle(x='lon', y='lat', source=markers)


"""
User Interactions
"""

def animate_update():
    tick = slider.value + 1
    slider.value = tick

def slider_update(attr, old, new):
    """
    Updates all of the datasources, depending on current value of slider
    """
    start = timer()
    if slider.value>series_length:
        animate()
    else:
        tick = slider.value
        i=0
        lons, lats = [], []
        marker_lons, marker_lats = [], []

        while i < no_of_markers:

            #update lines
            lons.append(series_data['lons'][i][0:tick])
            lats.append(series_data['lats'][i][0:tick])

            #update markers
            marker_lons.append(series_data['lons'][i][tick])
            marker_lats.append(series_data['lats'][i][tick])

            #update iterators
            i += 1

        #update marker display
        markers.data['lon'] = marker_lons
        markers.data['lat'] = marker_lats

        #update line display
        graph_source.data['lons'] = lons
        graph_source.data['lats'] = lats    

        #set map_focus
        map_focus_lon = series_data['lons'][tick]
        map_focus_lat = series_data['lats'][tick]

        #update map focus
        p.map_options.lng = map_focus_lon
        p.map_options.lat = map_focus_lat



slider = Slider(start=0, end=series_length, value=0, step=5)
slider.on_change('value', slider_update)
callback_id = None

def animate():
    global callback_id
    if button.label == "► Play":
        button.label = "❚❚ Pause"
        callback_id = curdoc().add_periodic_callback(animate_update, 1)

    else:
        button.label = "► Play"
        curdoc().remove_periodic_callback(callback_id)

button = Button(label="► Play", width=60)
button.on_click(animate)

"""
Display plot
"""


grid = layout([[p, data_table],
                [slider, button],
                ])

curdoc().add_root(grid)

我已经尝试过缓存绘图数据(p),但看起来这是在调用google api之前就已经存在了。

我探索过直接从api缓存地图磁贴,然后将它们作为背景图片拼接到情节中(使用bokeh ImageURL),但我无法让ImageUrl识别内存中的图片。

服务器文档建议可以使用redis作为后端,所以我想知道这是否会加快进度,但当我尝试启动它时,发现 bokeh serve myapp --allow-websocket-origin=127.0.0.1:5006 --backend=redis 我得到 --backend is not a recognised command.

有没有一种方法可以缓存完全渲染的图形(可能是图形文档本身),同时保留用户与图形交互的能力;或者在gmap图形渲染完成后缓存它,然后将其添加到其余的图形中?

python google-maps redis bokeh
1个回答
1
投票

如果这是独立的Bokeh内容(即不是Bokeh服务器应用),那么你可以用以下方法序列化情节的JSON表示 json_items 并在浏览器中明确地用以下方法给它重新补水 Bokeh.embed_items. 该JSON有可能被存储在Redis中,也许这将是相关的。但Bokeh服务器不是这样的。在最初的会话创建之后,从来没有任何 "整个文档 "可以存储或缓存,只是通过websocket协议发生的一系列增量的、部分的更新。例如,服务器说 "这个特定的数据源改变了",浏览器说 "好的,我应该重新计算边界并重新渲染"。

也就是说,我建议做一些改变。

第一,你不应该一个一个地更新CDS列。你不应该这样做。

# BAD
markers.data['lon'] = marker_lons
markers.data['lat'] = marker_lats

这会产生两个独立的更新事件和两个独立的重渲染请求。 除了这会导致额外的工作,还有一种情况是第一次更新保证会有不匹配的oldnew坐标。相反,你应该总是更新CDS .data dict "原子地",一次完成。

source.data = new_data_dict

另外,你可以试试 curdoc().hold 以收集更新到较少的事件中。

© www.soinside.com 2019 - 2024. All rights reserved.