Geopandas with log-scale colormap - python

If I have the plot below, how can I turn the colormap/legend into a log-scale?
import geopandas as gpd
import matplotlib.pyplot as plt
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
world = world[(world.pop_est>0) & (world.name!="Antarctica")]
fig, ax = plt.subplots(1, 1)
world.plot(column='pop_est', ax=ax, legend=True)

GeoPandas plots are using matplotlib, so you can use normalization of colormap provided by it. Note than I am also specifying min and max values as mins and maxs of the column I am plotting.
world.plot(column='pop_est', legend=True, norm=matplotlib.colors.LogNorm(vmin=world.pop_est.min(), vmax=world.pop_est.max()), )

You can simply plot the log of the value instead of the value itself.
import geopandas as gpd
import matplotlib.pyplot as plt
from numpy import log10
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
world = world[(world.pop_est>0) & (world.name!="Antarctica")]
world['logval'] = log10(world['pop_est'])
fig, ax = plt.subplots(1, 1)
world.plot(column='logval', ax=ax, legend=True)

Related

Geopandas plot is streched

I'm trying to plot a state of Germany with geopandas. Unfortunately the plot is a bit streched.
import matplotlib.pyplot as plt
import geopandas as gpd
shapes = gpd.read_file('shapes.shp')
shapes.plot(figsize=(20,20), color='white', edgecolor='black')
If I execute the code above, I'll receive the following plot.
But if you compare the shape of the plot to the real shape of the state as displayed below, then this plot is a bit streched.
I tried to adjust the axes and the figsize, but I didn't work.
Thanks for your help
As gboffi mentioned the projection is not right. So i changed it to EPSG:3857.
import matplotlib.pyplot as plt
import geopandas as gpd
shapes = gpd.read_file('shapes.shp').to_crs(epsg=3857)
fig, axs = plt.subplots(1, 1, figsize=(15,15))
shapes.plot(ax=axs, color='white', edgecolor='black')

Geopandas plot empty when changing crs and plotting with fig,ax (without fig,ax everything is fine)?

When using fig,ax from matplotlib in combination with a geopandas dataframe AND when changing the .crs, the plot is empty. Anyone an idea why this happens and how to fix it?
Dataset: https://hub.arcgis.com/datasets/esribeluxdata::belgium-municipalities-1
import geopandas as gpd
import matplotlib.pyplot as plt
from fiona.crs import from_epsg
belgium = gpd.read_file("BELGIUM__Municipalities.shp")
fig,ax = plt.subplots()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
municipalities.plot(ax = ax) -> crs=WGS84 (lat/long)
plt.show()
municipalities = municipaliteis.to_crs("epsg:3395") -> crs to Mercator projection
municipalities.crs
municipalities.plot(ax = ax) -> plot = empty: Why does this happen, how to fix it?
plt.show()
municipalities.plot() -> plot = Mercator plot
plt.show()
It is OK to change crs, below I made it with subplots. If you keep same ax object I think it could be difficult to see them both cause limits are not at all the same.
import geopandas as gpd
import matplotlib.pyplot as plt
from fiona.crs import from_epsg
municipalities = gpd.read_file("BELGIUM__Municipalities.shp")
fig, ax = plt.subplots(1, 2)
for a in ax:
a.spines['top'].set_visible(False)
a.spines['right'].set_visible(False)
a.spines['left'].set_visible(False)
a.spines['bottom'].set_visible(False)
a.get_xaxis().set_visible(False)
a.get_yaxis().set_visible(False)
municipalities.plot(ax=ax[0], color='red')
municipalities = municipalities.to_crs("epsg:3395")
municipalities.plot(ax=ax[1])
plt.show()
EDIT:
In your second call, your ax is no more referring to an visually existing area so, you can do that to recreate it:
import geopandas as gpd
import matplotlib.pyplot as plt
from fiona.crs import from_epsg
municipalities = gpd.read_file("BELGIUM__Municipalities.shp")
def init():
fig,ax = plt.subplots()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
return ax
ax = init()
municipalities.plot(ax = ax)
plt.show()
ax = init()
municipalities = municipalities.to_crs("epsg:3395")
municipalities.plot(ax=ax)
plt.show()
municipalities.plot()
plt.show()
In the last call, matplotlib creates a new axes object as you do not mention any axes to work with.

Generating Legend for geopandas plot

I am plotting a shape file with Geopandas. Additionally im Adding Points of a dataframe (see picture). Now im trying to add a legend (at the right of the original plot) for the point. I dont really know how to do that!
Plot
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import geopandas as gpd
import test
variable = 'RTD_rtd'
df = test.getdataframe()
gdf = gpd.GeoDataFrame(
df, geometry=gpd.points_from_xy(df.NP_LongDegree, df.NP_LatDegree))
fp = "xxx"
map_df = gpd.read_file(fp)
ax = map_df.plot(color='white', edgecolor='black', linewidth=0.4, figsize= (10,10))
gdf.plot(column=variable, ax=ax, cmap='Reds', markersize=14.0, linewidth=2.0)
plt.show()
One Idea was to add a simple legend. I want something looking better. Maybe something similar to whats done in this tutorial: Tutorial
I followed the example that you referred to and this is the concise version. It would have been better if you could have shared a bit of your dataset 'df'. It seems that you want to have a colorbar which fig.colorbar generates.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import geopandas as gpd
import test
from shapely.geometry import Point
df = pd.read_csv('london-borough-profiles.csv', header=0)
df = df[['Area name','Population density (per hectare) 2017']]
fp = 'London_Borough_Excluding_MHW.shp'
map_df = gpd.read_file(fp)
gdf = map_df.set_index('NAME').join(df.set_index('Area name'))
variable = 'Population density (per hectare) 2017'
vmin, vmax = 120, 220
fig, ax = plt.subplots(1, figsize=(10, 6))
gdf.plot(column=variable, cmap='Blues', ax = ax, linewidth=0.8, edgecolor='0.8')
ax.axis('off')
ax.set_title('Population density (per hectare) 2017', fontdict={'fontsize': '25', 'fontweight' : '3'})
ax.annotate('Source: London Datastore, 2014',xy=(0.1, .08), xycoords='figure fraction', horizontalalignment='left', verticalalignment='top', fontsize=12, color='#555555')
sm = plt.cm.ScalarMappable(cmap='Blues', norm=plt.Normalize(vmin=vmin, vmax=vmax))
sm._A = []
cbar = fig.colorbar(sm)
You can add this into your solution and for this you have to set label for each plot
plt.legend()

Matplotlib/Seaborn: how to plot a rugplot on the top edge of x-axis?

Suppose I draw a plot using the code below. How to plot the rug part on the top edge of x-axis?
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.distplot(np.random.normal(0, 0.1, 100), rug=True, hist=False)
plt.show()
The seaborn.rugplot creates a LineCollection with the length of the lines being defined in axes coordinates. Those are always the same, such that the plot does not change if you invert the axes.
You can create your own LineCollection from the data though. The advantage compared to using bars is that the linewidth is in points and therefore no lines will be lost independend of the data range.
import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt
import seaborn as sns
def upper_rugplot(data, height=.05, ax=None, **kwargs):
from matplotlib.collections import LineCollection
ax = ax or plt.gca()
kwargs.setdefault("linewidth", 1)
segs = np.stack((np.c_[data, data],
np.c_[np.ones_like(data), np.ones_like(data)-height]),
axis=-1)
lc = LineCollection(segs, transform=ax.get_xaxis_transform(), **kwargs)
ax.add_collection(lc)
fig, ax = plt.subplots()
data = np.random.normal(0, 0.1, 100)
sns.distplot(data, rug=False, hist=False, ax=ax)
upper_rugplot(data, ax=ax)
plt.show()
Rugs are just thin lines at the data points. Yo can think of them as thin bars. That being said, you can have a following work around: Plot distplot without rugs and then create a twin x-axis and plot a bar chart with thin bars. Following is a working answer:
import numpy as np; np.random.seed(21)
import matplotlib.pyplot as plt
import seaborn as sns
fig, ax = plt.subplots()
data = np.random.normal(0, 0.1, 100)
sns.distplot(data, rug=False, hist=False, ax=ax)
ax1 = ax.twinx()
ax1.bar(data, height=ax.get_ylim()[1]/10, width=0.001)
ax1.set_ylim(ax.get_ylim())
ax1.invert_yaxis()
ax1.set_yticks([])
plt.show()

How do I change the plot size of a regplot in Seaborn?

Something similar to the fig.set_size_inches(18.5, 10.5) of matplotlib.
You can declare fig, ax pair via plt.subplots() first, then set proper size on that figure, and ask sns.regplot to plot on that ax
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# some artificial data
data = np.random.multivariate_normal([0,0], [[1,-0.5],[-0.5,1]], size=100)
# plot
sns.set_style('ticks')
fig, ax = plt.subplots()
fig.set_size_inches(18.5, 10.5)
sns.regplot(data[:,0], data[:,1], ax=ax)
sns.despine()
Or a little bit shorter:
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# some artificial data
data = np.random.multivariate_normal([0,0], [[1,-0.5],[-0.5,1]], size=100)
# plot
sns.set_style('ticks')
g = sns.regplot(data[:,0], data[:,1])
g.figure.set_size_inches(18.5, 10.5)
sns.despine()

Categories

Resources