Datashader canvas.line() 别名
Datashader canvas.line() aliasing
我使用 bokeh 绘制温度曲线,但在某些情况下,数据集非常大(> 500k 测量值)并且我的 bokeh 用户体验很差(事件 output_backend="webgl").所以我正在试验数据着色器以获得更快的渲染和更流畅的用户体验。
但是datashader给出的视觉结果不如bokeh的结果漂亮,datashader结果有锯齿:
我通过以下代码获得了这种并排比较:
import pandas as pd
import datashader as ds
import datashader.transfer_functions as tf
from bokeh.plotting import figure
from bokeh.io import output_notebook, show
from bokeh.models import ColumnDataSource
from bokeh.layouts import row
import numpy as np
output_notebook()
# generate signal
n = 2000
start = 0
end = 70
signal = [np.sin(x) for x in np.arange(start, end, step=(end-start)/n)]
signal = pd.DataFrame(signal, columns=["signal"])
signal = signal.reset_index()
# create a bokeh plot
source = ColumnDataSource(signal)
p = figure(plot_height=300, plot_width=400, title="bokeh plot")
p.line(source=source, x="index", y="signal")
# create a datashader image and put it in a bokeh plot
x_range = (signal["index"].min(), signal["index"].max())
y_range = (signal["signal"].min(), signal["signal"].max())
cvs = ds.Canvas(x_range=x_range, y_range=y_range, plot_height=300, plot_width=400)
agg = cvs.line(signal, 'index', 'signal')
img = tf.shade(agg)
image_source = ColumnDataSource(data=dict(image = [img.data]))
q = figure(x_range=x_range, y_range=y_range, plot_height=300, plot_width=400, title="datashader + bokeh")
q.image_rgba(source = image_source,
image="image",
dh=(y_range[1] - y_range[0]),
dw=(x_range[1] - x_range[0]),
x=x_range[0],
y=y_range[0],
dilate=False)
# visualize both plot, bokeh on left
show(row(p, q))
您是否知道如何修复此别名并获得平滑的结果? (类似于散景的结果)
这是您的代码的可运行版本,在 Jupyter 笔记本中使用 HoloViews:
import pandas as pd, numpy as np, holoviews as hv
from holoviews.operation.datashader import datashade, dynspread
hv.extension("bokeh")
%opts Curve RGB [width=400]
n, start, end = 2000, 0, 70
sine = [np.sin(x) for x in np.arange(start, end, step=(end-start)/n)]
signal = pd.DataFrame(sine, columns=["signal"]).reset_index()
curve = hv.Curve(signal)
curve + datashade(curve)
的确,这里的数据阴影输出看起来不太好。 Datashader 的时间序列支持,与 Datashader 的其余部分一样,旨在允许对光栅网格上大量数学上完美(即无限细)的曲线进行精确累加和求和,以便每条曲线上的每个 x 位置都落入一个且唯一的网格中的一个 y 位置。在这里,您似乎只需要大型时间序列的服务器端渲染,这需要网格中多个附近的容器的部分递增,而数据着色器还没有为此进行优化。
您已经可以做的一件事是以高分辨率渲染曲线然后 "spread" 这样每个非零像素也将显示在相邻像素中:
curve + dynspread(datashade(curve, height=1200, width=1200, dynamic=False, \
cmap=["#30a2da"]), max_px=3, threshold=1)
这里我将颜色设置为匹配 Bokeh 的默认值,然后强制 HoloView 的 "dynspread" 功能扩展 3 个像素。在您的版本中使用 Datashader+Bokeh,您将执行 ``img = tf.spread(tf.shade(agg), px=3)` 并在 Canvas 调用中增加绘图大小以获取类似的结果。
我还没有尝试 运行 对 tf.shade() 或 tf.spread() 的结果进行简单的平滑过滤,但它们都只是 return RGB 图像, 所以像这样的一些过滤器可能会产生好的结果。
真正的解决方案是为数据着色器实现一个可选的抗锯齿线条绘制功能,在先绘制线条时运行,而不是稍后修复像素,但这需要一些工作。欢迎投稿!
我使用 bokeh 绘制温度曲线,但在某些情况下,数据集非常大(> 500k 测量值)并且我的 bokeh 用户体验很差(事件 output_backend="webgl").所以我正在试验数据着色器以获得更快的渲染和更流畅的用户体验。
但是datashader给出的视觉结果不如bokeh的结果漂亮,datashader结果有锯齿:
我通过以下代码获得了这种并排比较:
import pandas as pd
import datashader as ds
import datashader.transfer_functions as tf
from bokeh.plotting import figure
from bokeh.io import output_notebook, show
from bokeh.models import ColumnDataSource
from bokeh.layouts import row
import numpy as np
output_notebook()
# generate signal
n = 2000
start = 0
end = 70
signal = [np.sin(x) for x in np.arange(start, end, step=(end-start)/n)]
signal = pd.DataFrame(signal, columns=["signal"])
signal = signal.reset_index()
# create a bokeh plot
source = ColumnDataSource(signal)
p = figure(plot_height=300, plot_width=400, title="bokeh plot")
p.line(source=source, x="index", y="signal")
# create a datashader image and put it in a bokeh plot
x_range = (signal["index"].min(), signal["index"].max())
y_range = (signal["signal"].min(), signal["signal"].max())
cvs = ds.Canvas(x_range=x_range, y_range=y_range, plot_height=300, plot_width=400)
agg = cvs.line(signal, 'index', 'signal')
img = tf.shade(agg)
image_source = ColumnDataSource(data=dict(image = [img.data]))
q = figure(x_range=x_range, y_range=y_range, plot_height=300, plot_width=400, title="datashader + bokeh")
q.image_rgba(source = image_source,
image="image",
dh=(y_range[1] - y_range[0]),
dw=(x_range[1] - x_range[0]),
x=x_range[0],
y=y_range[0],
dilate=False)
# visualize both plot, bokeh on left
show(row(p, q))
您是否知道如何修复此别名并获得平滑的结果? (类似于散景的结果)
这是您的代码的可运行版本,在 Jupyter 笔记本中使用 HoloViews:
import pandas as pd, numpy as np, holoviews as hv
from holoviews.operation.datashader import datashade, dynspread
hv.extension("bokeh")
%opts Curve RGB [width=400]
n, start, end = 2000, 0, 70
sine = [np.sin(x) for x in np.arange(start, end, step=(end-start)/n)]
signal = pd.DataFrame(sine, columns=["signal"]).reset_index()
curve = hv.Curve(signal)
curve + datashade(curve)
的确,这里的数据阴影输出看起来不太好。 Datashader 的时间序列支持,与 Datashader 的其余部分一样,旨在允许对光栅网格上大量数学上完美(即无限细)的曲线进行精确累加和求和,以便每条曲线上的每个 x 位置都落入一个且唯一的网格中的一个 y 位置。在这里,您似乎只需要大型时间序列的服务器端渲染,这需要网格中多个附近的容器的部分递增,而数据着色器还没有为此进行优化。
您已经可以做的一件事是以高分辨率渲染曲线然后 "spread" 这样每个非零像素也将显示在相邻像素中:
curve + dynspread(datashade(curve, height=1200, width=1200, dynamic=False, \
cmap=["#30a2da"]), max_px=3, threshold=1)
这里我将颜色设置为匹配 Bokeh 的默认值,然后强制 HoloView 的 "dynspread" 功能扩展 3 个像素。在您的版本中使用 Datashader+Bokeh,您将执行 ``img = tf.spread(tf.shade(agg), px=3)` 并在 Canvas 调用中增加绘图大小以获取类似的结果。
我还没有尝试 运行 对 tf.shade() 或 tf.spread() 的结果进行简单的平滑过滤,但它们都只是 return RGB 图像, 所以像这样的一些过滤器可能会产生好的结果。
真正的解决方案是为数据着色器实现一个可选的抗锯齿线条绘制功能,在先绘制线条时运行,而不是稍后修复像素,但这需要一些工作。欢迎投稿!