I am reading data from a csv file and plotting contours using python. The code works but when I check shapefile created, I can see only few contour lines are getting plotted whereas when I check image plot there are many more lines. What is going wrong in this code? I think the cs.collections is creating some problem but I am not able to figure it out.
import os
import numpy as np
import pandas as pd
from matplotlib.mlab import griddata
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
from shapely.geometry import mapping, Polygon, LineString,MultiLineString
import fiona
# set up plot
plt.clf()
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, axisbg='w', frame_on=False)
# grab data
data = pd.read_csv('Filename.csv', sep=',')
norm = Normalize()
# define map extent
lllon = -180
lllat = -90
urlon = 180
urlat = 90
# Set up Basemap instance
m = Basemap(#projection = 'merc',llcrnrlon = lllon, llcrnrlat = lllat, urcrnrlon = urlon, urcrnrlat = urlat,resolution='h', epsg=4326)
# transform lon / lat coordinates to map projection
data['projected_lon'], data['projected_lat'] = m(*(data.CLON.values, data.CLAT.values))
# grid data
numcols, numrows = 100, 100
xi = np.linspace(data['projected_lon'].min(), data['projected_lon'].max(), numcols)
yi = np.linspace(data['projected_lat'].min(), data['projected_lat'].max(), numrows)
xi, yi = np.meshgrid(xi, yi)
# interpolate
x, y, z = data['projected_lon'].values, data['projected_lat'].values, data.PRES.values
zi = griddata(x, y, z, xi, yi)
# contour plot
cs = plt.contour(xi, yi, zi,zorder=4)
plt.show()
lenvar = (len(cs.collections)) #number of contours
print(lenvar)
#print(cs.collections)
lines = [] # Empty list for contour sections
for i in range(lenvar):
n = i
p = cs.collections[i].get_paths()[0]
v = p.vertices # getting the individual verticies as a numpy.ndarray
x = v[:,0] #takes first column
y = v[:,1] #takes second column
line = LineString([(i[0], i[1]) for i in zip(x,y)]) #Defines Linestring
lines.append(line) #appends to list
schema = {'geometry': 'LineString','properties': {'id': 'int'}} # sets up parameter for shapefile
with fiona.open('ConShp.shp', 'w', 'ESRI Shapefile', schema) as c: # creates new file to be written to
for j in range(len(lines)):
l = (lines[j]) # creates variable
print(l)
print(type(l))
c.write({'geometry': mapping(l),'properties': {'id': j},})
data Sample is like:
Lat, Lon, Value
18.73, 26.34, 5000
20.00, 60.00, 7000
Shapefile_plot_in_GIS
Image of Plot in python
Related
I am trying to regrid my .nc data with irregular grid with the following code:
from mpl_toolkits.basemap import Basemap
from netCDF4 import Dataset as NetCDFFile
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import griddata
nc = NetCDFFile('test.nc')
lat = nc.variables['latitude'][:]
lon = nc.variables['longitude'][:]
time = nc.variables['time'][:]
ssi = nc.variables['solar_irradiation'][:]
XI = np.arange(46.025, 56.525, 0.05)
YI = np.arange(5.025, 15.525, 0.05)
lat_new, lon_new = np.meshgrid(XI, YI)
new_grid = griddata((lat, lon), ssi, (lat_new, lon_new), method='linear')
It works fine, there are NaN values at lat/lon boxes which are not in the original file.
Then I want to plot it using Basemap:
map = Basemap(projection='merc', llcrnrlon=-5., llcrnrlat=35., urcrnrlon=30., urcrnrlat=60.,
resolution='i')
map.drawcountries()
map.drawcoastlines()
x, y = map(XI, YI)
rad = map.contourf(x, y, new_grid)
cb = map.colorbar(rad, "bottom", size="10%", pad="10%")
I am receiving following error: IndexError: too many indices for array: array is 1-dimensional, but 2 were indexed. I know that this means, but I have no clue how to change to code so that it worked the same way. Thank you for every help!
I've drawn a contour plot using matplolib and i want to overly this plot over folium map or is there any way to draw contour plot on map using folium
This is my code
import json
import numpy as np
from scipy.interpolate import griddata
from matplotlib import pyplot as plt
f = open('data.json', 'r')
data = json.load(f)
temp = data['temp']
lon = data['lon']
lat = data['lat']
x = np.linspace(min(lon), max(lon), 100)
y = np.linspace(min(lat), max(lat), 100)
X,Y = np.meshgrid(x, y)
Z = griddata((lon, lat), temp, (X, Y), method='cubic')
plt.contour(X,Y, Z)
plt.show()
My data file data.json, below is how my plot looks now i want to plot this over map
it's not clear your geometry is correct, have reversed lat & lon
straight forward with https://pypi.org/project/geojsoncontour/
import json
import numpy as np
from scipy.interpolate import griddata
from matplotlib import pyplot as plt
import geojsoncontour
import geopandas as gpd
f = open('data.json', 'r')
data = json.load(f)
temp = data['temp']
lon = data['lon']
lat = data['lat']
y = np.linspace(min(lon), max(lon), 100)
x = np.linspace(min(lat), max(lat), 100)
X,Y = np.meshgrid(x, y)
Z = griddata((lat, lon), temp, (X, Y), method='cubic')
contour = plt.contour(X,Y, Z)
gdf = gpd.GeoDataFrame.from_features(json.loads(geojsoncontour.contour_to_geojson(
contour=contour,
min_angle_deg=3.0,
ndigits=5,
stroke_width=1))).set_crs("EPSG:4326")
m = gdf.explore(color=gdf["stroke"])
plt.show()
m
I've started working with Basemap, which seems potentially very useful.
If I plot some global data on a latitude/longitude grid as filled contours, it works great: Iff I leave the lat_0 and lon_0 as zero. Once I change the center location, the map moves but the data doesn't. I would be grateful for advice.
I've created a simple version of the code I'm using, with some simple sample data that illustrates the problem. The values should be (are) large at the equator but small at the poles. If you run the code with lat_0 and lon_0 = 0, it works fine. But if you change the center location to a different coordinate, the same pattern/data is presented even though the map has moved.
from mpl_toolkits.basemap import Basemap, cm
import matplotlib.pyplot as plt
import numpy as np
# create data
lat = np.linspace(-90,90,num=180)
lon = np.linspace(-180,180,num=361)
h2o_north = np.linspace(1,65,num=90)
h2o_south = np.flipud(h2o_north)
h2o = np.append(h2o_north,h2o_south)
data = np.transpose(np.tile(h2o,(len(lon),1)))
# create figure and axes instances
fig = plt.figure(figsize=(10,10))
ax = fig.add_axes([0.1,0.1,0.8,0.8])
# create map
m = Basemap(projection='ortho',lon_0=-50,lat_0=50,resolution='l')
# draw coastlines and country boundaries
m.drawcoastlines()
m.drawcountries()
# draw parallels
parallels = np.arange(-90.,90,10.)
m.drawparallels(parallels)
# draw meridians
meridians = np.arange(180.,360.,10.)
m.drawmeridians(meridians)
ny = data.shape[0]
nx = data.shape[1]
lons, lats = m.makegrid(nx, ny) # get lat/lons of ny by nx evenly space grid
x, y = m(lons, lats) # compute map projection coordinates
# draw filled contours.
clevs = np.linspace(0,70,num=281)
cs = m.contourf(x,y,data,clevs,cmap=plt.cm.jet)
# colorbar
cbar = m.colorbar(cs,location='bottom',pad="5%",ticks=np.linspace(0,70,15))
cbar.set_label('Scale of the data')
plt.title('Some global data', fontsize=14)
Use np.meshgrid() to create the meshgrid of lon-lat, then, convert it to projection coordinates, and the data are ready to generate contours and plot.
Here is the working code:
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
# data for z (2D array)
h2o_north = np.linspace(1, 65, num=90)
h2o_south = np.flipud(h2o_north)
h2o = np.append(h2o_north, h2o_south)
data = np.transpose(np.tile(h2o, (len(h2o_north), 1)))
# create figure and axes instances
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot()
# create basemap instance
m = Basemap(projection='ortho', lon_0=-50, lat_0=50, resolution='c', ax=ax)
# create meshgrid covering the whole globe with ...
# conforming dimensions of the `data`
lat = np.linspace(-90, 90, data.shape[0])
lon = np.linspace(-180, 180, data.shape[1])
xs, ys = np.meshgrid(lon, lat) # basic mesh in lon, lat (degrees)
x, y = m(xs, ys) # convert (lon,lat) to map (x,y)
# draw filled contours
clevs = np.linspace(0, np.max(data), 60)
cs = m.contourf(x, y, data, clevs, cmap=plt.cm.jet)
m.drawcoastlines()
m.drawcountries()
m.drawmeridians(range(-180, 180, 30))
m.drawparallels(range(-90, 90, 30))
# draw colorbar
cbar = m.colorbar(cs, location='bottom', pad="5%", ticks=np.linspace(0, np.max(data), 5))
cbar.set_label('Scale of the data')
plt.show()
The resulting plot:
I'm trying to interpolate data within boundaries and plot contour lines (polygons) based on Latitude, longitude, value data from csv files.
Results I want print as geojson.
I'm stuck on the basic contour plot from csv. I really appreciate help here.
This is what I got in this moment but can't make it work.
import numpy as np
import matplotlib.pyplot as plt
data = np.genfromtxt('temp.csv', delimiter=',')
x = data[:1]
y = data[:2]
[x,y] = meshgrid(x,y);
z = data[:3];
plt.contour(x,y,z)
plt.show()
The CSV looks like this
2015-10-28T09:25:12.800Z,51.56325,17.529043333,4.6484375,19.8046875
2015-10-28T09:25:12.900Z,51.56325,17.529041667,4.4921875,19.6875
2015-10-28T09:25:13.000Z,51.563248333,17.529041667,4.453125,19.9609375
2015-10-28T09:25:13.200Z,51.563245,17.529041667,4.140625,19.765625
2015-10-28T09:25:13.300Z,51.563243333,17.529041667,4.609375,19.6484375
2015-10-28T09:25:13.500Z,51.563241667,17.529041667,4.609375,19.53125
2015-10-28T09:25:13.600Z,51.56324,17.529041667,4.4921875,19.375
2015-10-28T09:25:13.700Z,51.563238333,17.529041667,4.4140625,19.765625
2015-10-28T09:25:13.800Z,51.563236667,17.529041667,4.453125,20.234375
2015-10-28T09:25:13.900Z,51.563235,17.529041667,4.3359375,19.84375
2015-10-28T09:25:14.000Z,51.563233333,17.529041667,4.53125,19.453125
2015-10-28T09:25:14.100Z,51.563231667,17.529041667,4.53125,19.8046875
2015-10-28T09:25:14.200Z,51.563228333,17.529041667,4.1796875,19.4921875
2015-10-28T09:25:14.300Z,51.563226667,17.529041667,4.2578125,19.453125
2015-10-28T09:25:14.400Z,51.563225,17.529041667,4.4921875,19.4921875
2015-10-28T09:25:14.500Z,51.563223333,17.529041667,4.375,19.453125
2015-10-28T09:25:14.600Z,51.563221667,17.529041667,4.609375,18.90625
2015-10-28T09:25:14.700Z,51.563218333,17.529041667,4.53125,19.6875
2015-10-28T09:25:14.900Z,51.563215,17.529041667,4.140625,18.75
2015-10-28T09:25:15.000Z,51.563213333,17.529041667,4.453125,18.828125
Column 1 - Latitude
Column 2 - Longitude
Column 3 - Value
For contour lines I need also limits - for example (4.1,4.3,4.6)
I guess there is some mistake in your code (according to your data you shouldn't do x = data[:1] but more x = data[..., 1]).
With your of data, the basic steps I will follow to interpolate the z value and fetch an output as a geojson would require at least the shapely module (and here geopandas is used for the convenience).
import numpy as np
import matplotlib.pyplot as plt
from geopandas import GeoDataFrame
from matplotlib.mlab import griddata
from shapely.geometry import Polygon, MultiPolygon
def collec_to_gdf(collec_poly):
"""Transform a `matplotlib.contour.QuadContourSet` to a GeoDataFrame"""
polygons, colors = [], []
for i, polygon in enumerate(collec_poly.collections):
mpoly = []
for path in polygon.get_paths():
try:
path.should_simplify = False
poly = path.to_polygons()
# Each polygon should contain an exterior ring + maybe hole(s):
exterior, holes = [], []
if len(poly) > 0 and len(poly[0]) > 3:
# The first of the list is the exterior ring :
exterior = poly[0]
# Other(s) are hole(s):
if len(poly) > 1:
holes = [h for h in poly[1:] if len(h) > 3]
mpoly.append(Polygon(exterior, holes))
except:
print('Warning: Geometry error when making polygon #{}'
.format(i))
if len(mpoly) > 1:
mpoly = MultiPolygon(mpoly)
polygons.append(mpoly)
colors.append(polygon.get_facecolor().tolist()[0])
elif len(mpoly) == 1:
polygons.append(mpoly[0])
colors.append(polygon.get_facecolor().tolist()[0])
return GeoDataFrame(
geometry=polygons,
data={'RGBA': colors},
crs={'init': 'epsg:4326'})
data = np.genfromtxt('temp.csv', delimiter=',')
x = data[..., 1]
y = data[..., 2]
z = data[..., 3]
xi = np.linspace(x.min(), x.max(), 200)
yi = np.linspace(y.min(), y.max(), 200)
zi = griddata(x, y, z, xi, yi, interp='linear') # You could also take a look to scipy.interpolate.griddata
nb_class = 15 # Set the number of class for contour creation
# The class can also be defined by their limits like [0, 122, 333]
collec_poly = plt.contourf(
xi, yi, zi, nb_class, vmax=abs(zi).max(), vmin=-abs(zi).max())
gdf = collec_to_gdf(collec_poly)
gdf.to_json()
# Output your collection of features as a GeoJSON:
# '{"type": "FeatureCollection", "features": [{"type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[51.563214073747474,
# (...)
Edit:
You can grab the colors values (as an array of 4 values in range 0-1, representing RGBA values) used by matplotplib by fetching them on each item of the collection with the get_facecolor() method (and then use them to populate one (or 4) column of your GeoDataFrame :
colors = [p.get_facecolor().tolist()[0] for p in collec_poly.collections]
gdf['RGBA'] = colors
Once you have you GeoDataFrame you can easily get it intersected with your boundaries. Use these boundaries to make a Polygon with shapely and compute the intersection with your result:
mask = Polygon([(51,17), (51,18), (52,18), (52,17), (51,17)])
gdf.geometry = gdf.geometry.intersection(mask)
Or read your geojson as a GeoDataFrame:
from shapely.ops import unary_union, polygonize
boundary = GeoDataFrame.from_file('your_geojson')
# Assuming you have a boundary as linestring, transform it to a Polygon:
mask_geom = unary_union([i for i in polygonize(boundary.geometry)])
# Then compute the intersection:
gdf.geometry = gdf.geometry.intersection(mask_geom)
Almost I got what I excepted. Based on mgc answer. I change griddata as you suggest to scipy.interpolate.griddata and interpolation method to nearest. Now its works like I want.
Only last thing that I need is to limit this interpolation to polygon (boundaries) also from geoJson.
The other problem is to export to geojson polygons WITH colors as attributes.
import numpy as np
import matplotlib.pyplot as plt
#from matplotlib.mlab import griddata
from scipy.interpolate import griddata
from geopandas import GeoDataFrame
from shapely.geometry import Polygon, MultiPolygon
def collec_to_gdf(collec_poly):
"""Transform a `matplotlib.contour.QuadContourSet` to a GeoDataFrame"""
polygons = []
for i, polygon in enumerate(collec_poly.collections):
mpoly = []
for path in polygon.get_paths():
try:
path.should_simplify = False
poly = path.to_polygons()
# Each polygon should contain an exterior ring + maybe hole(s):
exterior, holes = [], []
if len(poly) > 0 and len(poly[0]) > 3:
# The first of the list is the exterior ring :
exterior = poly[0]
# Other(s) are hole(s):
if len(poly) > 1:
holes = [h for h in poly[1:] if len(h) > 3]
mpoly.append(Polygon(exterior, holes))
except:
print('Warning: Geometry error when making polygon #{}'
.format(i))
if len(mpoly) > 1:
mpoly = MultiPolygon(mpoly)
polygons.append(mpoly)
elif len(mpoly) == 1:
polygons.append(mpoly[0])
return GeoDataFrame(geometry=polygons, crs={'init': 'epsg:4326'})
data = np.genfromtxt('temp2.csv', delimiter=',')
x = data[..., 1]
y = data[..., 2]
z = data[..., 4]
xi = np.linspace(x.min(), x.max(), num=100)
yi = np.linspace(y.min(), y.max(), num=100)
#zi = griddata(x, y, z, xi, yi, interp='nn') # You could also take a look to scipy.interpolate.griddata
zi = griddata((x, y), z, (xi[None,:], yi[:,None]), method='nearest')
nb_class = [5,10,15,20,25,30,35,40,45,50] # Set the number of class for contour creation
# The class can also be defined by their limits like [0, 122, 333]
collec_poly = plt.contourf(
xi, yi, zi, nb_class, vmax=abs(zi).max(), vmin=-abs(zi).max())
gdf = collec_to_gdf(collec_poly)
#gdf.to_json()
print gdf.to_json()
plt.plot(x,y)
plt.show()
I am trying to plot a contour and quiver plot over a basemap. When I plot, I get no errors, but only the basemap will show. The netcdf file only has one point in it for lat and long, so I had to create a range of coordinates. Any ideas why this is happening?
import netCDF4
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import pylab
from mpl_toolkits.basemap import Basemap
from matplotlib.patches import Polygon
ncfile = netCDF4.Dataset('30JUNE2012_0400UTC.cdf', 'r')
dbZ = ncfile.variables['MAXDBZF']
u = ncfile.variables['UNEW']
v = ncfile.variables['VNEW']
#print u
#print v
#print dbZ
data = dbZ[0,0]
data.shape
#print data.shape
z_index = 0 # z-level you want to plot (0-19)
U = u[0,z_index, :,:] #[time,z,x,y]
V = v[0,z_index, :,:]
lats = np.linspace(35.0, 41.0, data.shape[0])
lons = np.linspace(-81.0,-73.0, data.shape[1])
# create the map
map = Basemap(llcrnrlat=36,urcrnrlat=40,\
llcrnrlon=-80,urcrnrlon=-74,lat_ts=20,resolution='c')
# load the shapefile, use the name 'states'
map.readshapefile('st99_d00', name='states', drawbounds=True)
# collect the state names from the shapefile attributes so we can
# look up the shape obect for a state by it's name
state_names = []
for shape_dict in map.states_info:
state_names.append(shape_dict['NAME'])
ax = plt.gca() # get current axes instance
x,y = map(*np.meshgrid(lats,lons))
levels = np.arange(5,60,3)
c = map.contourf(x,y,data, levels, cmap='jet')
plt.colorbar()
q=plt.quiver(U,V,width=0.002, scale_units='xy',scale=10)
qk= plt.quiverkey (q,0.95, 1.02, 20, '20m/s', labelpos='N')
plt.show()