Adding Labels to a Shapefile Map - matplotlib

I have a shapefile that maps the world to sales territories. The shapefile records lists the sales territory code and name. I would like to be able to add the territory code in the center of the region, but to do using ax.text, I need the center point of the region. Any ideas how to do this?
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import shapefile
from mpl_toolkits.basemap import Basemap as Basemap
from matplotlib.colors import rgb2hex, Normalize
from matplotlib.patches import Polygon
from matplotlib.colorbar import ColorbarBase
from matplotlib.collections import PatchCollection
plt.rcParams['figure.figsize'] = [16,12]
fig = plt.figure()
m = Basemap(llcrnrlon=-121,llcrnrlat=20,urcrnrlon=-62,urcrnrlat=51,
projection='lcc',lat_1=32,lat_2=45,lon_0=-95)
shp_info = m.readshapefile('world_countries_boundary_file_world_2002','countries',drawbounds=True)
sf = shapefile.Reader('territory_map') # Custom file mapping out territories
recs = sf.records()
shapes = sf.shapes()
Nshp = len(shapes)
colors={}
territory_codes=[]
cmap = plt.cm.RdYlGn
# details is a pandas datafile with column "DELTA" that has data to plot
vmin = details.DELTA.min()
vmax = details.DELTA.max()
norm = Normalize(vmin=vmin, vmax=vmax)
for index,row in details.iterrows():
colors[row['TERRITORY_CODE']] = cmap((row['DELTA']-vmin)/(vmax-vmin))[:3]
territory_codes.append(row['TERRITORY_CODE'])
ax = fig.add_subplot(111)
for nshp in range(Nshp):
ptchs = []
pts = np.array((shapes[nshp].points))
prt = shapes[nshp].parts
par = list(prt) + [pts.shape[0]]
for pij in range(len(prt)):
ptchs.append(Polygon(pts[par[pij]:par[pij+1]]))
try:
color = rgb2hex(colors[recs[nshp][0]])
except:
color = 'w' # If no data, leave white (blank)
ax.add_collection(PatchCollection(ptchs, facecolor=color, edgecolor='b', linewidths=.7))
x, y = # Coordinates that are center of region
ax.text(x, y, recs[nshp][0]) # <---- this would be the text to add
# Add colorbar
ax_c = fig.add_axes([0.1, 0.1, 0.8, 0.02])
cb = ColorbarBase(ax_c,cmap=cmap,norm=norm,orientation='horizontal')
cb.ax.set_xlabel('Daily Change, USD')
#Set view to United States
ax.set_xlim(-150,-40)
ax.set_ylim(15,70)
plt.show()
Resulting Map of Code without Territory Names

you're probably looking to take the mean of all the x coordinates and the mean of all the y coordinates of your polygon shape.
I can't test this but it could look something like this:
x,y = pts[0].mean(), pts[1].mean()
or this:
x,y = pts[:,0].mean(), pts[:,1].mean()
depending on the dimensions of your numpy array.

Related

Creating US map with 50 state density and color bar using basemap

I have a dictionary named density, I am trying to create a US state map as the color shows the density of the state. I am trying to replicate this use Basemap (Python) to plot US with 50 states
however I am getting error.
This is my data:
density = {'NY': 648.0,
'FL': 696.0,
'TX': 833.0,
'CA': 927.0,
'PA': 472.0,
'OH': 721.0,
'NJ': 645.0,
'IL': 607.0,
'MI': 570.0,
'AZ': 616.0,
'GA': 799.0,
'MD': 652.0,
'NC': 720.0,
'LA': 546.0,
'TN': 806.0,
'MO': 564.0,
'SC': 574.0,
'VA': 818.0,
'IN': 780.0,
'AL': 619.0,
'MA': 626.0,
'WA': 749.0,
'KY': 680.0,
'WI': 615.0,
'OK': 633.0,
'MN': 743.0,
'IA': 543.0,
'WV': 599.0,
'MS': 695.0,
'AR': 698.0,
'OR': 878.0,
'CO': 782.0,
'NV': 930.0,
'KS': 637.0,
'CT': 1078.0,
'UT': 580.0,
'NM': 667.0,
'NE': 552.0,
'PR': 698.0,
'ME': 702.0,
'ID': 679.0,
'DE': 845.0,
'NH': 668.0,
'RI': 616.0,
'HI': 1131.0,
'DC': 711.0,
'MT': 653.0,
'SD': 495.0,
'ND': 685.0,
'VT': 754.0,
'AK': 1080.0,
'WY': 1028.0,
'VI': 1261.0,
'GU': 889.0}
Here is my code which I get the error.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap as Basemap
from matplotlib.colors import rgb2hex
from matplotlib.patches import Polygon
m = Basemap(llcrnrlon=-119,llcrnrlat=22,urcrnrlon=-64,urcrnrlat=49,
projection='lcc',lat_1=33,lat_2=45,lon_0=-95)
shp_info = m.readshapefile('st99_d00','states',drawbounds=True)
colors={}
statenames=[]
cmap = plt.cm.hot # use 'hot' colormap
vmin = 0; vmax = 450 # set range.
for shapedict in m.states_info:
statename = shapedict['NAME']
if statename not in ['District of Columbia','Puerto Rico']:
pop = popdensity[statename]
colors[statename] = cmap(1.-np.sqrt((pop-vmin)/(vmax-vmin)))[:3]
statenames.append(statename)
ax = plt.gca() # get current axes instance
for nshape,seg in enumerate(m.states):
if statenames[nshape] not in ['Puerto Rico', 'District of Columbia']:
if statenames[nshape] == 'Alaska':
seg = list(map(lambda (x,y): (0.35*x + 1100000, 0.35*y-1300000), seg))
if statenames[nshape] == 'Hawaii':
seg = list(map(lambda (x,y): (x + 5100000, y-900000), seg))
color = rgb2hex(colors[statenames[nshape]])
poly = Polygon(seg,facecolor=color,edgecolor=color)
ax.add_patch(poly)
plt.title('******')
plt.show()
I am confused what I need to do to this code work.
I am new to pyhton, any help and feedback is highly appreciated.
TIA!

Matplotlib: strange minor ticks with log base 2 colorbar

I am plotting some contours with tricontourf. I want the colormap to be scaled in log values and tick labels and colours bounds to be in log base 2. Here's my code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import matplotlib.ticker as ticker
import matplotlib.colors as colors
section = 'T7'
data = np.loadtxt( section + '_values.dat')
x = data[:,0]
y = data[:,1]
z = data[:,2]
triang = tri.Triangulation(x,y)
fig1, ax1 = plt.subplots()
ax1.set_aspect('equal')
bounds = [2.**-1,2.**1,2**3,2**5,2**7,2**9]
norm = colors.LogNorm()
formatter = ticker.LogFormatter(2)
tcf = ax1.tricontourf(triang, z, levels = bounds, cmap='hot_r', norm = norm )
fig1.colorbar(tcf, format=formatter)
plt.show()
And here's the result:
What are thos ugly minor ticks and how do I get rid of them?
Using Matplotlib 3.3.0 an Mac OS
You could use cb.ax.minorticks_off() to turn off the minor tick and cb.ax.minorticks_on() to turn it on.
cb = fig1.colorbar(tcf, format=formatter)
cb.ax.minorticks_off()
matplotlib.pyplot.colorbar returns a Colorbar object which extends ColorbarBase.
You can find that two functions in the document of class matplotlib.colorbar.ColorbarBase.

How to set x axis according to the numbers in the DATAFRAME

i am using Matplotlib to show graph of some information that i get from the users,
i want to show it as:axis x will be by the ID of the users and axis y will be by the Winning time that whey have..
I dont understand how can i put the x axis index as the ID of my users.
my code:
import matplotlib.pyplot as plt
import matplotlib,pylab as pylab
import pandas as pd
import numpy as np
#df = pd.read_csv('Players.csv')
df = pd.read_json('Players.json')
# df.groupby('ID').sum()['Win']
axisx = df.groupby('ID').sum()['Win'].keys()
axisy = df.groupby('ID').sum()['Win'].values
fig = pylab.gcf()
# fig.canvas.set_window_title('4 In A Row Statistic')
# img = plt.imread("Oi.jpeg")
# plt.imshow(img)
fig, ax = plt.subplots()
ax.set_xticklabels(axisx.to_list())
plt.title('Game Statistic',fontsize=20,color='r')
plt.xlabel('ID Players',color='r')
plt.ylabel('Wins',color='r')
x = np.arange(len(axisx))
rects = ax.bar(x, axisy, width=0.1)
plt.show()
use plt.xticks(array_of_id). xticks can set the current tick locations and labels of the x-axis.

How can I draw single points on a plot already containing data?

In a while loop I'm updating two sets of data in a plot (some data X and a threshold). Now I'd like to add single points (peaks of X) on the same plot. How can I do that?
import matplotlib.pyplot as plt
plt.ion()
fig = plt.figure()
plt_ps = fig.add_subplot(111)
# initialize plots
powerspectrum, = plt_ps.plot(np.zeros([windowSize,]))
threshold, = plt_ps.plot(np.zeros([windowSize,]))
peaks, = plt_ps.plot([], [], 'or') # peaks will just be a set of coordinates, eg peaks_x=[2,4,7] and peaks_y=[3,7,6]
while(somecondition):
# some data processing
powerspectrum.set_ydata(new_powerspectrum_data)
threshold.set_ydata(new_threshold_data)
#peaks.? how do I set new peaks? Tried peaks.set_data(peaks_x, peaks_y) but peaks do not show up
plt_ps.relim()
plt_ps.autoscale_view()
fig.canvas.draw()
Just use plot with the right style:
import matplotlib.pyplot as plt
xs = [1,2,5,3,6,7,1,3,4,5,2,6,7,8,2,1]
ys = [3,4,5,2,7,1,3,4,1,2,3,4,5,2,3,1]
plt.plot(xs,ys,'.')
plt.show()

viewing a polygon read from shapefile with matplotlib

I am trying to view a basic polygon read from a Shapefile using matplotlib and pyshp
But all my efforts yield just an empty axes with no polygon. Here are few of my tries, using the dataset showing the borders of Belgium:
import shapefile as sf
r = sf.Reader("BEL_adm/BEL_adm0")
p=r.shapes()
b=p[0]
points = b.points
import matplotlib.pyplot as plt
from matplotlib.path import Path
imporst matplotlib.patches as patches
verts = points
verts = []
for x,y in points:
verts.append(tuple([x,y]))
codes = ['']*len(verts)
codes[0] = Path.MOVETO
codes[-1] = Path.CLOSEPOLY
for i in range(1,len(verts)):
codes[i]=Path.LINETO
path = Path(verts, codes)
fig = plt.figure()
ax = fig.add_subplot(111)
patch = patches.PathPatch(path, facecolor='orange', lw=2)
ax.add_patch(patch)
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
plt.show()
Another try with patches also yields an empty frame:
fig = plt.figure(figsize=(11.7,8.3))
ax = plt.subplot(111)
x,y=zip(*b.points)
import matplotlib.patches as patches
import matplotlib.pyplot as plt
bol=patches.Polygon(b.points,True, transform=ax.transAxes)
ax.add_patch(bol)
ax.set_ylim(0,60)
ax.set_xlim(0,200)
plt.show()
Would be happy to see what I am missing.
Thanks, Oz
instead of calling set_xlim(), set_ylim() to set the range of axis, you can use ax.autoscale().
For your Polygon version, you don't need to set transform argument to ax.transAxes, just call:
bol=patches.Polygon(b.points,True)