I have two polygons (one rectangle and one triangle), I want to have a function (poly_intersect) that gives me the intersection between these two polygons.
related image is here
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
polygon1 = pd.DataFrame([[2,2],[4,2],[4,4],[2,4],[2,2]],columns=['X','Y'])
polygon2 = pd.DataFrame([[1,3],[3,3],[3,6],[1,3]],columns=['X','Y'])
fig, ax = plt.subplots(1,1, figsize=(6, 4))
ax.add_patch(matplotlib.patches.Polygon(polygon1.values,color='blue',alpha=0.5))
ax.add_patch(matplotlib.patches.Polygon(polygon2.values,color='green',alpha=0.5))
ax.axis([0,5,1,7])
vertices = poly_intersect(polygon1,polygon2)
expected output: [[2,3],[3,3],[3,4],[2,4]]
Related
I have a figure object returned by a function.
import numpy as np
from scipy.spatial import Voronoi, voronoi_plot_2d, Delaunay
import shapely.geometry
import shapely.ops
points = np.random.random((20, 2))
print(points)
vor = Voronoi(points)
fig = voronoi_plot_2d(vor, show_vertices=True, show_points=True)
fig.add
plt.show()
print(vor.ridge_points)
print(vor.ridge_points[1,0])
print(vor.ridge_points[1,1])
plt.plot(points[vor.ridge_points[1,0]], points[vor.ridge_points[1,1]])
plt.show()
I would like to overlay fig
on another plot created in the line
plt.plot(points[vor.ridge_points[1,0]], points[vor.ridge_points[1,1]])
Suggestions on how to visualize both the plots in a single figure will be helpful.
You should create a fig, ax object, and pass the ax argument to the voronoi_plot_2d as suggested in the comments by #Jody Klymak, like:
import numpy as np
from scipy.spatial import Voronoi, voronoi_plot_2d, Delaunay
import shapely.geometry
import shapely.ops
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
points = np.random.random((20, 2))
print(points)
vor = Voronoi(points)
voronoi_plot_2d(vor, show_vertices=True, show_points=True, ax=ax)
print(vor.ridge_points)
print(vor.ridge_points[1,0])
print(vor.ridge_points[1,1])
ax.plot(points[vor.ridge_points[1,0]], points[vor.ridge_points[1,1]])
plt.show()
I have a 120mm diameter circular disk, where I measure temperature at 20 different locations. These measurement locations are at random places. I am looking for a way to plot it as in attached desired plot link. When I used tricontour, It just plots the random points. I am unable to find a way to fill the circle as in below attached pic. Is there any other way to plot this? Spent lot of time searching for it with no success.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
data = {"x": [110,50,-85,20,45,0,-80,-30,-105,80], "y":
[0,100,75,-90,20,115,-85,-20,-45,-90],"z":[10,2,6,4,9,12,2,6,4,12]}
x = data['x']
y = data['y']
z = data['z']
f, ax = plt.subplots(1)
plot = ax.tricontourf(x,y,z, 20)
ax.plot(x,y, 'ko ')
circ1 = Circle((0, 0), 120, facecolor='None', edgecolor='r', lw=5)
ax.add_patch(circ1)
f.colorbar(plot)
Example data :
Desired plot:
What I got from tricontour:
There is much data to do a really nice coontour plot, but here is a solution with your data and an example with a substantially larger dataset:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as tri
data = {"x": [110,50,-85,20,45,0,-80,-30,-105,80], "y":
[0,100,75,-90,20,115,-85,-20,-45,-90],"z":[10,2,6,4,9,12,2,6,4,12]}
df = pd.DataFrame(data)
fig = plt.figure()
ax = fig.add_subplot(projection='polar')
ax.set_title("tricontour")
ax.tricontourf(df["x"], df["y"], df["z"],20)
plt.show()
which gives
and for a larger dataframe:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
df= pd.DataFrame(np.random.randint(0,1000,size=(1000, 3)), columns=list('XYZ'))
fig = plt.figure()
ax = fig.add_subplot(projection='polar')
ax.set_title("tricontour")
ax.tricontourf(df["X"], df["Y"], df["Z"],20)
plt.show()
which returns
I want to draw polygons using fill(). How can I draw polygons of different color? It seems to me that I can only use one color. I tried a list with three color values per polygon but I keep getting this error: length of rgba sequence should be either 3 or 4. The only thing that worked is an array with three color values. But this leads to polygons of the same color. Why does something simple as color=np.random.rand(3,num_polygons) not work?
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_axes([0.,0.,1.,1.])
num_polygons = 2
x = np.random.randn(3,num_polygons)
y = np.random.randn(3,num_polygons)
ax.fill(x,y,color=[0.8,0.3,0.2]) # <--- ??
plt.show()
What did I miss?
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_axes([0.,0.,1.,1.])
num_polygons = 2
x = np.random.randn(3,num_polygons)
y = np.random.randn(3,num_polygons)
ax.fill(x,y, 'green')
plt.show()
I have created a point map and overlayed county boundaries on it using python basemap. I have another shapefile which is based on species distribution map of IUCN data(species_13143). I have overlayed that shape file onto the previous map. It worked well. But unfortunately, it didn't fill up the polygons associated with it. I want to fill those polygons by using colors as per this map (I don't mind about colors; single color is ok)
.
I have found the similar question in StackOverflow. But none of that worked in my case. code and relevant image attached here..
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
plt.figure(figsize=(5,10))
map = Basemap(projection = 'merc', resolution = 'h',area_thresh = 0.5, llcrnrlon=79.2643, llcrnrlat=5.3135, urcrnrlon=82.0658, urcrnrlat=9.951)
map.drawcoastlines(linewidth=0.5)
map.drawcountries(linewidth=0.5)
map.fillcontinents(alpha=0.5)
map.drawmapboundary()
map.drawmeridians(np.arange(0, 360, 0.5), labels=[False, False, False, True], linewidth=0.1,)
map.drawparallels(np.arange(-90, 90, 0.5), labels=[False, True, False, False], linewidth=0.1)
#Read district boundaries.
sh_info=map.readshapefile('C:\\Users\\Tharindu\\Downloads\\species_13143\\species_13143',"areas",color='blue')
shp_info = map.readshapefile('C:\\Users\\Tharindu\\downloads\\Compressed\\LKA_adm1',"areas")
for index,row in sightings_dropped.iterrows():
x,y = map(row['longitude'], row['latitude'])
map.plot(x, y, 'green', markersize=7, alpha=0.8,marker='o',markeredgecolor='black')
map.drawmapscale(81.5, 5.8, 80.5, 6, 50)
If I'm understanding this correctly... In essence, all you're looking for is just to fill in a shapefile with whatever color? This is actually listed in the basemap docs.
from matplotlib.collections import PatchCollection
from matplotlib.patches import Polygon
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
patches = []
for info, shape in zip(map.comarques_info, map.comarques):
patches.append( Polygon(np.array(shape), True) )
ax.add_collection(PatchCollection(patches, facecolor= 'm', edgecolor='k', linewidths=1., zorder=2))
I'm a fan of list comprehension:
from matplotlib.collections import PatchCollection
from matplotlib.patches import Polygon
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
patches = [Polygon(np.array(shape), True) for info, shape in zip(m.states_info, m.states)]
ax.add_collection(PatchCollection(patches, facecolor= 'green', edgecolor='k', linewidths=1., zorder=2))
Hopefully this helps and I answer your question.
I am trying to plot a multi-color line using pandas series. I know matplotlib.collections.LineCollection will sharply promote the efficiency.
But LineCollection require line segments must be float. I want to use datatime index of pandas as x-axis.
points = np.array((np.array[df_index.astype('float'), values]).T.reshape(-1,1,2))
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments)
fig = plt.figure()
plt.gca().add_collection(lc)
plt.show()
But the picture can't make me satisfied.
Is there any solution?
To produce a multi-colored line, you will need to convert the dates to numbers first, as matplotlib internally only works with numeric values.
For the conversion matplotlib provides matplotlib.dates.date2num. This understands datetime objects, so you would first need to convert your time series to datetime using series.index.to_pydatetime() and then apply date2num.
s = pd.Series(y, index=dates)
inxval = mdates.date2num(s.index.to_pydatetime())
You can then work with the numeric points as usual , e.g. plotting as Polygon or LineCollection[1,2].
The complete example:
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
from matplotlib.collections import LineCollection
dates = pd.date_range("2017-01-01", "2017-06-20", freq="7D" )
y = np.cumsum(np.random.normal(size=len(dates)))
s = pd.Series(y, index=dates)
fig, ax = plt.subplots()
#convert dates to numbers first
inxval = mdates.date2num(s.index.to_pydatetime())
points = np.array([inxval, s.values]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, cmap="plasma", linewidth=3)
# set color to date values
lc.set_array(inxval)
# note that you could also set the colors according to y values
# lc.set_array(s.values)
# add collection to axes
ax.add_collection(lc)
ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_minor_locator(mdates.DayLocator())
monthFmt = mdates.DateFormatter("%b")
ax.xaxis.set_major_formatter(monthFmt)
ax.autoscale_view()
plt.show()
Since people seem to have problems abstacting this concept, here is a the same piece of code as above without the use of pandas and with an independent color array:
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np; np.random.seed(42)
from matplotlib.collections import LineCollection
dates = np.arange("2017-01-01", "2017-06-20", dtype="datetime64[D]" )
y = np.cumsum(np.random.normal(size=len(dates)))
c = np.cumsum(np.random.normal(size=len(dates)))
fig, ax = plt.subplots()
#convert dates to numbers first
inxval = mdates.date2num(dates)
points = np.array([inxval, y]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, cmap="plasma", linewidth=3)
# set color to date values
lc.set_array(c)
ax.add_collection(lc)
ax.xaxis_date()
ax.autoscale_view()
plt.show()
ImportanceOfBeingErnest's is a very good answer and saved me many hours of work. I want to share how I used above answer to change color based on signal from a pandas DataFrame.
import matplotlib.dates as mdates
# import matplotlib.pyplot as plt
# import numpy as np
# import pandas as pd
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm
Make test DataFrame
equity = pd.DataFrame(index=pd.date_range('20150701', periods=150))
equity['price'] = np.random.uniform(low=15500, high=18500, size=(150,))
equity['signal'] = 0
equity.signal[15:45] = 1
equity.signal[60:90] = -1
equity.signal[105:135] = 1
# Create a colormap for crimson, limegreen and gray and a norm to color
# signal = -1 crimson, signal = 1 limegreen, and signal = 0 lightgray
cmap = ListedColormap(['crimson', 'lightgray', 'limegreen'])
norm = BoundaryNorm([-1.5, -0.5, 0.5, 1.5], cmap.N)
# Convert dates to numbers
inxval = mdates.date2num(equity.index.to_pydatetime())
# Create a set of line segments so that we can color them individually
# This creates the points as a N x 1 x 2 array so that we can stack points
# together easily to get the segments. The segments array for line collection
# needs to be numlines x points per line x 2 (x and y)
points = np.array([inxval, equity.price.values]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
# Create the line collection object, setting the colormapping parameters.
# Have to set the actual values used for colormapping separately.
lc = LineCollection(segments, cmap=cmap, norm=norm, linewidth=2)
# Set color using signal values
lc.set_array(equity.signal.values)
fig, ax = plt.subplots()
fig.autofmt_xdate()
# Add collection to axes
ax.add_collection(lc)
plt.xlim(equity.index.min(), equity.index.max())
plt.ylim(equity.price.min(), equity.price.max())
plt.tight_layout()
# plt.savefig('test_mline.png', dpi=150)
plt.show()