I clipped a raster file through a shapefile. Now i want to clip that raster file through each features of shapefile. If there are 5 feature in that shp i wanted to clip the raster through those 5 features and i should get 5seperate rasters as per features. I'm using rasterio and fiona for that. Is there a way to do that?
Maybe you can start from here:
import rasterio
import Fiona
# Create a Raster object
raster = rasterio.Raster()
# Get the shapefile data
shapefile = open('shapefile.shp', 'r')
# Get the raster data
rasters = shapefile.shape.getData()
# Loop through the rasters and clip them to the features in the shapefile
for raster in rasters:
# Get the coordinates of the feature in the raster
featureX = raster.GetX()
featureY = raster.GetY()
# Clip the raster to the feature
raster.Clip(featureX, featureY)
This works for me
#import libs
import rasterio
from rasterio import plot
from rasterio.mask import mask
from rasterio.plot import show
from matplotlib import pyplot
import fiona
import shapely
import geopandas as gpd
#raster file path
ras_fp = (r'Classification.tif')
#read shapefile
gdf = gpd.read_file('vill.shp')
# gdf.crs
names = [x for x in gdf['layer']] #get column value from shapefile
#read raster data
ras_data = rasterio.open(ras_fp)
#output path
out_raster_fp = '/output'
#save output files as per shapefile features
for i in range(len(gdf)):
geom = []
coord = shapely.geometry.mapping(gdf)["features"][i]["geometry"]
geom.append(coord)
with rasterio.open(ras_fp)as src:
out_image, out_transform = rasterio.mask.mask(src,geom,crop=True)
out_meta = src.meta
out_meta.update({'driver':'GTiff',
'height':out_image.shape[1],
'width':out_image.shape[2],
'transform':out_transform})
#file_path = ''
with rasterio.open(f'{out_raster_fp}/{names[i]}.tif','w',**out_meta)as
dest:
dest.write(out_image)
Related
I have a shapefile of areas/polygons and I'm trying to show that in a choropleth_mapbox in plotly express. What I want to show is only the boundaries/borders. i.e. the fill colour is transparent!
I've been doing something like this:
import geopandas as gpd
import plotly.express as px
from plotly.offline import plot
import pandas as pd
#read my geo dataframe
geodf = 'path/myShp.shp'
geodf = gpd.read_file(geodf)
# shape file is a different CRS, change to lon/lat GPS co-ordinates
geodf = geodf.to_crs("WGS84")
fig = px.choropleth_mapbox(
geodf.set_index("objectid"),
geojson=geodf.geometry,
locations=geodf.index,
opacity =0.1,
center=dict(lat=52.484, lon=-1.88141),
mapbox_style="carto-positron",
zoom=9,
)
fig.update_layout(coloraxis_showscale=False)
plot(fig)
The above code still shows polygons with filled colours. How can I remove the fill colour and keep only the border?
I was trying to play with the opacity, but that affects both the fill colour and the border! Are they both controlled using the same parameters? Can one apply different properties to either?
To help better explain what I'm trying to achieve, I used QGIS to produce something similar to what my code is currently doing (1) and what I'm trying to get to (2), see images below:
1-Current Code:
2-Desired Output:
Thanks in advance!
If all you want are boundary lines, then you can add a geojson layer. Have used other geometry as you geometry is not accessible to me.
import geopandas as gpd
import plotly.express as px
import plotly.graph_objects as go
from shapely.geometry import MultiPolygon
from plotly.offline import plot
import pandas as pd
# read my geo dataframe
geodf = "path/myShp.shp"
# geodf = gpd.read_file(geodf)
geodf = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
# shape file is a different CRS, change to lon/lat GPS co-ordinates
geodf = geodf.to_crs("WGS84")
# create an empty figure with a mapbox trace
fig = go.Figure(go.Scattermapbox())
# now add boundaries we want
fig.update_layout(
coloraxis_showscale=False,
mapbox={
"style":"carto-positron",
"layers": [
{
"source": geodf["geometry"].__geo_interface__,
"type": "line",
"color": "red"
}
]
},
)
I need to use the "description" as my chart or plot title and I cannot find a way to do this in my internet searches. The output from the .nc file variable that has the "description" that I need looks like this:
<class 'netCDF4._netCDF4.Variable'>
float64 M(lat, on)
_FillValue: nan
long_name: Wind Speed at 100m
description: Anomaly for June 2021 vs the previous 30 years
unlimited dimensions:
current shape = (2920, 7200)
My code looks like this:
# -*- coding: utf-8 -*-
"""
#author: U321103
"""
from sys import exit
import netCDF4 as nc4
from netCDF4 import Dataset
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
#from mpl_toolkits.basemap import Basemap, cm
import datetime
from datetime import datetime
import pandas as pd
import xarray as xr
import bottleneck as bn
import cartopy.crs as ccrs
from mpl_toolkits.basemap import Basemap
import os
os.environ["PROJ_LIB"] = 'C:\\Users\\Yury\\anaconda3\\Library\\share'
# -----------------------------------------------------------------------------------------------------------
#
# -----------------------------------------------------------------------------------------------------------
#%matplotlib inline
#The easiest way to read the data is:
path = "//porfiler03/gtdshare/VORTEX/ANOMALY_FILES/anomaly.M.2021.06.vs30y/world.nc"
# Open the NetCDF file
fh = Dataset(path)
#read variables in fh
for var in fh.variables.values():
print(var)
# Get the 100m wind speed
wind100 = fh['M'][:]
#wind100_units = fh['M'].units
# Get the latitude and longitude points
lats = fh.variables['lat'][:]
lons = fh.variables['lon'][:]
# Get some parameters for the Stereographic Projection
lon_0 = lons.mean()
lat_0 = lats.mean()
#m = Basemap(width=25000000,height=12000000,
# resolution='l',projection='lcc',\
# lat_ts=50,lat_0=lat_0,lon_0=lon_0)
m = Basemap(projection='merc',llcrnrlat=-40,urcrnrlat=60,\
llcrnrlon=-180,urcrnrlon=180,lat_ts=20,resolution='c')
# help on coordinates: https://matplotlib.org/basemap/users/merc.html
fh.close()
# Because our lon and lat variables are 1D,
# use meshgrid to create 2D arrays
# Not necessary if coordinates are already in 2D arrays.
lon, lat = np.meshgrid(lons, lats)
xi, yi = m(lon, lat)
# Plot Data
cs = m.pcolor(xi,yi,np.squeeze(wind100))
# Add Grid Lines
m.drawparallels(np.arange(-80., 81., 40.), labels=[1,0,0,0], fontsize=10)
m.drawmeridians(np.arange(-180., 181., 40.), labels=[0,0,0,1], fontsize=10)
# Add Coastlines, States, and Country Boundaries
m.drawcoastlines()
m.drawstates()
m.drawcountries()
# Add Colorbar
cbar = m.colorbar(cs, location='bottom', pad="10%")
#cbar.set_label(wind100_units)
# Add Title
plt.title(' ')
plt.show()
exit()
So, what I need exactly is "Anomaly for June 2021 vs the previous 30 years" to add to the plot below in the line with plt.title() - thank you!
You should add this line of code wind100_description = fh['M'].description somewhere before fh.close(). Then simply do plt.title(wind100_description) instead of plt.title(' '). Also, it's a good practice to remove the imports you don't need, of which you have quite a few :)
I am running this in Databricks but the decision tree image will not display.
%pip install pydot
%pip install pydotplus
# Load libraries
from sklearn.tree import DecisionTreeClassifier
from sklearn import datasets
from IPython.display import Image
from sklearn import tree
import pydotplus
# Load data
iris = datasets.load_iris()
X = iris.data
y = iris.target
# Create DOT data
dot_data = tree.export_graphviz(clf, out_file=None,
feature_names=iris.feature_names,
class_names=iris.target_names)
# Draw graph
graph = pydotplus.graph_from_dot_data(dot_data)
# Show graph
Image(graph.create_png())
I only get this message (no visual):
Out[4]: <IPython.core.display.Image object>
I'm stumped. Thoughts?
Databricks has the worst documentation, and their examples do not work at this time, so I had to come up with my own solution using PIL and Matplotlib.
Here is how I display images in Databricks in Python:
from PIL import Image
import matplotlib.pyplot as plt
def display_image(path, dpi=100):
"""
Description:
Displayes an image
Inputs:
path (str): File path
dpi (int): Your monitor's pixel density
"""
img = Image.open(path)
width, height = img.size
plt.figure(figsize = (width/dpi,height/dpi))
plt.imshow(img, interpolation='nearest', aspect='auto')
i can show the image using image.open, but how do i display from the binary data?
trying to use plot gets: ValueError: x and y can be no greater than 2-D, but have shapes (64,) and (64, 64, 3). this makes sense as that is what the result is supposed to be, but how do i display it?
import pathlib
import glob
from os.path import join
import matplotlib.pyplot as plt
from PIL import Image
import tensorflow as tf
def parse(image): # my like ings, but with .png instead of .jpeg.
image_string = tf.io.read_file(image)
image = tf.image.decode_png(image_string, channels=3)
image = tf.image.convert_image_dtype(image, tf.float32)
image = tf.image.resize(image, [64, 64])
return image
root = "in/flower_photos/tulips"
path = join(root,"*.jpg")
files = sorted(glob.glob(path))
file=files[0]
image = Image.open(file)
image.show()
binary=parse(file)
print(type(binary))
# how do i see this?
#plt.plot(binary) # does not seem to work
#plt.show() # does not seem to work
found a nice pillow tutorial.
from matplotlib import image
from matplotlib import pyplot
from PIL import Image
# load the image
filename='Sydney-Opera-House.jpg'
im = Image.open(filename)
# summarize some details about the image
print(im.format)
print(im.mode)
print(im.size)
# show the image
#image.show()
# load image as pixel array
data = image.imread(filename)
# summarize shape of the pixel array
print(data.dtype)
print(data.shape)
# display the array of pixels as an image
pyplot.imshow(data)
pyplot.show()
I have a plot object of bokeh where I plot sin(x) curve.
from math import *
from io import BytesIO
from bokeh.plotting import (figure, output_file, show)
from bokeh.io import (export_png, export_svgs)
import base64
import numpy as np
plot = figure(plot_width=1000, plot_height=500)
x = np.linspace(-2*np.pi, 2*np.pi, 1000)
y = np.array([sin(i) for i in x])
plot.line(x, y, line_width=1)
Now, instead of saving it to some html file by some name, output_file('sine.html') I want to create a BytesIO() object so that I can further do base64 encoding.
I kindly need community help.
The reason why I desire is in matplotlib I can export an image as BytesIO() object and work with it smoothly rendering it back in Flask or Dash app like this,
figfile = BytesIO()
plt.savefig(figfile, format='png')
plt.clf()
figfile.seek(0)
figdata_png = base64.b64encode(figfile.getvalue())
return figdata_png.decode('UTF-8')
and I want the same applicability with bokeh.
Please guide me with this.
Bokeh provides this functionality in bokeh.io.export.get_screenshot_as_png:
from bokeh.io.export import get_screenshot_as_png
img = get_screenshot_as_png(plot)
img is a PIL image instance which contains the image.
Off-topic: This can also be used to have the plot displayed as a PNG in JupyterLab. Just call get_screenshot_as_png(plot) and you are done.