I have a geotiff raster data sets with elevation data init and i want to plot it in specific area, such as 60°E - 70° E ,70°S - 80°E.
I have a bit of code from here,but the pcolormesh seem couldn't plot my geotif.it's all red. picture. The picture is shown by imshow as really picture
When I try to make a plot with this code below:
path = "F:\\Mosaic_h1112v28_ps.tif"
dataset = gdal.Open(path)
data = dataset.ReadAsArray()
x0, dx, dxdy, y0, dydx, dy = dataset.GetGeoTransform()
nrows, ncols = data.shape
londata = np.linspace(x0, x0+dx*ncols)
latdata = np.linspace(y0, y0+dy*nrows)
lons, lats = np.meshgrid(lonarray, latarray)
fig = plt.figure(figsize=(8, 8))
m = Basemap(projection='lcc', lon_0=67.5, lat_0=-68.5, height=950000,
width=580000, resolution='h')
m.drawcoastlines()
x, y = m(lons, lats)
Then i dont know how to continue it . I just want to use imshow, but the imshow dont specify area(lat/lon).
I will really appreciate your help.
It's a good question, here is my solution.
Required packages: georaster with its dependencies (gdal, etc).
Data for demo purposes downloadable from http://dwtkns.com/srtm/
import georaster
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
fig = plt.figure(figsize=(8,8))
# full path to the geotiff file
fpath = r"C:\\path_to_your\geotiff_file\srtm_57_10.tif" # Thailand east
# read extent of image without loading
# good for values in degrees lat/long
# geotiff may use other coordinates and projection
my_image = georaster.SingleBandRaster(fpath, load_data=False)
# grab limits of image's extent
minx, maxx, miny, maxy = my_image.extent
# set Basemap with slightly larger extents
# set resolution at intermediate level "i"
m = Basemap( projection='cyl', \
llcrnrlon=minx-2, \
llcrnrlat=miny-2, \
urcrnrlon=maxx+2, \
urcrnrlat=maxy+2, \
resolution='i')
m.drawcoastlines(color="gray")
m.fillcontinents(color='beige')
# load the geotiff image, assign it a variable
image = georaster.SingleBandRaster( fpath, \
load_data=(minx, maxx, miny, maxy), \
latlon=True)
# plot the image on matplotlib active axes
# set zorder to put the image on top of coastlines and continent areas
# set alpha to let the hidden graphics show through
plt.imshow(image.r, extent=(minx, maxx, miny, maxy), zorder=10, alpha=0.6)
plt.show()
The resulting plot:
Edit1
My original answer places focus on how to plot simple geotiff image on the most basic projection with Basemap. A better answer was not possible without access to all required resources (i.e. geotiff file).
Here I try to improve my answer.
I have clipped a small portion from whole world geotiff file. Then reproject (warp) it to LCC projection specifications defined by Basemap() to be used. All the process were done with GDAL softwares. The resulting file is named "lcc_2.tiff". With this geotiff file, the plotting of the image is done with the code below.
The most important part is that geotiff file must have the same coordinate system (same projection) as the projection used by Basemap.
import georaster
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
fig = plt.figure(figsize=(8,8))
m = Basemap(projection='lcc', lon_0=67.5, lat_0=-68.5, \
height=950000, width=580000, resolution='h')
m.drawcoastlines()
m.fillcontinents(color='beige')
image = georaster.SingleBandRaster( "lcc_2.tiff", latlon=False)
plt.imshow(image.r, extent=image.extent, zorder=10, alpha=0.6)
plt.show()
The output map:
Here is my solution.
1. Import GEOTIF file and transform it into 2-D array data
from osgeo import gdal
pathToRaster = r'./xxxx.tif'
raster = gdal.Open(pathToRaster, gdal.GA_ReadOnly)
data = raster.GetRasterBand(1).ReadAsArray()
data = data[::-1]
2. Plot it using Pcolormesh
kk = plt.pcolormesh(data,cmap = plt.cm.Reds,alpha = 0.45, zorder =2)
You can use rioxarray
import rioxarray as rio
ds = rio.open_rasterio(path)
# Example lat lon range for subset
geometries = [
{
'type': 'Polygon',
'coordinates': [[
[33.97301017665958, -118.45830810580743],
[33.96660083660732, -118.37455741054782],
[33.92304171545437, -118.37151348516299],
[33.915042933806724, -118.42909440702563]
]]
}
]
clipped = ds.rio.clip(geometries)
clipped.plot()
Related
The current question is somewhat similar to a resampling question on:
Resample question on Stackoverflow
However, my specific problem is that I only have a partial satellite image and not the full image. As a result, I'm not sure how to proceed. Here's what I've tried so far:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
def transform_extent_pts(extent_pts, map_proj, pt_crs):
xul, yul = map_proj.transform_point(
x = extent_pts[0],
y = extent_pts[3],
src_crs = pt_crs)
xlr, ylr = map_proj.transform_point(
x = extent_pts[1],
y = extent_pts[2],
src_crs = pt_crs)
return [xul, xlr, ylr, yul]
sat_image1 = ROOT
df = plt.imread(sat_image1)
# re-project to Mercator
map_proj = ccrs.Mercator()
# Image extent in Geostationary coordinates:
data_crs = ccrs.Geostationary(central_longitude=0.0)
ax2 = plt.axes(projection=data_crs)
img_extent_sat = ax2.get_extent(crs=data_crs)
img_extent_sat = [1.03*x for x in img_extent_sat]
#img_extent_sat=[-32.150361957, 30.150361957, 7.150361956, 42.150361956]
# Convert to Mercator
img_extent_merc = transform_extent_pts(img_extent_sat, map_proj, ccrs.Geodetic())
plt.close()
fig = plt.figure(figsize=(10,10))
ax = plt.axes(projection=map_proj)
ax.coastlines(color='blue')
ax.gridlines(color='black', alpha=0.5, linestyle='--', linewidth=0.75, draw_labels=True)
# Map extent in degrees (PlateCarree) coordinates:
map_extent_deg = (50., -20., -40., 40.) # African continent
map_extent_deg = (-31, 38.009232, 2.880476, 42)
# Convert to Mercator
map_extent_merc = transform_extent_pts(map_extent_deg, map_proj, ccrs.Geodetic())
ax.set_extent(map_extent_merc, map_proj)
plt.imshow(df, origin='upper', transform=data_crs, extent=img_extent_sat)
The main issue I'm facing is that the projection of my data seems to be incorrect, and there might also be a small misalignment. I'm now wondering how I can change the projection of my data. Could you provide some guidance on how to accomplish this?
I've tried a few things, but unfortunately the image is only available in PNG format. The "transform" function, such as using "geostationary," doesn't seem to work with this format. Are there any other options available? Can the projection be changed afterwards, or is that not possible? I assume that the exact coordinates can be obtained by shifting the image.
Perhaps the two red dots can be helpful. I know their coordinates, and they should align with the two white squares:
plt.plot(sta_lon, sta_lat, marker='o', color='red', markersize=8,
alpha=0.7, transform=ccrs.Geodetic())
plt.text(sta_lon, sta_lat+0.25, sta_name, ha='center', fontsize=18,
color='red', transform=ccrs.Geodetic())
I am trying to get a DEM raster to line up with a shapefile in Python, but it will not show up no matter what I do. This is for lab exercise, the entire rest of the exercise relies on these lining up, as I will be extracting data from the raster and polygon layers to a point layer.
I know how to do all this "by hand" in ArcGIS, but the point of the exercise is to use R or Python (the professor did an example with R, but we can use whichever, and I have been learning Python the past couple of months for a work project). In the class notes, he says that both files are in EPSG 3847, but the shapefile was missing the CRS, so I added the CRS to it in geopandas.
The DEM appears to be EPSG 3006 (even though it was supposed to be in 3847), so I tried converting it to EPSG 3847 and it still does not show up. So then I tried going the other way and converting the shapefile to EPSG 3006, which did not help either.
import contextily as cx
import geopandas as gpd
import rasterio
from rasterio.plot import show
from rasterio.crs import CRS
from rasterio.plot import show as rioshow
import matplotlib.pyplot as plt
#data files
abisveg = gpd.read_file(r'/content/drive/MyDrive/Stackoverflow/Sweden/abisveg_polygon.shp')
abisveg_3847 = abisveg.set_crs(epsg = 3847)
abisveg_3006 = abisveg_3847.to_crs(epsg = 3006)
src = rasterio.open(r'/content/drive/MyDrive/Stackoverflow/Sweden/nh_75_6.tif')
DEM = src.read()
### creating plot grid
fig = plt.figure(figsize = (20,20), constrained_layout = True)
gs = fig.add_gridspec(1,3)
ax1 = fig.add_subplot(gs[0,0])
ax2 = fig.add_subplot(gs[0,1], sharex = ax1, sharey = ax1)
ax3 = fig.add_subplot(gs[0,2], sharex = ax1, sharey = ax1)
### Plot 1 - Basemap Only
abisveg_3006.plot(ax = ax1, color = 'none')
cx.add_basemap(ax1, crs = 3006)
ax1.set_aspect('equal')
ax1.set_title("Basemap of AOI")
### Plot 2 - DEM
# abisveg_3847.plot(ax = ax2, color = 'none')
show(DEM, ax=ax2, cmap = "Greys")
cx.add_basemap(ax2, crs = 3006)
ax2.set_aspect('equal')
ax2.set_title('Digitial Elevation Model of AOI')
### Plot 3 - Vegetation Types
abisveg_3006.plot(ax = ax3, column = "VEGKOD", cmap = "viridis")
cx.add_basemap(ax3, crs = 3006)
ax3.set_aspect('equal')
ax3.set_title("Vegetation Types")
3 Panel map with missing DEM:
https://i.imgur.com/taG2U9Q.jpg
Trying to plot the files in Matplotlib has not worked, b/c they do not align at all. I am using contextily for the basemap, and have set the basemap CRS to EPSG 3847 (or 3006, depending on which version of the GIS files I was using). The shapefile shows up in the correct location no matter the projection, but the Raster does not show up. What's weird is that if I open everything up in ArcGIS, it all lines up correctly.
If I plot just the DEM all by itself, it shows up, though I don't know where on the earth it is plotting.
fig = plt.figure(figsize = (10,10), constrained_layout = True)
show(DEM, cmap = "Greys")
DEM just by itself:
https://i.imgur.com/KyYu7jc.jpg
I have my code in a colab notebook here:
https://colab.research.google.com/drive/1VAZ3dgf0QS2PPBOl8KJ2FXtB2oRj0qJ8?usp=share_link
The files are here:
https://drive.google.com/drive/folders/1t-xvpIcLOIR9uYXOguJ7KyKqt7wuYSNc?usp=share_link
You could give EOmaps a try... it uses matplotlib/cartopy for plotting and handles re-projecting the data and shapes to the plot-crs
from pathlib import Path
from eomaps import Maps
import geopandas as gpd
p = Path(r"path to the data folder")
# read shapefile
abisveg = gpd.read_file(p / 'abisveg_polygon.shp').set_crs(epsg = 3847)
# create a map in epsg=3006
m = Maps(crs=3006, figsize=(10, 8))
# add stamen-terrain basemap
m.add_wms.OpenStreetMap.add_layer.stamen_terrain()
# plot shapefile (zorder=2 to be on top of the DEM)
m.add_gdf(abisveg, column=abisveg.VEGKOD, cmap="viridis", ec="k", lw=0.2, alpha=0.5, zorder=2)
# plot DEM
m2 = m.new_layer_from_file.GeoTIFF(p / "nh_75_6.tif", cmap="Greys", zorder=1)
m.ax.set_extent((589913.0408156103, 713614.6619114348, 7495264.310799116, 7618965.93189494),
Maps.CRS.epsg(3006))
Using the OSMnx library, I'm trying to draw lines as polygons on top of a base map (with per-defined coordinates not adhering to the underlying network), but with no luck. I'm certain that the coordinates I have are inside of the boundary, and I get no error when adding them.
Here's my current code, which generates the base map and also adds a multi polygon layer below the network. So it's possible to add polygons, which makes me think there might a projection issue with my coordinates, but I haven't had any luck setting different projections.
Any help would be much appreciated!
import matplotlib.pyplot as plt
from descartes import PolygonPatch
from shapely.geometry import Polygon, MultiPolygon
import osmnx as ox
ox.config(log_console=True, use_cache=True)
ox.__version__
def plot(geometries):
# get the place shape
gdf = ox.gdf_from_place('Copenhagen Municipality,Denmark')
gdf = ox.project_gdf(gdf)
# get the street network, with retain_all=True to retain all the disconnected islands' networks
G = ox.graph_from_place('Copenhagen Municipality,Denmark', network_type='drive', retain_all=True)
G = ox.project_graph(G)
fig, ax = ox.plot_graph(G, fig_height=10, show=False, close=False, edge_color='#777777')
# Add shape from gdf
for geometry in gdf['geometry'].tolist():
if isinstance(geometry, (Polygon, MultiPolygon)):
if isinstance(geometry, Polygon):
geometry = MultiPolygon([geometry])
for polygon in geometry:
patch = PolygonPatch(polygon, fc='#cccccc', ec='k', linewidth=3, alpha=0.1, zorder=-1)
ax.add_patch(patch)
# Add lines:
for geometry in geometries:
if isinstance(geometry, (Polygon, MultiPolygon)):
if isinstance(geometry, Polygon):
geometry = MultiPolygon([geometry])
for polygon in geometry:
patch = PolygonPatch(polygon, fc='#148024', ec='#777777', linewidth=10, alpha=1, zorder=2)
ax.add_patch(patch)
plt.savefig('images/cph.png', alpha=True, dpi=300)
plot(geometries)
geometries is a list which contains polygons like these:
POLYGON ((55.6938796 12.5584122, 55.6929711 12.5585957, 55.6921317 12.5579927, 55.6916918 12.5564539, 55.6909246 12.5553629, 55.6901215 12.554119, 55.6891181 12.5531433, 55.6881469 12.5526575, 55.687502 12.5538862, 55.6866445 12.5530816, 55.6856769 12.5524416, 55.6848185 12.5515929, 55.6838506 12.551074, 55.6829915 12.5504047, 55.6821492 12.5498124, 55.6812104 12.5492503, 55.680311 12.5486803, 55.6792187 12.547724, 55.6783172 12.5472156, 55.6774282 12.5466767, 55.6765291 12.5461124, 55.6755652 12.5453961, 55.6747743 12.5445313, 55.6738159 12.5439029, 55.673417 12.5454132, 55.6733398 12.5470051, 55.6731045 12.5486561, 55.6726013 12.5501493, 55.6727833 12.5520672, 55.6716717 12.5525378, 55.6706619 12.5528382, 55.6698239 12.5521737))
POLYGON ((55.6693768 12.5509383, 55.6684025 12.5511539, 55.6677405 12.5500371, 55.6668188 12.5501435, 55.6658323 12.550075, 55.665264 12.5487917, 55.6649187 12.5473085, 55.6645313 12.5457653))
In geopandas dataframes, the geo-coordinates are (longitude, latitude). Here is a simple demonstration code that plots some sample data.
import geopandas as gpd
import pandas as pd
import matplotlib.pyplot as plt
import osmnx as ox
from shapely import wkt #need wkt.loads
# simple plot of OSM data
gdf = ox.gdf_from_place('Copenhagen Municipality,Denmark')
gdf = gpd.GeoDataFrame(gdf, crs={'init': 'epsg:4326'}) #set CRS
ax1 = gdf.plot(color='lightgray') # grab axis as `ax1` for reuse
# prep the polygons to plot on the axis `ax1`
# use (longitude latitude), and the last point must equal the 1st
pgon1 = "POLYGON((12.5584122 55.6938796, 12.5585957 55.6929711, 12.5579927 55.6921317, 12.5564539 55.6916918, 12.5553629 55.6909246, 12.554119 55.6901215, 12.5531433 55.6891181, 12.5526575 55.6881469, 12.5538862 55.687502, 12.5530816 55.6866445, 12.5524416 55.6856769, 12.5515929 55.6848185, 12.551074 55.6838506, 12.5504047 55.6829915, 12.5498124 55.6821492, 12.5492503 55.6812104, 12.5486803 55.680311, 12.547724 55.6792187, 12.5472156 55.6783172, 12.5466767 55.6774282, 12.5461124 55.6765291, 12.5453961 55.6755652, 12.5445313 55.6747743, 12.5439029 55.6738159, 12.5454132 55.673417, 12.5470051 55.6733398, 12.5486561 55.6731045, 12.5501493 55.6726013, 12.5520672 55.6727833, 12.5525378 55.6716717, 12.5528382 55.6706619, 12.5521737 55.6698239, 12.5584122 55.6938796))"
pgon2 = "POLYGON((12.5509383 55.6693768, 12.5511539 55.6684025, 12.5500371 55.6677405, 12.5501435 55.6668188, 12.550075 55.6658323, 12.5487917 55.665264, 12.5473085 55.6649187, 12.5457653 55.6645313, 12.5509383 55.6693768))"
# create dataframe of the 2 polygons
d = {'col1': [1, 2], 'wkt': [pgon1, pgon2]}
df = pd.DataFrame( data=d )
# make geo-dataframe from it
geometry = [wkt.loads(pgon) for pgon in df.wkt]
gdf2 = gpd.GeoDataFrame(df, \
crs={'init': 'epsg:4326'}, \
geometry=geometry)
# plot it as red polygons
gdf2.plot(ax=ax1, color='red', zorder=5)
The output plot:
I want to plot the average daily temperature from the NOAA Earth System Research Laboratory's Physical Sciences Division onto a map created with matplotlib's Basemap.
The dataset can be download as a netCDF-file from here.
My problem is, however, that Basemap seems not to store the center (or boundary box) coordinates of the map as the subsequent overplot only fills part of the map, see the following figure:
The code to generate the figure is as follows:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import netCDF4
# to check whether a file exists (before downloading it)
import os.path
import sys
fig1, ax1 = plt.subplots(1,1, figsize=(8,6) )
temperature_fname = 'air.sig995.2016.nc'
url = 'https://www.esrl.noaa.gov/psd/thredds/fileServer/Datasets/ncep.reanalysis.dailyavgs/surface/{0}'.format( temperature_fname)
if not os.path.isfile( temperature_fname ):
print( "ERROR: you need to download the file {0}".format(url) )
sys.exit(1)
# read netCDF4 dataset
tmprt_dSet = netCDF4.Dataset( temperature_fname )
# extract (copy) the relevant data
tmprt_vals = tmprt_dSet.variables['air'][:] - 273.15
tmprt_lat = tmprt_dSet.variables['lat'][:]
tmprt_lon = tmprt_dSet.variables['lon'][:]
# close dataset
tmprt_dSet.close()
# use the Miller projection
map1 = Basemap( projection='mill', resolution='l',
lon_0=0., lat_0=0.
)
# draw coastline, map-boundary
map1.drawcoastlines()
map1.drawmapboundary( fill_color='white' )
# draw grid
map1.drawparallels( np.arange(-90.,90.,30.), labels=[1,0,0,0] )
map1.drawmeridians( np.arange(-180.,180.,60.),labels=[0,0,0,1] )
# overplot temperature
## make the longitude and latitude grid projected onto map
tmprt_x, tmprt_y = map1(*np.meshgrid(tmprt_lon,tmprt_lat))
## make the contour plot
CS1 = map1.contourf( tmprt_x, tmprt_y, tmprt_vals[0,:,:],
cmap=plt.cm.jet
)
cbar1 = map1.colorbar( CS1, location='right' )
cbar1.set_label( r'$T$ in $^\circ$C')
plt.show()
Note: if I set lon_0=180 everything looks fine (it is just not the center position I would like to have)
I have the feeling that the solution is pretty obvious and I would appreciate any hint pointing me into that direction.
As commented, the data is aranged from 0 to 360 instead of -180 to 180. So you would need to
map the range between 180 and 360 degrees to -180 to 0.
move the second half of the data in front of the first half, such that it is sorted ascendingly.
Adding the following piece of code in between your data extraction and the plotting function would do that.
# map lon values to -180..180 range
f = lambda x: ((x+180) % 360) - 180
tmprt_lon = f(tmprt_lon)
# rearange data
ind = np.argsort(tmprt_lon)
tmprt_lon = tmprt_lon[ind]
tmprt_vals = tmprt_vals[:, :, ind]
Complete code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import netCDF4
# read netCDF4 dataset
tmprt_dSet = netCDF4.Dataset('data/air.sig995.2018.nc')
# extract (copy) the relevant data
tmprt_vals = tmprt_dSet.variables['air'][:] - 273.15
tmprt_lat = tmprt_dSet.variables['lat'][:]
tmprt_lon = tmprt_dSet.variables['lon'][:]
# close dataset
tmprt_dSet.close()
### Section added ################
# map lon values to -180..180 range
f = lambda x: ((x+180) % 360) - 180
tmprt_lon = f(tmprt_lon)
# rearange data
ind = np.argsort(tmprt_lon)
tmprt_lon = tmprt_lon[ind]
tmprt_vals = tmprt_vals[:, :, ind]
##################################
fig1, ax1 = plt.subplots(1,1, figsize=(8,6) )
# use the Miller projection
map1 = Basemap( projection='mill', resolution='l',
lon_0=0., lat_0=0. )
# draw coastline, map-boundary
map1.drawcoastlines()
map1.drawmapboundary( fill_color='white' )
# draw grid
map1.drawparallels( np.arange(-90.,90.,30.), labels=[1,0,0,0] )
map1.drawmeridians( np.arange(-180.,180.,60.),labels=[0,0,0,1] )
# overplot temperature
## make the longitude and latitude grid projected onto map
tmprt_x, tmprt_y = map1(*np.meshgrid(tmprt_lon,tmprt_lat))
## make the contour plot
CS1 = map1.contourf( tmprt_x, tmprt_y, tmprt_vals[0,:,:],
cmap=plt.cm.jet
)
cbar1 = map1.colorbar( CS1, location='right' )
cbar1.set_label( r'$T$ in $^\circ$C')
plt.show()
This is challenging. I split the data array into 2 parts. The first part spans from 0° to 180°E longitude. The second part lying on the west side of 0° need longitude shift of 360°. Colormap must be normalized and applied to get common reference colors. Here is the working code and the resulting plot:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import netCDF4
import matplotlib as mpl
#import os.path
#import sys
fig1, ax1 = plt.subplots(1,1, figsize=(10,6) )
temperature_fname = r'.\air.sig995.2018.nc'
# read netCDF4 dataset
tmprt_dSet = netCDF4.Dataset( temperature_fname )
# extract (copy) the relevant data
shift_val = - 273.15
tmprt_vals = tmprt_dSet.variables['air'][:] + shift_val
tmprt_lat = tmprt_dSet.variables['lat'][:]
tmprt_lon = tmprt_dSet.variables['lon'][:]
# prep norm of the color map
color_shf = 40 # to get better lower range of colormap
normalize = mpl.colors.Normalize(tmprt_vals.data.min()+color_shf, \
tmprt_vals.data.max())
# close dataset
#tmprt_dSet.close()
# use the Miller projection
map1 = Basemap( projection='mill', resolution='i', \
lon_0=0., lat_0=0.)
# draw coastline, map-boundary
map1.drawcoastlines()
map1.drawmapboundary( fill_color='white' )
# draw grid
map1.drawparallels( np.arange(-90.,90.,30.), labels=[1,0,0,0] )
map1.drawmeridians( np.arange(-180.,180.,60.), labels=[0,0,0,1] )
# overplot temperature
# split data into 2 parts at column 73 (longitude: +180)
# part1 (take location as is)
beg_col = 0
end_col = 73
grdx, grdy = np.meshgrid(tmprt_lon[beg_col:end_col], tmprt_lat[:])
tmprt_x, tmprt_y = map1(grdx, grdy)
CS1 = map1.contourf( tmprt_x, tmprt_y, tmprt_vals[0,:, beg_col:end_col],
cmap=plt.cm.jet, norm=normalize)
# part2 (longitude is shifted -360 degrees, but -359.5 looks better)
beg_col4 = 73
end_col4 = 144
grdx, grdy = np.meshgrid(tmprt_lon[beg_col4:end_col4]-359.5, tmprt_lat[:])
tmprt_x, tmprt_y = map1(grdx, grdy)
CS4 = map1.contourf( tmprt_x, tmprt_y, tmprt_vals[0,:, beg_col4:end_col4],
cmap=plt.cm.jet, norm=normalize)
# color bars CS1, CS4 are the same (normalized), plot one only
cbar1 = map1.colorbar( CS1, location='right' )
cbar1.set_label( r'$T$ in $^\circ$C')
plt.show()
The resulting plot:
Both answers posted so far are a solution to my question (thank you, ImportanceOfBeingErnest and swatchai).
I thought, however, that there must be a simpler way to do this (and by simple I mean some Basemap utility). So I looked again into the documentation [1] and found something which I overlooked so far: mpl_toolkits.basemap.shiftgrid. The following two lines need to be added to the code:
from mpl_toolkits.basemap import shiftgrid
tmprt_vals, tmprt_lon = shiftgrid(180., tmprt_vals, tmprt_lon, start=False)
Note that the second line has to be added before the meshgrid call.
[1] https://matplotlib.org/basemap/api/basemap_api.html
I have a gamma-ray maps (image with surface brightness) in fits format as also .hpx as output by the Aladin converter.
I wish to compute the angular power spectrum. How do I create a file readable by
healpy.anafast?
I seem to be getting the data format wrong (TypeErrors).
One of the Gamma Ray images I tried was the Fermi Galactic Diffuse. The file
is a public LAT Galactic diffuse map named gll_iem_v02_P6_V11_DIFFUSE.fit on:
http://fermi.gsfc.nasa.gov/ssc/data/access/lat/BackgroundModels.html
I have pasted the code below as I use it, but it is essentially the script called plot_wmap_power_spectra on astroml:
"""
WMAP power spectrum analysis with HealPy
----------------------------------------
This demonstrates how to plot and take a power spectrum of the WMAP data
using healpy, the python wrapper for healpix. Healpy is available for
download at the `github site <https://github.com/healpy/healpy>`_
"""
# Author: Jake VanderPlas <vanderplas#astro.washington.edu>
# License: BSD
# The figure is an example from astroML: see http://astroML.github.com
import numpy as np
from matplotlib import pyplot as plt
# warning: due to a bug in healpy, importing it before pylab can cause
# a segmentation fault in some circumstances.
import pylab
import healpy as hp
###
from astroML.datasets import fetch_wmap_temperatures
###
#------------------------------------------------------------
# Fetch the data
###
wmap_unmasked = fetch_wmap_temperatures(masked=False)
#PredictedSurfaceFluxFromModelMap = np.arange(hp.read_map('PredictedSurfaceFluxFromModelMap.hpx[1]'))
PredictedSurfaceFluxFromModelMap = hp.read_map('gll_iem_v02_p6_V11_DIFFUSE.fit',dtype=np.float,verbose=True)
#PredictedSurfaceFluxFromModelMap = hp.read_map('all.fits',dtype=np.float,verbose=True)
#cl_out = hp.read_cl('PredictedSurfaceFluxFromModelMap.hpx',dtype=np.float)#,verbose=True)
wmap_masked = fetch_wmap_temperatures(masked=True)
###
white_noise = np.ma.asarray(np.random.normal(0, 0.062, wmap_masked.shape))
len(cl_out)
#------------------------------------------------------------
# plot the unmasked map
fig = plt.figure(1)
#hp.mollview(wmap_unmasked, min=-1, max=1, title='Unmasked map',
# fig=1, unit=r'$\Delta$T (mK)')
########----------------
##hp.mollview(PredictedSurfaceFluxFromModelMap, min=-1, max=1, title='Unmasked map',
## fig=1, unit=r'$\Delta$T (mK)')
########----------------
#------------------------------------------------------------
# plot the masked map
# filled() fills the masked regions with a null value.
########----------------
#fig = plt.figure(2)
#hp.mollview(wmap_masked.filled(), title='Masked map',
# fig=2, unit=r'$\Delta$T (mK)')
########----------------
#------------------------------------------------------------
# compute and plot the power spectrum
########----------------
#cl = hp.anafast(wmap_masked.filled(), lmax=1024)
cl = hp.anafast(PredictedSurfaceFluxFromModelMap, lmax=1024)
#cl = cl_out
########----------------
ell = np.arange(len(cl))
cl_white = hp.anafast(white_noise, lmax=1024)
fig = plt.figure(3)
ax = fig.add_subplot(111)
ax.scatter(ell, ell * (ell + 1) * cl,
s=4, c='black', lw=0,
label='data')
ax.scatter(ell, ell * (ell + 1) * cl_white,
s=4, c='gray', lw=0,
label='white noise')
ax.set_xlabel(r'$\ell$')
ax.set_ylabel(r'$\ell(\ell+1)C_\ell$')
ax.set_title('Angular Power (not mask corrected)')
ax.legend(loc='upper right')
ax.grid()
ax.set_xlim(0, 1100)
plt.show()
I have uploaded your map also to Figshare, where is likely to be available in the future.
Once you have the map in HEALPix format, it is easy to just read it with healpy:
import healpy as hp
m = hp.ma(hp.read_map("gll_iem_v02_p6_V11_DIFFUSE.hpx"))
Mask NaN pixels:
m.mask = np.isnan(m)
Plot it:
hp.mollview(m, min=-1e-5, max=1e-5, xsize=2000)
title("gll_iem_v02_p6_V11_DIFFUSE")
Compute and plot the angular power spectrum:
plt.loglog(hp.anafast(m))
See also a IPython notebook: http://nbviewer.ipython.org/7553252