How to draw a png-osm-map with coordinates - python

I want to create a map with several given points in Python. For this I want to use Basemap from matplotlib. It works well, but I don't know how to get a proper background map.
How can I import an OSM map? Or should I use a different mapping package? I just want to create a raster map and save it as png.

This not my solution; I have pasted it from the question because the asker doesn't have enough reputation to answer his own question.
I found a solution:
Using imshow within Basemap includes an png into the plot as
background image. To obtain the right background image, I used the
export feature of OSM with boundaries taken from the Basemap
constructor:
m = Basemap(llcrnrlon=7.4319, urcrnrlat=52.0632, urcrnrlon=7.848, llcrnrlat=51.8495,
resolution='h', projection='merc')
im = plt.imread('background.png')
m.imshow(im, interpolation='lanczos', origin='upper')

I found some accessible basemap imagery from NASA GIBS tileserver. You might be able to use the same method for other tileservers.
http://earthdata.nasa.gov/wiki/main/index.php/GIBS_Supported_Clients#Script-level_access_to_imagery
Thi Uses GDAL's gdal_translate in a python subshell:
import subprocess
import matplotlib.pyplot
import mpl_toolkits.basemap
l,u,r,d=(7.4319,52.0632,7.848,51.8495)
subprocess.call ('gdal_translate -of GTiff -outsize 400 400 -projwin {l} {u} {r} {d} TERRA.xml Background.tif'.format(l=l,u=u,r=r,d=d),shell=True )
im=matplotlib.pyplot.imread('Background.tif')
m = mpl_toolkits.basemap.Basemap(llcrnrlon=l, urcrnrlat=u, urcrnrlon=r, llcrnrlat=d,
resolution='h', projection='merc')
m.imshow(im, interpolation='lanczos', origin='upper')
matplotlib.pyplot.show()
This needs the TERRA.xml file from the above link, though you can inline the XML as well.

Related

How to create a Wind Rose in KML format (google earth) using Python

I need to create a Wind Rose KML file to be opened in google earth with as (similar to) the following pictures.
I can create wind roses using windrose python module, like this one:
And I know how to create KML points and lines in python using simplekml module like this one:
Does anyone know any package capable of doing that?
or any idea of how to do it?
If you use matplotlib when draw windrose, try to save the fig with following opthons.
plt.axis('off')
plt.savefig('windrose.png', bbox_inches='tight', pad_inches=0, transparent=True)
After you got the image file, generate ground overlay code in kml.
import simplekml
kml = simplekml.Kml(open=1)
doc = kml.newdocument(name='sample', open=1, visibility=0)
ground = doc.newgroundoverlay(name='windrose example')
ground.icon.href = 'windrose.png'
ground.altitudemode = simplekml.AltitudeMode.absolute
ground.altitude = 500.0
ground.latlonbox.north = 38.031368255615234
ground.latlonbox.south = 37.11344909667969
ground.latlonbox.east = 141.5791015625
ground.latlonbox.west = 140.4208984375
ground.visibility = 1
kml.save('sample.kml')
Each values are need to adjust.
Please refer following, if you'd like to know more about ground overlay.
https://developers.google.com/kml/documentation/altitudemode#absolute
Open Google Earth.
Draw a static picture\chart like wanted one over a map.
Save it into a KML file.
Open with any text editor.
It must show you an example which lead you to generate a valid KML with your data.

Python mapping: plotting an electoral boundary over a street map?

I would have thought this would be so simple it would be almost example 1 in any mapping documentation. But it seems not... I want to map the boundary of an electorate over a street map, using cartopy. I can download the GIS data of the electorates in either MapInfo or ShapeFile form. When I tried to do this a year ago, the only way I could find to do it was to extract the lat/long coordinates of the MapInfo polygon, and plot them with matplotlib.
I'm trying to be a bit more elegant this year. With the MapInfo file, I can isolate my particular electorate with
import geopandas as gpd
v = gpd.read_file('VicMaps/vic-july-2018-mid-mif/E_VIC18.MIF')
cg = v.loc[7].geometry
My efforts to extract a particular single boundary from a shapefile are given below.
The other issue is that when I try to run this in jupyter, attempts at plotting a map causes the kernel (python 3.4) to crash.
There must be examples of this somewhere, but so far I haven't found an example which works with my data. This is what I have so far, cobbled together from various helpful answers to other people's questions:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.io.shapereader import Reader
from cartopy.io.img_tiles import OSM
shp = Reader('VicMaps/E_AUGFN3_region.shp')
fig = plt.figure(figsize=(16,16))
tiler = OSM()
ax = plt.axes(projection=tiler.crs)
ax.set_extent([144.956158, 145.085398, -37.813662, -37.690999])
for r, g in zip(shp.records(), shp.geometries()):
if r.attributes['Elect_div'] == 'Cooper':
ax.add_geometries(g, ccrs.Geodetic())
plt.show()
But what happens is that the kernel just dies "unexpectedly".
If anybody could point me in the direction of a solution, I'd be delighted! Also: I'm not wedded to cartopy; if there's a better package I'll use it.
Thanks!

Plot RGB satellite image in Cassini-Soldner projection on a map in Python

I have a geo-referenced RGB satellite image from the MODIS instrument in geotiff format. What is the correct way to plot it on a map using cartopy and preserve the RGB colours?
The main obstacle I guess is the projection of the image which is Cassini-Soldner:
import numpy as np
from osgeo import gdal, osr
ds = gdal.Open('modis_201303261252_rgb.tif')
print(ds.GetGeoTransform())
(-1669791.8857914428, 250.0, 0.0, 1669792.327327792, 0.0, -250.0)
proj = ds.GetProjection()
inproj = osr.SpatialReference()
inproj.ImportFromWkt(proj)
print(inproj)
PROJCS["unnamed",
GEOGCS["unnamed ellipse",
DATUM["unknown",
SPHEROID["unnamed",6378137,0]],
PRIMEM["Greenwich",0],
UNIT["degree",0.0174532925199433]],
PROJECTION["Cassini_Soldner"],
PARAMETER["latitude_of_origin",72],
PARAMETER["central_meridian",-4],
PARAMETER["false_easting",0],
PARAMETER["false_northing",0],
UNIT["metre",1,
AUTHORITY["EPSG","9001"]]]
I tried to follow this example https://ocefpaf.github.io/python4oceanographers/blog/2015/03/02/geotiff/
and use cartopy to define a projection from an EPSG code. So I googled for Cassini-Soldner EPSG code (9806), but cartopy's ccrs.epsg() doesn't recognise it.
I want to use plt.imshow() method, but I'm a bit confused what to use as a projection keyword when the axis is created and what to pass as a transform= argument in imshow.
(I would add this as a comment but I need 50 rep.)
Out of interest, how did you come by a Cassini projection MODIS RGB?
An alternative is to use a Cartopy pull request I've made, which allows for the time dimension to be used with GeoAxes.add_wmts(), so that you can pull MODIS RGB imagery tiles for your time from NASA GIBS straight into a Cartopy GeoAxes: https://github.com/SciTools/cartopy/pull/788
Edit: this feature is in v0.15

Importing an svg file into a matplotlib figure

I like to produce high quality plots and therefore avoid rasterized graphics as much as possible.
I am trying to import an svg file on to a matplotlib figure:
import matplotlib.pyplot as plt
earth = plt.imread('./gfx/earth.svg')
fig, ax = plt.subplots()
im = ax.imshow(earth)
plt.show()
This works with png perfectly. Can somebody tell me how to do it with svg or at least point my to proper documentation.
I know that a similar question has been asked (but not answered): here. Has anything changed since?
P.S. I know that I could just export a high resolution png and achieve a similar effect. This is not the solution I am looking for.
Here is the image I would like to import:
.
Maybe what you are looking for is svgutils
import svgutils.compose as sc
from IPython.display import SVG # /!\ note the 'SVG' function also in svgutils.compose
import numpy as np
# drawing a random figure on top of your SVG
fig, ax = plt.subplots(1, figsize=(4,4))
ax.plot(np.sin(np.linspace(0,2.*np.pi)), np.cos(np.linspace(0,2.*np.pi)), 'k--', lw=2.)
ax.plot(np.random.randn(20)*.3, np.random.randn(20)*.3, 'ro', label='random sampling')
ax.legend()
ax2 = plt.axes([.2, .2, .2, .2])
ax2.bar([0,1], [70,30])
plt.xticks([0.5,1.5], ['water ', ' ground'])
plt.yticks([0,50])
plt.title('ratio (%)')
fig.savefig('cover.svg', transparent=True)
# here starts the assembling using svgutils
sc.Figure("8cm", "8cm",
sc.Panel(sc.SVG("./Worldmap_northern.svg").scale(0.405).move(36,29)),
sc.Panel(sc.SVG("cover.svg"))
).save("compose.svg")
SVG('compose.svg')
Output:
to anyone ending up here in 2021...
I'd suggest having a look at the cairosvg package
(conda install -c conda-forge cairosvg or pip3 install cairosvg)
https://cairosvg.org/
import cairosvg
import matplotlib.pyplot as plt
from PIL import Image
from io import BytesIO
img_png = cairosvg.svg2png("... the content of the svg file ...")
img = Image.open(BytesIO(img_png))
plt.imshow(img)
SVG (Scalable Vector Graphics) is a vectorial format, which means the image is not composed of pixels, but instead of relative paths that can be scaled arbitrarily.
NumPy/Matplotlib, as numerics software, only really works with pixel graphics and cannot handle svg. I would suggest first converting the svg file to e.g. a png file by opening and saving it in software such as Inkscape (which is free). Then, open the exported png in Python.
Alternatively, use the wikimedia provided versions of the file in png format on the picture's information page (click on the download button to the right of the picture).
If you really believe you need the vectorial form, well, there is no way to do that. You can always superpose the matplotlib figure on to the figure manually (using the matplotlib Artist to draw on the plot canvas), or through some pycairo magic, and save that. But Matplotlib cannot work directly with svg content.

Python SAC plot w/ grid

I'm required to use the information from a .sac file and plot it against a grid. I know that using various ObsPy functions one is able to plot the Seismograms using st.plot() but I can't seem to get it against a grid. I've also tried following the example given here "How do I draw a grid onto a plot in Python?" but have trouble when trying to configure my x axis to use UTCDatetime. I'm new to python and programming of this sort so any advice / help would be greatly appreciated.
Various resources used:
"http://docs.obspy.org/tutorial/code_snippets/reading_seismograms.html"
"http://docs.obspy.org/packages/autogen/obspy.core.stream.Stream.plot.html#obspy.core.stream.Stream.plot"
The Stream's plot() method actually automatically generates a grid, e.g. if you take the default example and plot it via:
from obspy.core import read
st = read() # without filename an example file is loaded
tr = st[0] # we will use only the first channel
tr.plot()
You may want to play with the number_of_ticks, tick_format and tick_rotationparameters as pointed out in http://docs.obspy.org/packages/autogen/obspy.core.stream.Stream.plot.html.
However if you want more control you can pass a matplotlib figure as input parameter to the plot() method:
from obspy.core import read
import matplotlib.pyplot as plt
fig = plt.figure()
st = read('/path/to/file.sac')
st.plot(fig=fig)
# at this point do whatever you want with your figure, e.g.
fig.gca().set_axis_off()
# finally display your figure
fig.show()
Hope it helps.

Categories