import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

%matplotlib inline

mpl.rcParams['figure.figsize'] = (13,9) # change default figure size

"""
Explanation: Today's meeting started with a question.

I have a colorbar such as this:

How can I get a colorbar to look like in the figure below?


0. some necessary imports and fake data
End of explanation
"""


cmap1 = 'Blues'

"""
Explanation: We will start with the colormap used in the original question.
End of explanation
"""


x = np.arange(0, np.pi, 0.1)
y = np.arange(0, 2*np.pi, 0.1)
xx, yy = np.meshgrid(x, y)
zz = np.clip(6*(np.cos(xx) * np.sin(yy) + np.random.rand(*xx.shape)*np.cos(yy)), 0, 5.5)

"""
Explanation: In the absence of the data used in the given figure, we create a random array:
End of explanation
"""


fig, ax = plt.subplots(figsize=(12, 1))
cb = mpl.colorbar.ColorbarBase(ax, orientation='horizontal', cmap=cmap1)

"""
Explanation: 1. Customizing a colorbar
The first part of the problem is the colorbar appearance: colour steps, tick labels, etc. We use a mpl.colorbar.ColorbarBase() instance, because it allows us to show a colorbar without an actual mappable object.
End of explanation
"""


col_levels = np.arange(0,6.5,0.5) # sequence from 0 to 6 with step 0.5
tick_loc = np.arange(0,7,1) # sequence from 0 to 6 with step 1
fmt = '%1.2f' # tick labels format with two decimal places

fig, ax = plt.subplots(figsize=(12, 1))
cb = mpl.colorbar.ColorbarBase(ax, cmap=cmap1,
                               boundaries=col_levels,
                               ticks=tick_loc,
                               format=fmt,
                               orientation='horizontal')
cb.ax.tick_params(labelsize=20)

"""
Explanation: Thus we got a simple colorbar with smooth colour range for levels between 0 and 1.
Next, with a bunch of keywords we can achieve the desired appearance.
End of explanation
"""


cbkw = dict(ticks=tick_loc, format=fmt, orientation='vertical')

fig, ax = plt.subplots()
p = ax.contourf(x, y, zz, cmap=cmap1, levels=col_levels)
cb1 = fig.colorbar(p, ax=ax, **cbkw)
cb1.ax.tick_params(labelsize=20)

"""
Explanation: Now, to apply these settings to a data plot, we use a method colorbar() instead of the base colorbar class. We also put colour levels and colour map name in the contourf(). Other keywords are passed as before, but let's pack them into a dictinary.
End of explanation
"""


def myplot(cmap=cmap1):
    """Test a colormap on random data with other params being the same"""
    fig, ax = plt.subplots()
    p = ax.contourf(x, y, zz, cmap=cmap, levels=col_levels)
    cb1 = fig.colorbar(p, ax=ax, **cbkw)
    cb1.ax.tick_params(labelsize=20)

"""
Explanation: We will use this plot for other examples below, so let's make a function of it.
End of explanation
"""


cmap2 = 'gist_stern_r'

myplot(cmap2)

"""
Explanation: 1.2 Colour map
The second part of the question is about a colours sequence used to present the data, i.e. the choice of the colormap.
Let's check if the colormap is available here: http://matplotlib.org/examples/color/colormaps_reference.html
Yes, luckily, it is available under the name 'gist_stern'. We will add '_r' at the end to reverse it. Check it out!
End of explanation
"""


super_random_color_sequence = ['r', (0,0,1), '0.2', 'yellow', '#0044AB']
cmap3 = mpl.colors.ListedColormap(super_random_color_sequence)

myplot(cmap3)

"""
Explanation: But what if you want to customize the colormap or even create your own one? There are several ways to do this. Below are some of the easiest examples.
1.2.1 colormap from a list of colors
The simplest way is to use a sequence of colours. As you can see, any form of colour is valid here, whether it's letter, hex, tuple of RGB values, white/black ratio or just a name.
End of explanation
"""


c_white_trans = mpl.colors.colorConverter.to_rgba('w', alpha=0.0)
cmap4 = mpl.colors.LinearSegmentedColormap.from_list('some_name_for_this_cmap',
                                                    [c_white_trans, '#770000', 'red', 'yellow'], 64)

"""
Explanation: 1.2.2 LinearSegmentedColormap
Another way is to use LinearSegmentedColormap() instance, specifically it's method of generating a colormap from a list of colours. The advantage here is that the resulting colormap is evenly transitions between given colours.
For this example we also use a trick to create a transparent colour. This can be useful for showing several layers of data simultaneously.
End of explanation
"""


fig, ax = plt.subplots()
# First plot
p1 = ax.contourf(x, y, xx, cmap='viridis')
cb1 = fig.colorbar(p1, ax=ax, orientation='vertical', label='data1', pad=0.05)
# Second plot
p2 = ax.contourf(x, y, zz, cmap=cmap4, levels=col_levels)
cb2 = fig.colorbar(p2, ax=ax, label='data2', **cbkw)
cb2.ax.tick_params(labelsize=20)

"""
Explanation: To demonstrate the colour transparency we overlay two plots:
End of explanation
"""


import seaborn as sns
try:
    sns.color_palette('jet')
except ValueError as e:
    print(e)

"""
Explanation: 1.2.3 And kids, remember to avoid the rainbow or jet colormaps!
End of explanation
"""


HTML(html)

"""
Explanation: Further reading

http://matplotlib.org/examples/api/colorbar_only.html
http://matplotlib.org/examples/pylab_examples/custom_cmap.html
https://wxster.com/blog/2015/12/using-two-filled-contour-plots-simultaneously-in-matplotlib
End of explanation
"""


