Shapefile zooming to plot with geopandas - pandas

I have a shapefile of Italy and I'm plotting the GIS Data on it. Thing is I've got a small trajectory of a bus going within a city(Rome) and when i`m plotting, it appears like 1 dot. I guess because of my map.
How to zoom the map (.shp) ?
street_map = gpd.read_file("roads.shp")
...
...
fig,ax = plt.subplots(figsize = (20,15))
street_map.plot(ax = ax, alpha = 0.4, color = "grey")
geo_df[geo_df['Perc_'] > 25].plot(ax = ax, markersize = 20, color = "blue",
marker = "o", label = "Neg")
geo_df[geo_df['Perc_'] < 25].plot(ax = ax, markersize = 20, color = "red",
marker = "^", label = "Pos")
plt.legend(prop={'size':15})

Based on your 1st image, it is possible to get the zoom-in plot by specifying proper x and y limits.
...
ax.set_ylim([40.4, 47.2])
ax.set_xlim([7.0, 14.4])
(Place this code before plt.legend().
Hope this is useful.

Related

misalignment between grid cells and color mesh used to highlight them (in Matplotlib)

I am using the following code to to generate this heat map:
dim = np.arange(1, 32, 1)
fig, ax = plt.subplots(figsize=(7,9))
heatmap = ax.imshow(h, aspect=1, cmap=plt.cm.get_cmap('Blues', 5), clim=[0,100])
ax.set_ylabel("Days", fontsize=15)
ax.set_xlabel("Months", fontsize=15)
ax.set_title("Percentage of records per day", fontsize=18)
ax.set_yticks(range(0,31))
ax.set_yticklabels(dim, ha='center', minor=False)
ax.set_xticks(range(0,13,1))
ax.set_xticklabels(ylabel[7:],rotation=45, ha='right')
ax.grid(which = 'minor', color = 'w')
ax.set_facecolor('gray')
ax.xaxis.set_minor_locator(MultipleLocator(.5))
ax.yaxis.set_minor_locator(MultipleLocator(.5))
cbaxes = fig.add_axes([.8, .35, .04, .3])
cbar = fig.colorbar(heatmap, ticks = [0, 20, 40, 60, 80 ,100], label = 'Percentage', cax = cbaxes)
fig.show()
I would like to highlight all of the cells with a value greater or equal to 60.
I tried adding this to my code:
highlight = (h> 60)
highlight = np.ma.masked_less(highlight, 1)
ax.pcolormesh(highlight, facecolor = 'None')
and got this:
I am almost there but the cells and the mesh are misaligned. How could I fix this?
The cells in a heatmap are centered on integers, this means for example that the cell with index 0,0 is in fact -0.5 to 0.5 on both axes. You have to subtract 0.5 to the coordinates of your highlights.
Thanks to mozway's comment I was able to fix my problem. I changed the beginning of my code to:
highlight = (h> 60)
highlight = np.ma.masked_less(highlight, 1)
x = np.arange(-0.5,12,1) # len = 10
y = np.arange(-0.5,30,1) # len = 6
X, Y = np.meshgrid(x, y)
and change the line plotting the color mesh to:
ax.pcolormesh(x,y,highlight, facecolor = 'None', edgecolors = 'w',shading='auto', zorder=2)
I also had to set the z-order of the color mesh to be greater than the grid lines (zorder=2 and zorder=1 respectively).

Series plot - Geopandas

I dont have a working code - but a snipet of my code can be as follows. I'm trying to use geopandas with mathplotlib, and trying to plot a map with links and points.
shape_file = os.path.join(os.getcwd(), "Healthboard")
healthboard = gp.read_file(os.path.join(shape_file, "healthboard.shp"))
healthboard = healthboard.to_crs({'init': 'epsg:4326'}) # re-projection
geo_df1 = geo_df1[geo_df1['HealthBoardArea2019Code'] == string1]
geo = geo_df[geo_df['Healthboard '] == string2]
new_shape_file = os.path.join(os.getcwd(), "Council_Shapefile")
council_to_healtboard = pd.read_csv("council_to_healthboard.csv")
council_to_healthboard = council_to_healtboard.rename(columns = {'CA': 'Council_area_code'})
council = gp.read_file(os.path.join(new_shape_file, "Council_shapefile.shp"))
council = council.to_crs({'init': 'epsg:4326'})
council = council.rename(columns = {'la_s_code':'Council_area_code'})
df = council.merge(council_to_healthboard, on = 'Council_area_code', how ='inner')
# Plotting stuff
fig, ax = plt.subplots(figsize=(15,15))
geo_df1.plot(ax = ax, markersize=35, color = "blue", marker = "*", label = "Postcode Sector")
geo.geometry.plot(ax = ax, color = "red", markersize=20, alpha = 0.8, label = 'SiteName')
#healthboard[healthboard["HBName"]=="Lothian"].plot(ax = ax, alpha = 0.6)
#healthboard[healthboard["HBName"]=="Lothian"].boundary.plot(ax = ax, color = "black", alpha = 0.6)
df[df["HB"]=="S08000024"].boundary.plot(ax =ax, color = "black", alpha = 0.1)
df[df["HB"]=="S08000024"].plot(ax =ax, cmap = "viridis", alpha = 0.1)
links_gp.plot(ax =ax, alpha = 0.25, color='brown', linestyle = "-")
My links_gp.plot has 40 time periods, as a result I want to make one plot, and have a button to adjust the parameters of time. Or if not possible a series of 40 plots. I've tried numerous ways but keep failing on this. I would really appreciate if someone could guide me on this.
I'm aware that you are using matplotlib, but if you don't mind using bokeh instead, you could use the following. To create an interactive plot with a possibility to adjust a parameter, bokeh provides a slider widget which can be used to change the plot based on a custom filter function.
An example from a geopandas dataframe with LineString geometries similar to the one you posted:
import geopandas as gpd
from bokeh.io import show, output_notebook
from bokeh.models import (CDSView, ColumnDataSource, CustomJS,
CustomJSFilter, Slider, Column)
from bokeh.layouts import column
from bokeh.plotting import figure
# prepare data source
links_gp['x'] = links_gp.apply(lambda row: list(row['geometry'].coords.xy[0]), axis=1)
links_gp['y'] = links_gp.apply(lambda row: list(row['geometry'].coords.xy[1]), axis=1)
# drop geometry column, because it can't be serialized to ColumnDataSource
links_gp.drop('geometry', axis=1, inplace=True)
linesource = ColumnDataSource(links_gp)
p = figure(title = 'Bokeh Time Slider',
plot_height = 500,
plot_width = 600,
toolbar_location = 'below',
tools = "pan, wheel_zoom, box_zoom, reset")
slider = Slider(title='Time Period', start=1, end=40, step=1, value=1)
# Callback triggers the filter when the slider moves
callback = CustomJS(args=dict(source=linesource),
code="""source.change.emit();""")
slider.js_on_change('value', callback)
# Custom filter that selects all lines of the time period based on the slider value
custom_filter = CustomJSFilter(args=dict(slider=slider),
code="""
var indices = [];
// iterate through rows of data source and check if time period value equals the slider value
for (var i = 0; i < source.get_length(); i++){
if (source.data['Time Period'][i] == slider.value){
indices.push(true);
} else {
indices.push(false);
}
}
return indices;
""")
# Use filter to determine which lines are visible
view = CDSView(source=linesource, filters=[custom_filter])
# plot lines to map
p.multi_line('x', 'y', source=linesource, color='red', line_width=3, view=view)
layout = column(p, slider)
show(layout)
This will be the result of the above code.

Shrink matplotlib parasite axis horizontally to take up approximately 25% of the image length

I have an image like the one below:
The issue is I need the curves to only take up about 25% - 30% of the image. In other words I need to shrink the size of the two parasite axes horizontally. Is this even possible?
Here is what I have so far:
"""
Plotting _____________________________________________________________________________________________________________
"""
fig = plt.figure(figsize=(20,15))
host1 = host_subplot(211, axes_class=AA.Axes)
plt.subplots_adjust(right=0.75)
#Create custom axes
cax1 = plt.axes(frameon=False)
# Now create parasite axis
par11 = host1.twiny()
par12 = host1.twiny()
top_offset = 50
new_fixed_axis1 = par12.get_grid_helper().new_fixed_axis
par12.axis["top"] = new_fixed_axis1(loc="top",
axes=par11,
offset=(0, top_offset))
par11.axis["top"].toggle(all=True)
par12.axis["top"].toggle(all=True)
# Bottom Axis
bottom_offset1 = -50
bottom_offset2 = -100
par21 = host1.twiny()
par22 = host1.twiny()
new_fixed_axis2 = par21.get_grid_helper().new_fixed_axis
par21.axis["bottom"] = new_fixed_axis2(loc="bottom",
axes=par12,
offset=(0, bottom_offset1))
# Set Host Axis Labels
host1.set_xlabel("UTC Time")
host1.set_ylabel("Elevation (km")
# Set Top Axis Labels
par11.set_xlabel("Sonde Potential Temperature (K)")
par12.set_xlabel("Sonde Relative Humidity %")
vmin, vmax = np.min(chan_1064), np.max(chan_1064)
im = host1.imshow(chan_1064, aspect="auto", cmap=get_a_color_map(), vmin=-2e-4, vmax=0.6e-2,
extent=(min(xs), max(xs), min(bin_alt_array), max(bin_alt_array)))
scatter = host1.scatter(xs, ys, s=100, color='gold')
host1.set_xlim(min(xs), max(xs))
fig.colorbar(im)
plt.draw()
leg = plt.legend( loc = 'lower right')
# Adjust Fonts
font = {'family' : 'normal',
'weight' : 'bold',
'size' : 12}
mpl.rc('font', **font)
plt.tight_layout()
plt.show()
Sorry if it's a simple solution but, I have not been able to figure it out for the life of me.

Setting z_order when working with ConnectionPatch

I am trying to produce a figure where red line is not going to be visible inside the green rectangle (i.e. within the middle panel). Setting z order seems to be in effect only for the lower panel (subplot) and it is ignored for the upper and middle one. Can anyone help with this please.
Alternatively, what would also work for me is, if I plot two subplots: top and bottom, and the piece of line that connects points X (from the bottom) and Y (from the top subplot) does not get plotted in the region which is between two places. In other words, line looks as a broken line going from X to the top of bottom panel, then having some skip and then continuing from min_y in top panel and going all the way to Y.
I am planning to achieve this by setting color of rectangle to be white so that it overwrites these lines (but this does not work).
from matplotlib.patches import ConnectionPatch
import matplotlib.patches as patches
from matplotlib.patches import Rectangle
import matplotlib.pyplot as plt
fig, (ax_upper, ax_middle, ax_lower) = plt.subplots(3, 1, sharey = False)
ax_upper.spines['top'].set_visible(False)
ax_upper.spines['bottom'].set_visible(False)
ax_upper.spines['right'].set_visible(False)
ax_upper.get_xaxis().set_ticks([])
ax_middle.spines['left'].set_visible(False)
ax_middle.spines['right'].set_visible(False)
ax_middle.spines['top'].set_visible(False)
ax_middle.spines['bottom'].set_visible(False)
ax_middle.get_xaxis().set_ticks([])
ax_middle.get_yaxis().set_ticks([])
ax_lower.spines['top'].set_visible(False)
ax_lower.spines['right'].set_visible(False)
ax_upper.set_ylim(10, 100)
ax_lower.set_ylim(0, 10)
ax_lower.set_xlim(0, 100)
ax_upper.set_xlim(0, 100)
con = ConnectionPatch(xyA = (2, 2), xyB = (80,90), coordsA = "data", coordsB = "data", axesA = ax_lower, axesB = ax_upper)
ax_lower.add_artist(con)
con.set_zorder(1)
con.set_color("red")
con.set_linewidth(3)
con = ConnectionPatch(xyA = (95,5), xyB = (80, 90), coordsA = "data", coordsB = "data", axesA = ax_lower, axesB = ax_upper, lw=1)
ax_lower.add_artist(con)
con.set_zorder(1)
con.set_color("red")
con.set_linewidth(3)
ax_lower.plot([2], [2], marker="o", color = "red")
ax_upper.plot([80], [90], marker="o", color = "red", zorder = 2)
ax_lower.plot([95], [5], marker="o", color = "red")
ax_upper.plot([0,0],[0,0], label="class A", color = "red", zorder=1, marker = "o", )
ax_upper.legend(loc='upper left')
rect = Rectangle((0,0), 1, 1, linewidth=1, edgecolor='black', facecolor='green', zorder = 3)
ax_middle.add_patch(rect)
plt.show()
example output

Change markerfacecolor for some of the markers in Matplotlib

I have a plot that shows markers in a circle. I want to be able to change the colour of 3 of them. I've tried using a variable for markerfacecolor as follows but that doesn't work:
angle = 0.0
colorR = 'red'
angleUpdate = 2 * numpy.pi / (len(v.T))
for i in range(len(v.T)):
x = numpy.sin(angle)
y = numpy.cos(angle)
angle += angleUpdate
if i < 3:
colorR = 'green'
v[0, i] = x
v[1, i] = y
plt.plot(v[0], v[1], 'ko', markerfacecolor = colorR, markersize = 70, clip_on = False)
plt.show()
Is there a way of doing this?
In your plot 'ko' means put a black circle marker; k stands for black. You should try:
plt.plot(v[0], v[1], 'o', markerfacecolor = 'red')
To get the abbreviation of other symbols and colors try:
help(plt.plot)
You can either achieve your case using plot or scatter, depending on what you are doing:
import pylab as plt
x=[1,2,3,4,5,6,7,8,9,10]
plt.plot(x[:5],x[:5],'o',c='r',markersize=10)
plt.plot(x[5:],x[5:],'o',c='b',markersize=10)
plt.show()
will generate,
Similarly, you can also use
plt.scatter(x[:5],x[:5],c='r',s=100)
plt.scatter(x[5:],x[5:],c='b',s=100)