#!/usr/bin/env python # coding: utf-8 # # Matteo colourmaps # Matteo Niccoli has made some awesome colourmaps, and has published a routine to convert them to Matplotlib colourmaps. This is very cool! # # He explains all in his 25 April 2014 blog post [Convert colour palettes to Python Matplotlib colour palettes](http://mycarta.wordpress.com/2014/04/25/convert-color-palettes-to-python-matplotlib-colormaps/). # ## Load the data # There's a bit at the start where you are downloading data, unzipping, reformatting, etc. I thought I'd try doing all that in Python too... # In[1]: get_ipython().run_line_magic('pylab', 'inline') import numpy as np # We can read the data straight from the web. We'll need some of the standard libraries. # In[2]: import urllib2, zipfile, StringIO # Now we can read the zip file and examine its contents. We'll keep it in memory using a StringIO object. # In[3]: remote_file = 'http://mycarta.files.wordpress.com/2013/03/0-1.odt' # Read the data from the web, as normal. web_data = urllib2.urlopen(remote_file) # Convert the bytes into a file-like object in memory zip_in_memory = StringIO.StringIO(web_data.read()) # Instantiate a ZipFile object from the file-like in memory. z = zipfile.ZipFile(zip_in_memory) z.namelist() # We need file number 5. # In[4]: f = z.open(z.namelist()[5]) raw_data = f.read() # Let's look at the first 100 characters: # In[5]: raw_data[:100] # We just need to split this to get a list of strings: # In[6]: list_o_strings = raw_data.split() list_o_strings[:10] # Now we can use a nested list comprehension to step over the list of strings, splitting each string on its commas, and converting each element (which will still be a string) to a floating point number... # In[7]: list_o_lists = [[float(num) for num in string.split(',')] for string in list_o_strings] list_o_lists[:10] # In[8]: LinL = np.array(list_o_lists) LinL[:3] # Win! # ## Continue with Matteo's workflow # We'll just run Matteo's code... # In[9]: get_ipython().run_line_magic('matplotlib', 'inline') import matplotlib.pyplot as plt # In[10]: b3 = LinL[:,2] # value of blue at sample n b2 = LinL[:,2] # value of blue at sample n b1 = linspace(0, 1, len(b2)) # position of sample n - ranges from 0 to 1 # Setting up columns for tuples g3 = LinL[:,1] g2 = LinL[:,1] g1 = linspace(0,1,len(g2)) r3 = LinL[:,0] r2 = LinL[:,0] r1 = linspace(0,1,len(r2)) # Creating tuples R = zip(r1,r2,r3) G = zip(g1,g2,g3) B = zip(b1,b2,b3) # Transposing RGB = zip(R,G,B) rgb = zip(*RGB) # Creating dictionary k = ['red', 'green', 'blue'] LinearL = dict(zip(k,rgb)) # And test it with a plot. # In[11]: my_cmap = matplotlib.colors.LinearSegmentedColormap('matteo', LinearL) plt.figure(figsize=(5,4)) plt.pcolor(rand(10,10),cmap=my_cmap) plt.colorbar() plt.show() # ## Reverse it # To make a reversed version, I think we have to reverse rgb and repeat the process. It's a three-element list, where each element is a tuple of tuples. # In[12]: def reverse_colourmap(cmap): reverse = [] for channel in cmap: data = [] for t in channel: data.append((1 - t[0], t[1], t[2])) reverse.append(sorted(data)) return reverse # In[13]: rgb_r = reverse_colourmap(rgb) # In[14]: LinearL_r = dict(zip(k,rgb_r)) my_cmap_r = matplotlib.colors.LinearSegmentedColormap('matteo_r', LinearL_r) plt.figure(figsize=(5,4)) plt.pcolor(rand(10,10),cmap=my_cmap_r) plt.colorbar() plt.show() # The sorted() is important. As well as having the right x values, the coloumap channels must be in order. # # Instead of reversing the finished colourmap, let's do it from the start, with the original code... # In[15]: def gen_cmap(name, array, start, end): b3 = array[:,2] # value of blue at sample n b2 = array[:,2] # value of blue at sample n b1 = linspace(start, end, len(b2)) # position of sample n - ranges from 0 to 1 # Setting up columns for tuples g3 = array[:,1] g2 = array[:,1] g1 = linspace(start, end, len(g2)) r3 = array[:,0] r2 = array[:,0] r1 = linspace(start, end, len(r2)) # Creating tuples R = sorted(zip(r1,r2,r3)) G = sorted(zip(g1,g2,g3)) B = sorted(zip(b1,b2,b3)) # Transposing RGB = zip(R,G,B) rgb = zip(*RGB) # Creating dictionary k = ['red', 'green', 'blue'] LinearL = dict(zip(k,rgb)) return matplotlib.colors.LinearSegmentedColormap(name, LinearL) # In[16]: my_cmap_r = gen_cmap('matteo_r', LinL, 1, 0) plt.figure(figsize=(5,4)) plt.pcolor(rand(10,10),cmap=my_cmap_r) plt.colorbar() plt.show() # And just check this works with the original... # In[17]: my_cmap = gen_cmap('matteo', LinL, 0, 1) plt.figure(figsize=(5,4)) plt.pcolor(rand(10,10),cmap=my_cmap) plt.colorbar() plt.show() # Ha, I just read about numpy.flipud(a) and realized you could just flip the array we started with: # In[18]: my_cmap_r = gen_cmap('matteo_r', np.flipud(LinL), 0, 1) plt.figure(figsize=(5,4)) plt.pcolor(rand(10,10),cmap=my_cmap_r) plt.colorbar() plt.show() # NumPy is awesome. # ## For the impatient # You can also use the built-in cubehelix from matplotlib to produce a similar colourmap: # In[19]: get_ipython().run_line_magic('matplotlib', 'inline') get_ipython().run_line_magic('pylab', 'inline') import numpy as np import matplotlib.pyplot as plt import matplotlib._cm, matplotlib.cm name = "matteohelix" specs = matplotlib._cm.cubehelix(gamma=1.4,s=0.4,r=-0.8,h=2.0) specs_r = matplotlib.cm._reverse_cmap_spec(specs) matplotlib.cm.register_cmap(name=name , data=specs) matplotlib.cm.register_cmap(name=name+"_r", data=specs_r) plt.figure(figsize=(5,4)) plt.pcolor(rand(10,10),cmap=matplotlib.cm.get_cmap(name)) plt.colorbar() plt.show() plt.figure(figsize=(5,4)) plt.pcolor(rand(10,10),cmap=matplotlib.cm.get_cmap(name+'_r')) plt.colorbar() plt.show() # In[ ]: