I'm using Matplotlib and Python. I want to draw the union of a group of rectangles.
The rectangles can be connected or disconnected. I want also to assign a different color to the sides in common with other groups knowing that there is no overlapping regions between groups. Do you have any idea?
Thanks for your help.
I added code for more precision, I have tried to make a collection for each group of rectangles and give them same edge color but how to get only one shape (the perimeter of the group of rectangles)?
import numpy as np
import matplotlib
from matplotlib.patches import Rectangle
from matplotlib.collections import PatchCollection
import matplotlib.pyplot as plt
fig=plt.figure()
ax=fig.add_subplot(111)
patches = []
ListCollections=[]
while Cd1:
while Cd2:
patches += Rectangle((x,y), 400, 200)
p = PatchCollection(patches, cmap=None)
p.set_edgecolor('red')
p.set_facecolor(None)
ListCollections.append(p)
patches =[]
for l in ListCollections:
ax.add_collection(p)
plt.show()
Take a look at Shapely. There is an explicit union example http://toblerity.github.com/shapely/manual.html#object.union .
To plot the Shapely geometries you might also want to use https://pypi.python.org/pypi/descartes .
Finally, if the union must be done with matplotlib artists, I implemented the Cohen-Sutherland clipping algorithm for paths just the other day - I believe clipping one polygon with another is the same as taking their union. I'd be happy to share the code if that is the route you decide to go down (but why would you when you have Shapely!).
Related
I want to create a smooth cylinder using matplotlib/pyplot. I've adapted a tutorial online and produced the following minimal example:
from numpy import meshgrid,linspace,pi,sin,cos,shape
from matplotlib import pyplot
import matplotlib.tri as mtri
from mpl_toolkits.mplot3d import Axes3D
u,v = meshgrid(linspace(0,10,10),linspace(0,2*pi,20))
u = u.flatten()
v = v.flatten()
x = u
z = sin(v)
y = cos(v)
tri = mtri.Triangulation(u, v)
fig = pyplot.figure()
ax = fig.add_axes([0,0,1,1],projection='3d')
ax.plot_trisurf(x,y,z,triangles=tri.triangles,linewidth=0)
pyplot.show()
which produces a cylinder. I set linewidth=0 to remove the wireframe, however, there is now the "ghost" of the wireframe because the triangulation has (presumably) been spaced assuming the wireframe is there to fill in the gaps. This looks to be specific to plot_trisurf, because there are other 3d plotting examples (e.g., using plot_surface) which set linewidth=0 without these gaps showing up.
Doing an mtri.Triangulation?, it seems like it might not be possible to "perfectly" fill in the gaps, since it states
>Notes
> -----
> For a Triangulation to be valid it must not have duplicate points,
> triangles formed from colinear points, or overlapping triangles.
One partial solution is to just color the wireframe the same shade of blue, but after I've fixed this problem I also want to add a light source/shading on the surface, which would put me back at square one.
Is there a way to make this work? Or can someone suggest a different approach? Thanks for any help.
ax.plot_trisurf(x,y,z,triangles=tri.triangles,linewidth=0, antialiased=False)
I'm wanting to draw a figure with a hexagonal grid. The end result should look like a honeycomb. However, I'm having trouble getting my hexagons sized correctly using matplotlib.collections.RegularPolyCollection. Can anyone see what I am doing wrong, or offer another solution. I imagine this has been done before, so no need for me to reinvent the wheel.
import matplotlib.pyplot as plt
from matplotlib import collections, transforms
from matplotlib.colors import colorConverter
import numpy as np
# Make some offsets, doing 4 polygons for simplicity here
xyo = [(0,0), (1,0), (0,1), (1,1)]
# length of hexagon side
hexside = 1
# area of circle circumscribing the hexagon
circ_area = np.pi * hexside ** 2
fig, ax = plt.subplots(1,1)
col = collections.RegularPolyCollection(6, np.radians(90), sizes = (circ_area,),
offsets=xyo,transOffset=ax.transData)
ax.add_collection(col, autolim=True)
colors = [colorConverter.to_rgba(c) for c in ('r','g','b','c')]
col.set_color(colors)
ax.autoscale_view()
plt.show()
Whoever struggles with the same issue in 2020+, check out my hexalattice module:
It allows to create hexagonal grids (hexagonal lattices) in 2D with fine control over spatial distribution of the hexagons, circular clop of the lattice and rotations around the central slot.
Usage and graphical output:
from hexalattice.hexalattice import *
hex_centers, _ = create_hex_grid(nx=10,
ny=10,
do_plot=True)
plt.show() # import matplotlib.pyplot as plt
Installation:
'>> pip install hexalattice'
Advanced features
The module allows stacking of few grids, arbitrary grid rotation around its center, advanced control over gaps between the hexagons etc.
Example:
hex_grid1, h_ax = create_hex_grid(nx=50,
ny=50,
rotate_deg=0,
min_diam=1,
crop_circ=20,
do_plot=True)
create_hex_grid(nx=50,
ny=50,
min_diam=1,
rotate_deg=5,
crop_circ=20,
do_plot=True,
h_ax=h_ax)
I was thinking to put a text on my map, like the satellite imagery.
import numpy as np, matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
m = Basemap(resolution='l',projection='geos',lon_0=-75.)
fig = plt.figure(figsize=(10,8))
m.drawcoastlines(linewidth=1.25)
x,y = m(-150,80)
plt.text(x,y,'Jul-24-2012')
However, the text "Jul-24-2012" doesn't show up on my figure.
I guess the reason of this is because the map is not in Cartesian coordinates.
So, could anyone help me to figure out how to do this, please?
The reason that your text didn't show up is that you're trying to plot a point that's invalid for the map projection that you're using.
If you're just wanting to place text at a point in axes coordinates (e.g. the upper left hand corner of the plot) use annotate, not text.
In fact, it's fairly rare that you'll actually want to use text. annotate is much more flexible, and is actually geared towards annotating a plot, rather than just placing text at an x,y position in data coordinates. (For example, even if you want to annotate an x,y position in data coords, you often want the text offset from it by a distance in points instead of data units.)
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
m = Basemap(resolution='l',projection='geos',lon_0=-75.)
fig = plt.figure(figsize=(10,8))
m.drawcoastlines(linewidth=1.25)
#-- Place the text in the upper left hand corner of the axes
# The basemap instance doesn't have an annotate method, so we'll use the pyplot
# interface instead. (This is one of the many reasons to use cartopy instead.)
plt.annotate('Jul-24-2012', xy=(0, 1), xycoords='axes fraction')
plt.show()
I have difficulties in plotting e.g. polygons across the boundaries of a map generated using matplotlib-basemap. In the example below, the map boundary is specified by the dateline. I try to plot a triangle across the dateline by specifying the coordinates of vertices of a triangle. This works fine when all coordinates are within the map, but if they go across the map boundary, basemap performs strange extrapolation, as it seems not to know how to draw the rectangles in the right way.
Right way would mean in my sense that the triangle is drawn until the map boundary and would then continue at the other side of the map.
Below is a minimum code example and a figure illustrating the general problem.
Any ideas how to solve this problem in a general way are highly welcome.
from mpl_toolkits.basemap import Basemap
import matplotlib.pylab as plt
import numpy as np
import matplotlib.path as mpath
import matplotlib.patches as mpatches
import matplotlib as mpl
from matplotlib.collections import PatchCollection
![plt.close('all')
Path = mpath.Path
fig=plt.figure(); ax=fig.add_subplot(121); ax1=fig.add_subplot(122)
def do_plot(ax,lons,lats,title):
patches=\[\]
m = Basemap(projection='robin', resolution='c',lon_0=0.,ax=ax) #todo: how to make it properly work for other projections ???
m.drawmapboundary(fill_color='grey')
m.drawcoastlines()
#--- generate first sample with no problem
x,y=m(lons,lats)
verts = np.asarray(\[x,y\]).T
codes = \[Path.MOVETO,Path.LINETO,Path.LINETO\]
patches.append(mpatches.PathPatch(mpath.Path(verts, codes,closed=True)))
#--- generate collection
cmap = plt.cm.get_cmap('jet', 50); norm = mpl.colors.Normalize(vmin=None, vmax=None) #colorbar mapping
collection = PatchCollection(patches, cmap=cmap,norm=norm, alpha=1.,match_original=False) #construct library of all objects
colors = np.asarray(np.random.random(len(patches)))
collection.set_array(np.array(colors)) #assign data values here
#--- do actual plotting
im=m.ax.add_collection(collection)
ax.set_title(title)
do_plot(ax,\[-10.,0.,20.\],\[30.,50.,20.\],'This works')
do_plot(ax1,\[170,180,-175\],\[30.,50.,20.\],'... and here is the boundary problem')
plt.show()][1]
You cannot get around this problem with Basemap in a simple way. In your line x,y=m(lons,lats) you have transformed the points to map coordinates, and drawing the polygon just draws between those projected points.
You might try using Cartopy, which can do this. This example may help.
I just discovered pyplot.scatter and have been playing with it a bit. I'm having trouble interpreting my results due to the coloring. For example, given my 3 (a,b) sized data arrays dataX, dataY, and dataMag:
import pyplot as plt
import numpy as np
plt.scatter(x=dataX.flat, y=dataY.flat, vmin=np.min(dataMag),
vmax=np.max(dataMag), c=dataMag.flat, lw=1, s=1)
plt.show()
It would be really helpful if there was a way to set the low values in dataMag (i.e. 0) to white and have the colors gradually increase to the maximum color of black, or red, or whatever i don't care. Is there a way to do this?
Thanks in advance!
I think you are looking for the kwarg cmap.
plt.scatter(...,cmap='hot')
Taken from the scipy cookbook:
from pylab import *
from numpy import outer
rc('text', usetex=False)
a=outer(arange(0,1,0.01),ones(10))
figure(figsize=(10,5))
subplots_adjust(top=0.8,bottom=0.05,left=0.01,right=0.99)
maps=[m for m in cm.datad if not m.endswith("_r") ]
maps.sort()
l=len(maps)+1
for i, m in enumerate(maps):
subplot(1,l,i+1)
axis("off")
imshow(a,aspect='auto',cmap=get_cmap(m),origin="lower")
title(m,rotation=90,fontsize=10)
well generate a figure with all the color maps available with your installation. The name with '_r' appeded on the end will give you the same map, with the colors in the opposite direction.
It is also possible to define your own custom color maps