|
| 1 | +Metadata-Version: 2.2 |
| 2 | +Name: ridge_map |
| 3 | +Version: 0.0.6 |
| 4 | +Summary: 1d lines, 3d maps |
| 5 | +Home-page: https://github.com/ColCarroll/ridge_map |
| 6 | +Author: Colin Carroll |
| 7 | + |
| 8 | +License: MIT |
| 9 | +Classifier: Development Status :: 3 - Alpha |
| 10 | +Classifier: Intended Audience :: Developers |
| 11 | +Classifier: License :: OSI Approved :: MIT License |
| 12 | +Classifier: Programming Language :: Python :: 3 |
| 13 | +Classifier: Programming Language :: Python :: 3.5 |
| 14 | +Classifier: Programming Language :: Python :: 3.6 |
| 15 | +Classifier: Programming Language :: Python :: 3.7 |
| 16 | +Description-Content-Type: text/markdown |
| 17 | +License-File: LICENSE |
| 18 | +Requires-Dist: SRTM.py |
| 19 | +Requires-Dist: numpy |
| 20 | +Requires-Dist: matplotlib |
| 21 | +Requires-Dist: scikit-image>=0.14.2 |
| 22 | +Dynamic: author |
| 23 | +Dynamic: author-email |
| 24 | +Dynamic: classifier |
| 25 | +Dynamic: description |
| 26 | +Dynamic: description-content-type |
| 27 | +Dynamic: home-page |
| 28 | +Dynamic: license |
| 29 | +Dynamic: requires-dist |
| 30 | +Dynamic: summary |
| 31 | + |
| 32 | +ridge_map |
| 33 | +========= |
| 34 | + |
| 35 | + |
| 36 | +*Ridge plots of ridges* |
| 37 | +----------------------- |
| 38 | + |
| 39 | +A library for making ridge plots of... ridges. Choose a location, get an elevation map, and tinker with it to make something beautiful. Heavily inspired from [Zach Cole's beautiful art](https://twitter.com/ZachACole/status/1121554541101477889), [Jake Vanderplas' examples](https://github.com/jakevdp/altair-examples/blob/master/notebooks/PulsarPlot.ipynb), and Joy Division's [1979 album "Unknown Pleasures"](https://gist.github.com/ColCarroll/68e29c92b766418b0a4497b4eb2ecba4). |
| 40 | + |
| 41 | +Uses [matplotlib](https://matplotlib.org/), [SRTM.py](https://github.com/tkrajina/srtm.py), [numpy](https://www.numpy.org/), and [scikit-image](https://scikit-image.org/) (for lake detection). |
| 42 | + |
| 43 | +Installation |
| 44 | +------------ |
| 45 | + |
| 46 | +Available on [PyPI](https://pypi.org/project/ridge-map/): |
| 47 | + |
| 48 | +```bash |
| 49 | +pip install ridge_map |
| 50 | +``` |
| 51 | + |
| 52 | +Or live on the edge and install from github with |
| 53 | + |
| 54 | +```bash |
| 55 | +pip install git+https://github.com/colcarroll/ridge_map.git |
| 56 | +``` |
| 57 | + |
| 58 | +You can also make a copy of [this colab](https://colab.research.google.com/drive/1ntwd73haePt3OS5ysz4yGSlhmUecY24O?usp=sharing). |
| 59 | + |
| 60 | +Want to help? |
| 61 | +------------- |
| 62 | + |
| 63 | +- I feel like I am missing something easy or obvious with lake/road/river/ocean detection, but what I've got gets me most of the way there. If you hack on the `RidgeMap.preprocessor` method and find something nice, I would love to hear about it! |
| 64 | +- Did you make a cool map? Open an issue with the code and I will add it to the examples. |
| 65 | + |
| 66 | +Examples |
| 67 | +-------- |
| 68 | + |
| 69 | +The API allows you to download the data once, then edit the plot yourself, |
| 70 | +or allow the default processor to help you. |
| 71 | + |
| 72 | +### New Hampshire by default |
| 73 | + |
| 74 | +Plotting with all the defaults should give you a map of my favorite mountains. |
| 75 | + |
| 76 | +```python |
| 77 | +from ridge_map import RidgeMap |
| 78 | + |
| 79 | +RidgeMap().plot_map() |
| 80 | +``` |
| 81 | + |
| 82 | + |
| 83 | + |
| 84 | +### Download once and tweak settings |
| 85 | + |
| 86 | +First you download the elevation data to get an array with shape |
| 87 | +`(num_lines, elevation_pts)`, then you can use the preprocessor |
| 88 | +to automatically detect lakes, rivers, and oceans, and scale the elevations. |
| 89 | +Finally, there are options to style the plot |
| 90 | + |
| 91 | +```python |
| 92 | +rm = RidgeMap((11.098251,47.264786,11.695633,47.453630)) |
| 93 | +values = rm.get_elevation_data(num_lines=150) |
| 94 | +values=rm.preprocess( |
| 95 | + values=values, |
| 96 | + lake_flatness=2, |
| 97 | + water_ntile=10, |
| 98 | + vertical_ratio=240) |
| 99 | +rm.plot_map(values=values, |
| 100 | + label='Karwendelgebirge', |
| 101 | + label_y=0.1, |
| 102 | + label_x=0.55, |
| 103 | + label_size=40, |
| 104 | + linewidth=1) |
| 105 | +``` |
| 106 | + |
| 107 | + |
| 108 | + |
| 109 | +### Plot with colors! |
| 110 | + |
| 111 | +If you are plotting a town that is super into burnt orange for whatever |
| 112 | +reason, you can respect that choice. |
| 113 | + |
| 114 | +```python |
| 115 | +rm = RidgeMap((-97.794285,30.232226,-97.710171,30.334509)) |
| 116 | +values = rm.get_elevation_data(num_lines=80) |
| 117 | +rm.plot_map(values=rm.preprocess(values=values, water_ntile=12, vertical_ratio=40), |
| 118 | + label='Austin\nTexas', |
| 119 | + label_x=0.75, |
| 120 | + linewidth=6, |
| 121 | + line_color='orange') |
| 122 | +``` |
| 123 | + |
| 124 | + |
| 125 | + |
| 126 | +### Plot with even more colors! |
| 127 | + |
| 128 | +The line color accepts a [matplotlib colormap](https://matplotlib.org/gallery/color/colormap_reference.html#sphx-glr-gallery-color-colormap-reference-py), so really feel free to go to town. |
| 129 | + |
| 130 | +```python |
| 131 | +rm = RidgeMap((-123.107300,36.820279,-121.519775,38.210130)) |
| 132 | +values = rm.get_elevation_data(num_lines=150) |
| 133 | +rm.plot_map(values=rm.preprocess(values=values, lake_flatness=3, water_ntile=50, vertical_ratio=30), |
| 134 | + label='The Bay\nArea', |
| 135 | + label_x=0.1, |
| 136 | + line_color = plt.get_cmap('spring')) |
| 137 | +``` |
| 138 | + |
| 139 | + |
| 140 | + |
| 141 | +### Plot with custom fonts and elevation colors! |
| 142 | + |
| 143 | +You can find a good font [from Google](https://fonts.google.com/), and then get the path to the ttf file [in the github repo](https://github.com/google/fonts/tree/master/ofl). |
| 144 | + |
| 145 | +If you pass a matplotlib colormap, you can specify `kind="elevation"` to color tops of mountains different from bottoms. `ocean`, `gnuplot`, and `bone` look nice. |
| 146 | + |
| 147 | +```python |
| 148 | +from ridge_map import FontManager |
| 149 | + |
| 150 | +font = FontManager('https://github.com/google/fonts/blob/main/ofl/uncialantiqua/UncialAntiqua-Regular.ttf?raw=true') |
| 151 | +rm = RidgeMap((-156.250305,18.890695,-154.714966,20.275080), font=font.prop) |
| 152 | + |
| 153 | +values = rm.get_elevation_data(num_lines=100) |
| 154 | +rm.plot_map(values=rm.preprocess(values=values, lake_flatness=2, water_ntile=10, vertical_ratio=240), |
| 155 | + label="Hawai'i", |
| 156 | + label_y=0.85, |
| 157 | + label_x=0.7, |
| 158 | + label_size=60, |
| 159 | + linewidth=2, |
| 160 | + line_color=plt.get_cmap('ocean'), |
| 161 | + kind='elevation') |
| 162 | +``` |
| 163 | + |
| 164 | + |
| 165 | + |
| 166 | +### How do I find a bounding box? |
| 167 | + |
| 168 | +I have been using [this website](http://bboxfinder.com). I find an area I like, draw a rectangle, then copy and paste the coordinates into the `RidgeMap` constructor. |
| 169 | + |
| 170 | +```python |
| 171 | +rm = RidgeMap((-73.509693,41.678682,-73.342838,41.761581)) |
| 172 | +values = rm.get_elevation_data() |
| 173 | +rm.plot_map(values=rm.preprocess(values=values, lake_flatness=2, water_ntile=2, vertical_ratio=60), |
| 174 | + label='Kent\nConnecticut', |
| 175 | + label_y=0.7, |
| 176 | + label_x=0.65, |
| 177 | + label_size=40) |
| 178 | +``` |
| 179 | + |
| 180 | + |
| 181 | + |
| 182 | +### What about really flat areas? |
| 183 | + |
| 184 | +You might really have to tune the `water_ntile` and `lake_flatness` to get the water right. You can set them to 0 if you do not want any water marked. |
| 185 | + |
| 186 | +```python |
| 187 | +rm = RidgeMap((-71.167374,42.324286,-70.952454, 42.402672)) |
| 188 | +values = rm.get_elevation_data(num_lines=50) |
| 189 | +rm.plot_map(values=rm.preprocess(values=values, lake_flatness=4, water_ntile=30, vertical_ratio=20), |
| 190 | + label='Cambridge\nand Boston', |
| 191 | + label_x=0.75, |
| 192 | + label_size=40, |
| 193 | + linewidth=1) |
| 194 | +``` |
| 195 | + |
| 196 | + |
| 197 | + |
| 198 | +### Can I change the angle? |
| 199 | + |
| 200 | +Yes, you can change the angle at which you look at the map. South to North is 0 degrees, East to West is 90 degrees and so forth with the rest of the compass. I really recommend playing around with this setting because of the really cool maps it can generate. |
| 201 | + |
| 202 | +Play around with `interpolation`, `lock_rotation`, and `crop` to polish out the map. |
| 203 | + |
| 204 | +```python |
| 205 | +rm = RidgeMap((-124.848974,46.292035,-116.463262,49.345786)) |
| 206 | +values = rm.get_elevation_data(elevation_pts=300, num_lines=300, viewpoint_angle=11) |
| 207 | +values=rm.preprocess( |
| 208 | + values=values, |
| 209 | + lake_flatness=2, |
| 210 | + water_ntile=10, |
| 211 | + vertical_ratio=240 |
| 212 | +) |
| 213 | +rm.plot_map(values=values, |
| 214 | + label='Washington', |
| 215 | + label_y=0.8, |
| 216 | + label_x=0.05, |
| 217 | + label_size=40, |
| 218 | + linewidth=2 |
| 219 | +) |
| 220 | +``` |
| 221 | + |
| 222 | + |
| 223 | + |
| 224 | + |
| 225 | +### What about Walden Pond? |
| 226 | + |
| 227 | +It is that pleasant kettle pond in the bottom right of this map, looking entirely comfortable with its place in Western writing and thought. |
| 228 | + |
| 229 | +```python |
| 230 | +rm = RidgeMap((-71.418858,42.427511,-71.310024,42.481719)) |
| 231 | +values = rm.get_elevation_data(num_lines=100) |
| 232 | +rm.plot_map(values=rm.preprocess(values=values, water_ntile=15, vertical_ratio=30), |
| 233 | + label='Concord\nMassachusetts', |
| 234 | + label_x=0.1, |
| 235 | + label_size=30) |
| 236 | +``` |
| 237 | + |
| 238 | + |
| 239 | + |
| 240 | +### Do you play nicely with other matplotlib figures? |
| 241 | + |
| 242 | +Of course! If you really want to put a stylized elevation map in a scientific plot you are making, I am not going to stop you, and will actually make it easier for you. Just pass an argument for `ax` to `RidgeMap.plot_map`. |
| 243 | + |
| 244 | +```python |
| 245 | +import numpy as np |
| 246 | +fig, axes = plt.subplots(ncols=2, figsize=(20, 5)) |
| 247 | +x = np.linspace(-2, 2) |
| 248 | +y = x * x |
| 249 | + |
| 250 | +axes[0].plot(x, y, 'o') |
| 251 | + |
| 252 | +rm = RidgeMap() |
| 253 | +rm.plot_map(label_size=24, background_color=(1, 1, 1), ax=axes[1]) |
| 254 | +``` |
| 255 | + |
| 256 | + |
| 257 | + |
| 258 | +User Examples |
| 259 | +------------- |
| 260 | + |
| 261 | +### Annotating, changing background color, custom text |
| 262 | + |
| 263 | +This example shows how to annotate a lat/long on the map, and updates the color of the label text to allow for a dark background. Thanks to [kratsg](https://github.com/kratsg) for contributing. |
| 264 | + |
| 265 | +```python |
| 266 | +import matplotlib |
| 267 | +import matplotlib.pyplot as plt |
| 268 | +import numpy as np |
| 269 | + |
| 270 | +bgcolor = np.array([65,74,76])/255. |
| 271 | + |
| 272 | +scipp = (-122.060510, 36.998776) |
| 273 | +rm = RidgeMap((-122.087116,36.945365,-121.999226,37.023250)) |
| 274 | +scipp_coords = ((scipp[0] - rm.longs[0])/(rm.longs[1] - rm.longs[0]),(scipp[1] - rm.lats[0])/(rm.lats[1] - rm.lats[0])) |
| 275 | + |
| 276 | +values = rm.get_elevation_data(num_lines=150) |
| 277 | +ridges = rm.plot_map(values=rm.preprocess(values=values, |
| 278 | + lake_flatness=1, |
| 279 | + water_ntile=0, |
| 280 | + vertical_ratio=240), |
| 281 | + label='Santa Cruz\nMountains', |
| 282 | + label_x=0.75, |
| 283 | + label_y=0.05, |
| 284 | + label_size=36, |
| 285 | + kind='elevation', |
| 286 | + linewidth=1, |
| 287 | + background_color=bgcolor, |
| 288 | + line_color = plt.get_cmap('cool')) |
| 289 | + |
| 290 | +# Bit of a hack to update the text label color |
| 291 | +for child in ridges.get_children(): |
| 292 | + if isinstance(child, matplotlib.text.Text) and 'Santa Cruz' in child._text: |
| 293 | + label_artist = child |
| 294 | + break |
| 295 | +label_artist.set_color('white') |
| 296 | + |
| 297 | +ridges.text(scipp_coords[0]+0.005, scipp_coords[1]+0.005, 'SCIPP', |
| 298 | + fontproperties=rm.font, |
| 299 | + size=20, |
| 300 | + color="white", |
| 301 | + transform=ridges.transAxes, |
| 302 | + verticalalignment="bottom", |
| 303 | + zorder=len(values)+10) |
| 304 | + |
| 305 | +ridges.plot(*scipp_coords, 'o', |
| 306 | + color='white', |
| 307 | + transform=ridges.transAxes, |
| 308 | + ms=6, |
| 309 | + zorder=len(values)+10) |
| 310 | +``` |
| 311 | + |
| 312 | +#### Updated Annotation and Custom Text Color |
| 313 | +The above code still works, but now there is a simplified method (Shown Below) that will produce the same image. |
| 314 | + |
| 315 | +```python |
| 316 | +import matplotlib.pyplot as plt |
| 317 | +import numpy as np |
| 318 | + |
| 319 | +from ridge_map import RidgeMap |
| 320 | + |
| 321 | +bgcolor = np.array([65,74,76])/255. |
| 322 | + |
| 323 | +rm = RidgeMap((-122.087116,36.945365,-121.999226,37.023250)) |
| 324 | +values = rm.get_elevation_data(num_lines=150) |
| 325 | +values = rm.preprocess( |
| 326 | + values=values, |
| 327 | + lake_flatness=1, |
| 328 | + water_ntile=0, |
| 329 | + vertical_ratio=240 |
| 330 | +) |
| 331 | + |
| 332 | +rm.plot_map( |
| 333 | + values=values, |
| 334 | + label='Santa Cruz\nMountains', |
| 335 | + label_x=0.75, |
| 336 | + label_y=0.05, |
| 337 | + label_size=36, |
| 338 | + label_color='white', |
| 339 | + kind='elevation', |
| 340 | + linewidth=1, |
| 341 | + background_color=bgcolor, |
| 342 | + line_color = plt.get_cmap('cool') |
| 343 | +) |
| 344 | + |
| 345 | +rm.plot_annotation( |
| 346 | + label='SCIPP', |
| 347 | + coordinates=(-122.060510, 36.998776), |
| 348 | + x_offset=0.005, |
| 349 | + y_offset=0.005, |
| 350 | + label_size=20, |
| 351 | + annotation_size=6, |
| 352 | + color='white', |
| 353 | + background=False |
| 354 | +) |
| 355 | +``` |
| 356 | + |
| 357 | + |
| 358 | +Elevation Data |
| 359 | +-------------- |
| 360 | + |
| 361 | +Elevation data used by `ridge_map` comes from NASA's [Shuttle Radar Topography Mission](https://www2.jpl.nasa.gov/srtm/) (SRTM), high resolution topographic data collected in 2000, and released in 2015. SRTM data are sampled at a resolution of 1 arc-second (about 30 meters). SRTM data is provided to `ridge_map` via the python package `SRTM.py` ([link](https://github.com/tkrajina/srtm.py)). SRTM data is not available for latitudes greater than N 60° or less than S 60°: |
| 362 | + |
| 363 | + |
| 364 | + |
| 365 | + |
0 commit comments