How can I set up the correct color image color in datashader?

I have tried to plot a given example from the datashader page about Timeseries. I used all the code snippets including this paragraph and tried to plot the img with matplotlib by passing the img to the plt.imshow(img):

import datetime
import pandas as pd
import numpy as np
import xarray as xr
import datashader as ds
import datashader.transfer_functions as tf
from collections import OrderedDict

import matplotlib.pyplot as plt
...

cvs = ds.Canvas(x_range=x_range, y_range=y_range, plot_height=300, plot_width=900)
aggs= OrderedDict((c, cvs.line(df, 'ITime', c)) for c in cols)
img = tf.shade(aggs['a'])

plt.imshow(img)
plt.show()
plt.close()

I thought, it would render an image, with a white background and a blue graph as illustrated. Nevertheless, the result looks like this:

enter image description here enter image description here

Additionally, I have also tried the following lines, but I could not created example images as shown on the datashader page:


colors = ["red", "grey", "black", "purple", "pink",
          "yellow", "brown", "green", "orange", "blue"]
imgs = [tf.shade(aggs[i], cmap=[c]) for i, c in zip(cols, colors)]
tf.stack(*imgs)

How can I correctly setup the color of my image in order to plot, save or work with it?

How did it work in the datashader example?


How can I correctly setup the color of my image in order to plot, save or work with it?

The simple answer is that if you want to plot the output of tf.shade in Matplotlib using imshow, you can convert it to a PIL image that imshow understands using img.to_pil():

imshow img.to_pil

If you don't convert it to PIL like that, the output of tf.shade() is an object of type datashader.transfer_functions.Image, a type of Xarray DataArray that stacks the R, G, B, and A channels of an image as a multidimensional array. imshow can display RGBA images, but not in the stacked DataArray format returned by Datashader, so it appears to take only one of the channels (R, maybe?) and plots that using the default Matplotlib colormap, hence the different colors. So don't ever pass the output of tf.shade directly to imshow; that's not ever going to be useful, and it's a bit unfortunate that it plots anything at all, since it's so misleading.

You can safely pass the underlying two-dimensional aggregate array (the output of cvs.line) to imshow for Matplotlib to colormap and display, but (a) you'll want to choose your own colormap if you don't like Matplotlib's default of Viridis, and (b) the output will be flipped vertically as Datashader renders to coordinates starting in the lower left and Matplotlib's start in the upper left:

imshow output

But instead of any of these options, if you want a Matplotlib figure I'd recommend using Datashader's native Matplotlib dsshow plotting support to show the result as a Matplotlib figure; no need to deal with any of the intermediate steps like this, and as a bonus the results will be interactive.

How did it work in the datashader example?

The Datashader docs are all written as Jupyter notebooks, and in those examples the notebook is what handles image display, using Jupyter/IPython's rich display support. Specifically, a datashader Image object implements _repr_html_(), and Jupyter/IPython calls that method to display the object in the notebook. You can instead call img.to_pil() yourself if you want something easily converted to PNG as described in the PIL docs.