How may I calculate the centroid of a multipolygon in shapely (not a polygon) - gis

I understand that the centroid of a polygon may be calculated from
from shapely.geometry import Polygon
coordinate_list = [[1,2], [2,3], [5,5]]
output = Polygon(coordinate_list).centroid
However, my coordinate_list is a multiple polygons, e.g. my coordinate_list = [[[1,2], [2,3], [5,5]], [[0,0], [0,1], [1,0]]]
Is there way to do this. Shapely appears to have a multipolygon class but it does not operate the same as the Polygon class.

You can use MultiPolygon().centroid, it's just that you can't pass that coordinate_list directly to MultiPolygon constructor as it:
/../ takes a sequence of exterior ring and hole list tuples /../
/../ also accepts an unordered sequence of Polygon instances /../
https://shapely.readthedocs.io/en/stable/manual.html#collections-of-polygons
# Based on Multipolygon sample,
# https://shapely.readthedocs.io/en/stable/code/multipolygon.py
from matplotlib import pyplot
from shapely.geometry import Polygon, MultiPolygon
from descartes.patch import PolygonPatch
# from https://github.com/shapely/shapely/blob/main/docs/code/figures.py
from figures import BLUE, BLACK, SIZE, set_limits, plot_coords, color_isvalid
fig = pyplot.figure(1, figsize=SIZE, dpi=90)
ax = fig.add_subplot(121)
set_limits(ax, -1, 6, -1, 6)
coordinate_list = [[[1,2], [2,3], [5,5]], [[0,0], [0,1], [1,0]]]
# "constructor takes a sequence of exterior ring and hole list tuples" -
# https://shapely.readthedocs.io/en/stable/manual.html#collections-of-polygons
multi = MultiPolygon([(coordinate_list[0], []), (coordinate_list[1], [])])
# "the constructor also accepts an unordered sequence of Polygon instances"
#multi = MultiPolygon([Polygon(coordinate_list[0]),Polygon(coordinate_list[1])])
plot_coords(ax, multi.centroid, color=BLACK)
for polygon in multi.geoms:
plot_coords(ax, polygon.exterior)
patch = PolygonPatch(polygon, facecolor=BLUE, edgecolor=BLUE, alpha=0.5, zorder=2)
ax.add_patch(patch)

Related

Split a 3D polyline with an equal distance interval

I want to split a 3D polyline with an equal distance interval. A lot of answers work well for a 2D case, e.g. Splitting MultiLine or LineString into equal segments of particular length using GeoPandas and shapely, Shapely was used to split a 2D polyline. However, Shapely is a planar geometry library and z, the height above or below the plane, is ignored in geometric analysis, which can not used to handle a 3D case.
Any suggestion will be appreciate, python example would be better. Thanks again.
The following code is a 3D points input, while getting a 2D distance result.
from shapely.geometry import LineString, Point, MultiPoint
import numpy as np
line = LineString([(0, 0, 0), (2, 1, 1), (3, 2, 2), (3.5, 1, 1), (5, 2, 2)])
distance_delta = 0.9
# generate the equidistant points
distances = np.arange(0, line.length, distance_delta)
points = MultiPoint([line.interpolate(distance) for distance in distances] + [line.boundary.geoms[1]])

MySQL query claims point is not within polygon

I've drawn a polygon which contains a point in Google Maps. But if I pass the coordinates to MySQL to calculate if the point is within the polygon, it returns false.
SELECT ST_Within(
ST_GeomFromText('POINT(8.34047 54.91320)', 4326),
ST_GeomFromText('POLYGON((62.144619879597 10.486242310988,54.622536815923 2.3124141859883,55.403637023919 23.977453248488,62.144619879597 10.486242310988))', 4326)
) AS is_point_within_polygon;
=> returns 0
But the point is obviously within the polygon:
I double-checked that using Python:
import numpy as np
from shapely.geometry import Point
from shapely.geometry.polygon import Polygon
if __name__ == '__main__':
v0 = [62.144619879597, 10.486242310988]
v1 = [54.622536815923, 2.3124141859883]
v2 = [55.403637023919, 23.977453248488]
lats_vect = np.array([v0[0], v1[0], v2[0]])
lons_vect = np.array([v0[1], v1[1], v2[1]])
lats_vect = np.append(lats_vect, lats_vect[0])
lons_vect = np.append(lons_vect, lons_vect[0])
lons_lats_vect = np.column_stack((lons_vect, lats_vect))
polygon = Polygon(lons_lats_vect)
point = Point(8.34047, 54.9132)
print(point.within(polygon))
=> prints True
What's wrong with the MySQL query?
I think there are two issues here:
First with the query. You list polygon in lat-lon order, but the point seems to be in lon-lat order. You probably want
SELECT ST_Within(
ST_GeomFromText('POINT(54.91320 8.34047)', 4326), -- NOTE CHANGE HERE
ST_GeomFromText('POLYGON((62.144619879597 10.486242310988,54.622536815923 2.3124141859883,55.403637023919 23.977453248488,62.144619879597 10.486242310988))', 4326)
) AS is_point_within_polygon;
Even this query returns FALSE, and this is expected in MySQL. 4326 is Geodesic coordinate system, meaning it operates on the spherical Earth, not on this flat map. With geodesic CRS, edges follow the geodesic shortest lines on Earth, not straight lines on flat map, and for really long lines like here and points close to the edge it matter:
Points slightly further North would be within the polygon, e.g. check out
SELECT ST_Within(
ST_GeomFromText('POINT(56 8.34047)', 4326),
ST_GeomFromText('POLYGON((62.144619879597 10.486242310988,54.622536815923 2.3124141859883,55.403637023919 23.977453248488,62.144619879597 10.486242310988))', 4326)
) AS is_point_within_polygon

MaxPooling 1D layer in Trax

How can I code my own MaxPooling_1D layer in google Trax? I understand that current max pooling is based on 2D max pooling.
Here's how I tried using Keras 1d layer
import trax.layers as tl
def computePool(max_pool_1d,in_tensor):
#print(in_tensor)
return max_pool_1d(in_tensor)
def maxPooling1D():
max_pool_1d = tf.keras.layers.GlobalMaxPooling1D()
return tl.Fn('maxPooling1D', lambda x: computePool(max_pool_1d, x))
But this wouldn't go through in the model.
I want to create a layer with pool size = 2
The answer is
tl.MaxPool(pool_size=(2,), strides=(1,), padding='SAME'),

SHAP multiclass summary plot for Deep Explainer

I want to use SHAP summary plot for multiclass classification problem using Deep Explainer. I have 3 classes and for shap_values I got a list of 3 arrays each having (1000,1,24) size. Each array representing a class, I am getting the summary plot for individual class
import shap
background = train_x[np.random.choice(train_x.shape[0], 1000, replace=False)]
explainer = shap.DeepExplainer(model, background)
back= test_x[np.random.choice(test_x.shape[0], 1000, replace=False)]
shap_values = explainer.shap_values(back)
shap.summary_plot(shap_values[0][:,0,:], plot_type = 'bar', feature_names = features)
but when i try to plot all three classes on a single summary plot by this code
shap.summary_plot(shap_values,back_x, plot_type="bar",feature_names = features)
it gives me following error
IndexError: index 12 is out of bounds for axis 0 with size 1
how to plot all the 3 classes on a single summary plot?

Defining a seed value in Branscripts for CNTK sequential machine learning models

This is respect to CNTK brain scripts. I went through [1] to figure out whether there is an option to specify the random seed value, although I couldn't find any (Yes there is an option to set the 'random seed' parameter through the ParameterTensor() function, but if I followed that approach, I might have to explicitly initialize all the LSTM weights separately(defining separate weights for input layer gate, forget layer gate etc. ), instead of using the model sequence as below). Is there any other option available to set the random seed value, preserving the following RNN layered sequence.
nn_Train = {
action = train
BrainScriptNetworkBuilder = {
model = Sequential (
RecurrentLSTMLayer {$stateDim$, usePeepholes = true}:
DenseLayer {$labelDim$, bias=false}
)
z = model (inputs)
inputs=Input($inputDim$) # features
labels=Input($labelDim$)
# loss and metric
ce = SquareError(labels, z)
# node assignment
featureNodes = (inputs)
labelNodes = (labels)
criterionNodes = (ce)
evaluationNodes = (ce)
outputNodes = (z)
}
[1] https://github.com/microsoft/cntk/wiki/Parameters-And-Constants#random-initialization
There isn't a global random seed option for parameters unfortunately. However, you can modify the cntk.core.bs file next to cntk.exe where all the layers are defined to support random seed for the layers you want.