Ridge map plots using Python

I saw this tweet on May 1st:

I’ve seen these plots created before and find them visually very pleasing. I had a look at the github page and was really impressed with what I saw. I thought I would document here a very enjoyable couple of hours I spent creating an animated ridge map in Python. Here’s how I did it.

Installation

To install ridge map open your command prompt – ideally anaconda – and type the following:

pip install ridge_map

Or, you can ‘live dangerously’ to borrow a phrase from the github page and install via

pip install git+git://github.com/colcarroll/ridge_map.git

If you choose this route using anaconda you may need to run the following command first:

conda install -c anaconda git

If this all seems a little alien to you, head over to here where I explain how to get your computer and anaconda working together nicely.

Interestingly, ridge map uses SRTM.py which allows you to parse bounding boxes and coordinates to it and will retrieve elevations values for you! That was new to me and a great discovery.

Your first ridge map

With ridge map installed you can create your first ridge map in 2 lines:

from ridge_map import RidgeMap

RidgeMap().plot_map()

Simple as that.

How do you go about plotting the area of most interest to you?

import matplotlib.pyplot as plt
rm = RidgeMap((-11.337891,49.752880,2.373047,59.377988))
values = rm.get_elevation_data(num_lines=50)
rm.plot_map(values=rm.preprocess(values=values, lake_flatness=4, water_ntile=30, vertical_ratio=50),
            label='UK and Ireland',
            label_x=0.75,
            label_size=20,
            linewidth=1,
            line_color = plt.get_cmap('hsv'),
            kind='elevation')

First you will need to parse a bounding box of your area of interest. The documentation recommends you use this website:

http://bboxfinder.com/

You can just download the area you are interested in once and then play with the different ways of styling it with the different parameters in rm.plot_map. You can colour by elevation and use any of the matplotlib colour ramps to do so. The code above will create a slightly garish ridge map of the UK and Ireland – thanks to matplotlib ‘hsv’ colour ramp!

I have included a couple of examples in this blog’s associated notebook for you to play with, changing parameters etc. What I really want to do is to plot the elevations with a terrain colour ramp. Matplotlib does have such a ramp called ‘terrain’ but…

… I don’t want low lying areas in the image above shaded blue (i.e. water), I want them green. With a bit of searching I found the answer to my question on this stackoverflow post:

https://stackoverflow.com/questions/35920887/select-part-of-the-colormap-plotting-terrain

It’s quite elegant, it creates a truncated ‘terrain’ colourmap by extracting a subset. While it is a little more complex, the code below will create me a ridge map of the UK and Ireland with a nicely scaled colourmap.

##https://stackoverflow.com/questions/35920887/select-part-of-the-colormap-plotting-terrain
%matplotlib inline
from ridge_map import RidgeMap
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
import os

def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100):
    new_cmap = colors.LinearSegmentedColormap.from_list(
           'trunc({n},{a:.2f},{b:.2f})'.format(n=cmap.name, a=minval, b=maxval),
            cmap(np.linspace(minval, maxval, n)))
    return new_cmap    

cmap = plt.get_cmap('terrain')
new_cmap = truncate_colormap(cmap, 0.25, 0.9)
rm = RidgeMap((-11.337891,49.752880,2.373047,59.377988))
values = rm.get_elevation_data()
rm.plot_map(values=rm.preprocess(values=values),
            label='UK and Ireland',
            label_x=0.75,
            label_y=0.7,
            label_size=30,
            linewidth=1,
            line_color = plt.get_cmap(new_cmap),
            kind='elevation')

Giving me this image:

The final thing I wanted to do was to create an animated gif, taking the viewer from a single line image (well, 10) to 100 lines. I created a series of images and stitched them together using imageio.

First I’ll create the set of images:

##https://stackoverflow.com/questions/35920887/select-part-of-the-colormap-plotting-terrain
%matplotlib inline
from ridge_map import RidgeMap
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
import os
def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100):
    new_cmap = colors.LinearSegmentedColormap.from_list(
           'trunc({n},{a:.2f},{b:.2f})'.format(n=cmap.name, a=minval, b=maxval),
            cmap(np.linspace(minval, maxval, n)))
    return new_cmap    

cmap = plt.get_cmap('terrain')
new_cmap = truncate_colormap(cmap, 0.25, 0.9)

rm = RidgeMap((-1.587524,50.558815,1.483154,51.645294))
mydir = r"D:\testing\images2"
os.chdir(mydir)
x = 10
while x < 100:
    values = rm.get_elevation_data(num_lines=x)
    rm.plot_map(values=rm.preprocess(values=values, lake_flatness=4, water_ntile=20, vertical_ratio=40),
                label='South East\nEngland',
                label_y=0.8,
                label_x=0.85,
                label_size=20,
                line_color = plt.get_cmap(new_cmap),
                kind='elevation')

    name = str(x) + ".png"
    plt.savefig(name)
    x = x +10

Essentially the same as the code used previously but this time with a while loop, giving me a directory of images.

Now find all these images (and sort if necessary) and make a gif.

import imageio
import os
mydir = r"D:\testing\images2"
filenames = []
for root, dir, files in os.walk(mydir):
    for file in files:
        if file.endswith((".png")):
            filename1 =(os.path.join(root, file))
            filenames.append(filename1)

print(filenames)    

print()



images = []
for filename in filenames:
    images.append(imageio.imread(filename))
imageio.mimsave(r'D:\testing\movie.gif', images, duration=0.5)

Which should create…

Please do look at the following link for much more detail here

I have adapted and reused scripts. All the credit goes to Colin Carroll for those shown above.

https://colindcarroll.com/

Recap

In this post I have walked though creating ridge maps in Python using the ridge map Python library. We have:

  • Looked at how to install.
  • How to create and adjust the plots to match your area of interest.
  • Displayed the data using a terrain colour ramp.
  • Animated the output.

All the code with further descriptions is available here.

I am a freelancer able to help you with your projects. I offer consultancy, training and writing. I’d be delighted to hear from you. Please check out the books I have written on QGIS 3.4

https://www.packtpub.com/application-development/learn-qgis-fourth-edition

https://www.packtpub.com/application-development/qgis-quick-start-guide


I am @map_andrew on twitter