I'm trying to use cartopy to plot several maps and I want to use them offline. Cartopy has a data directory,
import cartopy.config
cartopy.config
{'data_dir': '/home/user/.local/share/cartopy',
'downloaders': {('shapefiles',
'gshhs'): <cartopy.io.shapereader.GSHHSShpDownloader at 0x7f3ee33ee7d0>,
('shapefiles',
'natural_earth'): <cartopy.io.shapereader.NEShpDownloader at 0x7f3ee33ee710>},
'pre_existing_data_dir': '',
'repo_data_dir': '/home/user/bin/virtualenvs/mobi/local/lib/python2.7/site-packages/cartopy/data'}
So I believe that i can download the maps from Natural Earth site. How can I structure this data on this directory so cartopy would not use the internet to plot? And how can I do the same for OpenStreetMap data?
(Partial answer only)
At Natural Earth web site, http://www.naturalearthdata.com/downloads/
, you can find all the downloadable files. For example, this link provides low resolution data: http://www.naturalearthdata.com/downloads/110m-physical-vectors/
One of the data files on that page has this link address: http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/physical/ne_110m_coastline.zip
This piece of code will download that file (if it is not readily available on the computer):-
import cartopy
fname = cartopy.io.shapereader.natural_earth( \
resolution='110m', \
category='physical', \
name='110m_coastline')
fname
is full pathname of the downloaded file.
You dont need to arrange the download location for cartopy. It already has default location that you can find by:
cartopy.config['data_dir'] # usually 'C:\\Users\\username\\.local\\share\\cartopy'
You can check out the files you downloaded and see how they are structured in that location.
Next time when you use cartopy function cartopy.io.shapereader.natural_earth
(with default config) it will use the local files if they are available.
I had Faced similar issue wherein, with cartopy, the plt.gca().coastlines() was triggering the download of a zip file from external server, but the download was failing as internet connectivity was absent.
/home/apps/CARTOPY/0.16.0/lib64/python2.7/site-packages/Cartopy-0.16.0-py2.7-linux-x86_64.egg/cartopy/io/__init__.py:260: DownloadWarning: Downloading: http://naciscdn.org/naturalearth/110m/physical/ne_110m_coastline.zip
warnings.warn('Downloading: {}'.format(url), DownloadWarning)
I manually downloaded the zip file , and extracted under - ~/.local/share/cartopy/shapefiles/natural_earth/physical.
~/.local/share/cartopy/shapefiles/natural_earth/physical> ls
ne_110m_coastline.README.html ne_110m_coastline.cpg ne_110m_coastline.prj ne_110m_coastline.shx
ne_110m_coastline.VERSION.txt ne_110m_coastline.dbf ne_110m_coastline.shp
then after renaming/removing "ne_" prefix from some files, i was able to solve this issue.
~/PLOT_TEST> ls ~/.local/share/cartopy/shapefiles/natural_earth/physical/
110m_coastline.cpg 110m_coastline.dbf 110m_coastline.prj 110m_coastline.shp 110m_coastline.shx ne_110m_coastline.README.html ne_110m_coastline.VERSION.txt
I have prepared a code in where you can download the the shapefiles from natural earth and then convert them into a dataframe. Pay attention, the country coordinates in natural earth are in polygon and multi-polygon format. In the case of dealing with Rivers which are linestring you need to modify the code.
You might need to manipulate the "name" with your desired filename like "coastlines". Find more information in the following link:
https://www.naturalearthdata.com/downloads/
import cartopy.io.shapereader as shpreader
ne_earth_countries = shpreader.natural_earth(resolution = '10m',
category = 'cultural',
name='admin_0_countries')
countries = shpreader.Reader(ne_earth_countries).records()
def extract_geom_meta(country):
coords = np.empty(shape=[0,2])
for geom in country.geometry:
coords = np.append(coords, geom.exterior.coords, axis=0)
country_name = country.attributes["ADMIN"]
return [country_name, coords]
WorldDF = pd.DataFrame([extract_geom_meta(country) for country in countries],
columns=['countries','coordinates'])
CountryDF = pd.concat([pd.DataFrame(WorldDF['coordinates'][country_idx])
for country_idx in range(len(WorldDF))]).reset_index()
CountryDF['Label'] = CountryDF.apply(lambda row: 1 if row['index'] == 0
else 0,axis=1).cumsum()-1
CountryDF['Country'] = CountryDF['Label'].apply(lambda row: WorldDF.countries[row])
CountryDF.rename(columns={0:'Longitude', 1:'Latitude'},inplace=True)
print(CountryDF.head())