mirror of
https://github.com/wassname/geopandas.git
synced 2026-09-24 13:30:40 +08:00
VIS: updated plotting defaults (#510)
* remove hardcoded defaults * use uniform color by default * for categorical data use default cmap tab10 instead of Set1 * forgot to remove hardcoded markersize * remove no longer used gencolor function * update MultiPolygons test * fix some tests + mixed geom case with cmap * enable more tests * fix for matplotlib 1.4.3 * skip one for 1.4.3 * fix some collection tests * small updates to docstring * undo take squaring of the markersize
This commit is contained in:
committed by
James McBride
parent
c6cf3b2bba
commit
4ed906ece6
+88
-100
@@ -1,9 +1,9 @@
|
||||
from __future__ import print_function
|
||||
|
||||
from distutils.version import LooseVersion
|
||||
import warnings
|
||||
|
||||
import numpy as np
|
||||
from six import next
|
||||
|
||||
|
||||
def _flatten_multi_geoms(geoms, colors=None):
|
||||
@@ -43,9 +43,8 @@ def _flatten_multi_geoms(geoms, colors=None):
|
||||
return components, component_colors
|
||||
|
||||
|
||||
def plot_polygon_collection(ax, geoms, values=None, linewidth=1.0,
|
||||
edgecolor='black', alpha=0.5,
|
||||
vmin=None, vmax=None, cmap=None, **kwargs):
|
||||
def plot_polygon_collection(ax, geoms, values=None, color=None,
|
||||
cmap=None, vmin=None, vmax=None, **kwargs):
|
||||
"""
|
||||
Plots a collection of Polygon and MultiPolygon geometries to `ax`
|
||||
|
||||
@@ -90,9 +89,12 @@ def plot_polygon_collection(ax, geoms, values=None, linewidth=1.0,
|
||||
if 'markersize' in kwargs:
|
||||
del kwargs['markersize']
|
||||
|
||||
# color=None overwrites specified facecolor/edgecolor with default color
|
||||
if color is not None:
|
||||
kwargs['color'] = color
|
||||
|
||||
collection = PatchCollection([PolygonPatch(poly) for poly in geoms],
|
||||
linewidth=linewidth, edgecolor=edgecolor,
|
||||
alpha=alpha, **kwargs)
|
||||
**kwargs)
|
||||
|
||||
if values is not None:
|
||||
collection.set_array(np.asarray(values))
|
||||
@@ -105,8 +107,7 @@ def plot_polygon_collection(ax, geoms, values=None, linewidth=1.0,
|
||||
|
||||
|
||||
def plot_linestring_collection(ax, geoms, values=None, color=None,
|
||||
vmin=None, vmax=None, cmap=None,
|
||||
linewidth=1.0, **kwargs):
|
||||
cmap=None, vmin=None, vmax=None, **kwargs):
|
||||
"""
|
||||
Plots a collection of LineString and MultiLineString geometries to `ax`
|
||||
|
||||
@@ -147,7 +148,7 @@ def plot_linestring_collection(ax, geoms, values=None, color=None,
|
||||
kwargs['color'] = color
|
||||
|
||||
segments = [np.array(linestring)[:, :2] for linestring in geoms]
|
||||
collection = LineCollection(segments, linewidth=linewidth, **kwargs)
|
||||
collection = LineCollection(segments, **kwargs)
|
||||
|
||||
if values is not None:
|
||||
collection.set_array(np.asarray(values))
|
||||
@@ -160,8 +161,8 @@ def plot_linestring_collection(ax, geoms, values=None, color=None,
|
||||
|
||||
|
||||
def plot_point_collection(ax, geoms, values=None, color=None,
|
||||
vmin=None, vmax=None, cmap=None,
|
||||
marker='o', markersize=2, **kwargs):
|
||||
cmap=None, vmin=None, vmax=None,
|
||||
marker='o', markersize=None, **kwargs):
|
||||
"""
|
||||
Plots a collection of Point geometries to `ax`
|
||||
|
||||
@@ -177,6 +178,11 @@ def plot_point_collection(ax, geoms, values=None, color=None,
|
||||
Values mapped to colors using vmin, vmax, and cmap.
|
||||
Cannot be specified together with `color`.
|
||||
|
||||
markersize : scalar or array-like, optional
|
||||
Size of the markers. Note that under the hood ``scatter`` is
|
||||
used, so the specified value will be proportional to the
|
||||
area of the marker (size in points^2).
|
||||
|
||||
Returns
|
||||
-------
|
||||
collection : matplotlib.collections.Collection that was plotted
|
||||
@@ -187,34 +193,18 @@ def plot_point_collection(ax, geoms, values=None, color=None,
|
||||
x = geoms.x.values
|
||||
y = geoms.y.values
|
||||
|
||||
collection = ax.scatter(x, y, s=markersize, c=values, color=color,
|
||||
vmin=vmin, vmax=vmax, cmap=cmap,
|
||||
# matplotlib 1.4 does not support c=None, and < 2.0 does not support s=None
|
||||
if values is not None:
|
||||
kwargs['c'] = values
|
||||
if markersize is not None:
|
||||
kwargs['s'] = markersize
|
||||
|
||||
collection = ax.scatter(x, y, color=color, vmin=vmin, vmax=vmax, cmap=cmap,
|
||||
marker=marker, **kwargs)
|
||||
return collection
|
||||
|
||||
|
||||
def _gencolor(N, colormap='Set1'):
|
||||
"""
|
||||
Color generator intended to work with one of the ColorBrewer
|
||||
qualitative color scales.
|
||||
|
||||
Suggested values of colormap are the following:
|
||||
|
||||
Accent, Dark2, Paired, Pastel1, Pastel2, Set1, Set2, Set3
|
||||
|
||||
(although any matplotlib colormap will work).
|
||||
"""
|
||||
from matplotlib import cm
|
||||
# don't use more than 9 discrete colors
|
||||
n_colors = min(N, 9)
|
||||
cmap = cm.get_cmap(colormap, n_colors)
|
||||
colors = cmap(range(n_colors))
|
||||
for i in range(N):
|
||||
yield colors[i % n_colors]
|
||||
|
||||
|
||||
def plot_series(s, cmap='Set1', color=None, ax=None, linewidth=1.0,
|
||||
figsize=None, **color_kwds):
|
||||
def plot_series(s, cmap=None, color=None, ax=None, figsize=None, **style_kwds):
|
||||
"""
|
||||
Plot a GeoSeries.
|
||||
|
||||
@@ -228,13 +218,13 @@ def plot_series(s, cmap='Set1', color=None, ax=None, linewidth=1.0,
|
||||
MultiPolygon, LineString, MultiLineString and Point
|
||||
geometries can be plotted.
|
||||
|
||||
cmap : str (default 'Set1')
|
||||
cmap : str (default None)
|
||||
The name of a colormap recognized by matplotlib. Any
|
||||
colormap will work, but categorical colormaps are
|
||||
generally recommended. Examples of useful discrete
|
||||
colormaps include:
|
||||
|
||||
Accent, Dark2, Paired, Pastel1, Pastel2, Set1, Set2, Set3
|
||||
tab10, tab20, Accent, Dark2, Paired, Pastel1, Set1, Set2
|
||||
|
||||
color : str (default None)
|
||||
If specified, all objects will be colored uniformly.
|
||||
@@ -242,42 +232,42 @@ def plot_series(s, cmap='Set1', color=None, ax=None, linewidth=1.0,
|
||||
ax : matplotlib.pyplot.Artist (default None)
|
||||
axes on which to draw the plot
|
||||
|
||||
linewidth : float (default 1.0)
|
||||
Line width for geometries.
|
||||
|
||||
figsize : pair of floats (default None)
|
||||
Size of the resulting matplotlib.figure.Figure. If the argument
|
||||
ax is given explicitly, figsize is ignored.
|
||||
|
||||
**color_kwds : dict
|
||||
Color options to be passed on to the actual plot function
|
||||
**style_kwds : dict
|
||||
Color options to be passed on to the actual plot function, such
|
||||
as ``edgecolor``, ``facecolor``, ``linewidth``, ``markersize``,
|
||||
``alpha``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
matplotlib axes instance
|
||||
"""
|
||||
if 'colormap' in color_kwds:
|
||||
if 'colormap' in style_kwds:
|
||||
warnings.warn("'colormap' is deprecated, please use 'cmap' instead "
|
||||
"(for consistency with matplotlib)", FutureWarning)
|
||||
cmap = color_kwds.pop('colormap')
|
||||
if 'axes' in color_kwds:
|
||||
cmap = style_kwds.pop('colormap')
|
||||
if 'axes' in style_kwds:
|
||||
warnings.warn("'axes' is deprecated, please use 'ax' instead "
|
||||
"(for consistency with pandas)", FutureWarning)
|
||||
ax = color_kwds.pop('axes')
|
||||
ax = style_kwds.pop('axes')
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
if ax is None:
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.set_aspect('equal')
|
||||
|
||||
# if no color specified, create range of colors based on cmap
|
||||
num_geoms = len(s.index)
|
||||
col_seq = False
|
||||
if color is None:
|
||||
color_generator = _gencolor(len(s), colormap=cmap)
|
||||
color = np.array([next(color_generator) for _ in range(num_geoms)])
|
||||
col_seq = True
|
||||
# if cmap is specified, create range of colors based on cmap
|
||||
values = None
|
||||
if cmap is not None:
|
||||
values = np.arange(len(s))
|
||||
if hasattr(cmap, 'N'):
|
||||
values = values % cmap.N
|
||||
style_kwds['vmin'] = style_kwds.get('vmin', values.min())
|
||||
style_kwds['vmax'] = style_kwds.get('vmax', values.max())
|
||||
|
||||
geom_types = s.geometry.type
|
||||
poly_idx = np.asarray((geom_types == 'Polygon')
|
||||
@@ -292,43 +282,40 @@ def plot_series(s, cmap='Set1', color=None, ax=None, linewidth=1.0,
|
||||
if not polys.empty:
|
||||
# color overrides both face and edgecolor. As we want people to be
|
||||
# able to use edgecolor as well, pass color to facecolor
|
||||
facecolor = color_kwds.pop('facecolor', None)
|
||||
if col_seq:
|
||||
if not facecolor:
|
||||
facecolor = color[poly_idx] if col_seq else color
|
||||
else:
|
||||
facecolor = style_kwds.pop('facecolor', None)
|
||||
if color is not None:
|
||||
facecolor = color
|
||||
plot_polygon_collection(ax, polys, facecolor=facecolor,
|
||||
linewidth=linewidth, **color_kwds)
|
||||
values_ = values[poly_idx] if cmap else None
|
||||
plot_polygon_collection(ax, polys, values_, facecolor=facecolor,
|
||||
cmap=cmap, **style_kwds)
|
||||
|
||||
# plot all LineStrings and MultiLineString components in same collection
|
||||
lines = s.geometry[line_idx]
|
||||
if not lines.empty:
|
||||
color_ = color[line_idx] if col_seq else color
|
||||
plot_linestring_collection(ax, lines, color=color_,
|
||||
linewidth=linewidth, **color_kwds)
|
||||
values_ = values[line_idx] if cmap else None
|
||||
plot_linestring_collection(ax, lines, values_, color=color, cmap=cmap,
|
||||
**style_kwds)
|
||||
|
||||
# plot all Points in the same collection
|
||||
points = s.geometry[point_idx]
|
||||
if not points.empty:
|
||||
color_ = color[point_idx] if col_seq else color
|
||||
plot_point_collection(ax, points, color=color_, **color_kwds)
|
||||
values_ = values[point_idx] if cmap else None
|
||||
plot_point_collection(ax, points, values_, color=color, cmap=cmap,
|
||||
**style_kwds)
|
||||
|
||||
plt.draw()
|
||||
return ax
|
||||
|
||||
|
||||
def plot_dataframe(df, column=None, cmap=None, color=None, linewidth=1.0,
|
||||
categorical=False, legend=False, ax=None,
|
||||
scheme=None, k=5, vmin=None, vmax=None, figsize=None,
|
||||
**color_kwds):
|
||||
def plot_dataframe(df, column=None, cmap=None, color=None, ax=None,
|
||||
categorical=False, legend=False, scheme=None, k=5,
|
||||
vmin=None, vmax=None, figsize=None, **style_kwds):
|
||||
"""
|
||||
Plot a GeoDataFrame.
|
||||
|
||||
Generate a plot of a GeoDataFrame with matplotlib. If a
|
||||
column is specified, the plot coloring will be based on values
|
||||
in that column. Otherwise, a categorical plot of the
|
||||
geometries in the `geometry` column will be generated.
|
||||
in that column.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@@ -341,39 +328,37 @@ def plot_dataframe(df, column=None, cmap=None, color=None, linewidth=1.0,
|
||||
column : str (default None)
|
||||
The name of the column to be plotted. Ignored if `color` is also set.
|
||||
|
||||
cmap : str (default None)
|
||||
The name of a colormap recognized by matplotlib.
|
||||
|
||||
categorical : bool (default False)
|
||||
If False, cmap will reflect numerical values of the
|
||||
column being plotted. For non-numerical columns (or if
|
||||
column=None), this will be set to True.
|
||||
|
||||
cmap : str (default 'Set1')
|
||||
The name of a colormap recognized by matplotlib.
|
||||
column being plotted. For non-numerical columns, this
|
||||
will be set to True.
|
||||
|
||||
color : str (default None)
|
||||
If specified, all objects will be colored uniformly.
|
||||
|
||||
linewidth : float (default 1.0)
|
||||
Line width for geometries.
|
||||
|
||||
legend : bool (default False)
|
||||
Plot a legend. Ignored if no `column` is given, or if `color` is given.
|
||||
|
||||
ax : matplotlib.pyplot.Artist (default None)
|
||||
axes on which to draw the plot
|
||||
|
||||
scheme : pysal.esda.mapclassify.Map_Classifier
|
||||
Choropleth classification schemes (requires PySAL)
|
||||
scheme : str (default None)
|
||||
Name of a choropleth classification scheme (requires PySAL).
|
||||
A pysal.esda.mapclassify.Map_Classifier object will be used
|
||||
under the hood. Supported schemes: 'Equal_interval', 'Quantiles',
|
||||
'Fisher_Jenks'
|
||||
|
||||
k : int (default 5)
|
||||
Number of classes (ignored if scheme is None)
|
||||
|
||||
vmin : None or float (default None)
|
||||
|
||||
Minimum value of cmap. If None, the minimum data value
|
||||
in the column to be plotted is used.
|
||||
|
||||
vmax : None or float (default None)
|
||||
|
||||
Maximum value of cmap. If None, the maximum data value
|
||||
in the column to be plotted is used.
|
||||
|
||||
@@ -381,33 +366,35 @@ def plot_dataframe(df, column=None, cmap=None, color=None, linewidth=1.0,
|
||||
Size of the resulting matplotlib.figure.Figure. If the argument
|
||||
axes is given explicitly, figsize is ignored.
|
||||
|
||||
**color_kwds : dict
|
||||
Color options to be passed on to the actual plot function
|
||||
**style_kwds : dict
|
||||
Color options to be passed on to the actual plot function, such
|
||||
as ``edgecolor``, ``facecolor``, ``linewidth``, ``markersize``,
|
||||
``alpha``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
matplotlib axes instance
|
||||
|
||||
"""
|
||||
if 'colormap' in color_kwds:
|
||||
if 'colormap' in style_kwds:
|
||||
warnings.warn("'colormap' is deprecated, please use 'cmap' instead "
|
||||
"(for consistency with matplotlib)", FutureWarning)
|
||||
cmap = color_kwds.pop('colormap')
|
||||
if 'axes' in color_kwds:
|
||||
cmap = style_kwds.pop('colormap')
|
||||
if 'axes' in style_kwds:
|
||||
warnings.warn("'axes' is deprecated, please use 'ax' instead "
|
||||
"(for consistency with pandas)", FutureWarning)
|
||||
ax = color_kwds.pop('axes')
|
||||
ax = style_kwds.pop('axes')
|
||||
if column and color:
|
||||
warnings.warn("Only specify one of 'column' or 'color'. Using "
|
||||
"'color'.", UserWarning)
|
||||
column = None
|
||||
|
||||
import matplotlib
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
if column is None:
|
||||
return plot_series(df.geometry, cmap=cmap, color=color,
|
||||
ax=ax, linewidth=linewidth, figsize=figsize,
|
||||
**color_kwds)
|
||||
return plot_series(df.geometry, cmap=cmap, color=color, ax=ax,
|
||||
figsize=figsize, **style_kwds)
|
||||
|
||||
if df[column].dtype is np.dtype('O'):
|
||||
categorical = True
|
||||
@@ -415,7 +402,10 @@ def plot_dataframe(df, column=None, cmap=None, color=None, linewidth=1.0,
|
||||
# Define `values` as a Series
|
||||
if categorical:
|
||||
if cmap is None:
|
||||
cmap = 'Set1'
|
||||
if LooseVersion(matplotlib.__version__) >= '2.0':
|
||||
cmap = 'tab10'
|
||||
else:
|
||||
cmap = 'Set1'
|
||||
categories = list(set(df[column].values))
|
||||
categories.sort()
|
||||
valuemap = dict([(k, v) for (v, k) in enumerate(categories)])
|
||||
@@ -449,21 +439,19 @@ def plot_dataframe(df, column=None, cmap=None, color=None, linewidth=1.0,
|
||||
polys = df.geometry[poly_idx]
|
||||
if not polys.empty:
|
||||
plot_polygon_collection(ax, polys, values[poly_idx],
|
||||
vmin=mn, vmax=mx, cmap=cmap,
|
||||
linewidth=linewidth, **color_kwds)
|
||||
vmin=mn, vmax=mx, cmap=cmap, **style_kwds)
|
||||
|
||||
# plot all LineStrings and MultiLineString components in same collection
|
||||
lines = df.geometry[line_idx]
|
||||
if not lines.empty:
|
||||
plot_linestring_collection(ax, lines, values[line_idx],
|
||||
vmin=mn, vmax=mx, cmap=cmap,
|
||||
linewidth=linewidth, **color_kwds)
|
||||
vmin=mn, vmax=mx, cmap=cmap, **style_kwds)
|
||||
|
||||
# plot all Points in the same collection
|
||||
points = df.geometry[point_idx]
|
||||
if not points.empty:
|
||||
plot_point_collection(ax, points, values[point_idx],
|
||||
vmin=mn, vmax=mx, cmap=cmap, **color_kwds)
|
||||
vmin=mn, vmax=mx, cmap=cmap, **style_kwds)
|
||||
|
||||
if legend and not color:
|
||||
from matplotlib.lines import Line2D
|
||||
@@ -477,7 +465,7 @@ def plot_dataframe(df, column=None, cmap=None, color=None, linewidth=1.0,
|
||||
for value, cat in enumerate(categories):
|
||||
patches.append(
|
||||
Line2D([0], [0], linestyle="none", marker="o",
|
||||
alpha=color_kwds.get('alpha', 0.5), markersize=10,
|
||||
alpha=style_kwds.get('alpha', 1), markersize=10,
|
||||
markerfacecolor=n_cmap.to_rgba(value)))
|
||||
ax.legend(patches, categories, numpoints=1, loc='best')
|
||||
else:
|
||||
|
||||
@@ -32,10 +32,6 @@ except KeyError:
|
||||
class TestPointPlotting:
|
||||
|
||||
def setup_method(self):
|
||||
# scatterplot does not yet accept list of colors in matplotlib 1.4.3
|
||||
# if we change the default to uniform, this might work again
|
||||
pytest.importorskip('matplotlib', '1.5.0')
|
||||
|
||||
self.N = 10
|
||||
self.points = GeoSeries(Point(i, i) for i in range(self.N))
|
||||
values = np.arange(self.N)
|
||||
@@ -51,45 +47,50 @@ class TestPointPlotting:
|
||||
|
||||
def test_default_colors(self):
|
||||
|
||||
# # without specifying values -> max 9 different colors
|
||||
# # without specifying values -> uniform color
|
||||
|
||||
# GeoSeries
|
||||
ax = self.points.plot()
|
||||
cmap = plt.get_cmap('Set1', 9)
|
||||
expected_colors = cmap(list(range(9))*2)
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(), expected_colors)
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(),
|
||||
[MPL_DFT_COLOR] * self.N)
|
||||
|
||||
# GeoDataFrame -> uses 'jet' instead of 'Set1'
|
||||
# GeoDataFrame
|
||||
ax = self.df.plot()
|
||||
cmap = plt.get_cmap(lut=9)
|
||||
expected_colors = cmap(list(range(9))*2)
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(), expected_colors)
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(),
|
||||
[MPL_DFT_COLOR] * self.N)
|
||||
|
||||
# # with specifying values -> different colors for all 10 values
|
||||
ax = self.df.plot(column='values')
|
||||
cmap = plt.get_cmap()
|
||||
expected_colors = cmap(np.arange(self.N)/(self.N-1))
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(), expected_colors)
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(),
|
||||
expected_colors)
|
||||
|
||||
def test_colormap(self):
|
||||
|
||||
# # without specifying values -> max 9 different colors
|
||||
# without specifying values but cmap specified -> no uniform color
|
||||
# but different colors for all points
|
||||
|
||||
# GeoSeries
|
||||
ax = self.points.plot(cmap='RdYlGn')
|
||||
cmap = plt.get_cmap('RdYlGn', 9)
|
||||
expected_colors = cmap(list(range(9))*2)
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(), expected_colors)
|
||||
cmap = plt.get_cmap('RdYlGn')
|
||||
exp_colors = cmap(np.arange(self.N) / (self.N - 1))
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(), exp_colors)
|
||||
|
||||
# GeoDataFrame -> same as GeoSeries in this case
|
||||
ax = self.df.plot(cmap='RdYlGn')
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(), expected_colors)
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(), exp_colors)
|
||||
|
||||
# # with specifying values -> different colors for all 10 values
|
||||
ax = self.df.plot(column='values', cmap='RdYlGn')
|
||||
cmap = plt.get_cmap('RdYlGn')
|
||||
expected_colors = cmap(np.arange(self.N)/(self.N-1))
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(), expected_colors)
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(), exp_colors)
|
||||
|
||||
# when using a cmap with specified lut -> limited number of different
|
||||
# colors
|
||||
ax = self.points.plot(cmap=plt.get_cmap('Set1', lut=5))
|
||||
cmap = plt.get_cmap('Set1', lut=5)
|
||||
exp_colors = cmap(list(range(5))*3)
|
||||
_check_colors(self.N, ax.collections[0].get_facecolors(), exp_colors)
|
||||
|
||||
def test_single_color(self):
|
||||
|
||||
@@ -106,7 +107,6 @@ class TestPointPlotting:
|
||||
|
||||
def test_style_kwargs(self):
|
||||
|
||||
# markersize
|
||||
ax = self.points.plot(markersize=10)
|
||||
assert ax.collections[0].get_sizes() == [10]
|
||||
|
||||
@@ -150,10 +150,6 @@ class TestPointPlotting:
|
||||
class TestPointZPlotting:
|
||||
|
||||
def setup_method(self):
|
||||
# scatterplot does not yet accept list of colors in matplotlib 1.4.3
|
||||
# if we change the default to uniform, this might work again
|
||||
pytest.importorskip('matplotlib', '1.5.0')
|
||||
|
||||
self.N = 10
|
||||
self.points = GeoSeries(Point(i, i, i) for i in range(self.N))
|
||||
values = np.arange(self.N)
|
||||
@@ -189,20 +185,20 @@ class TestLineStringPlotting:
|
||||
|
||||
def test_style_kwargs(self):
|
||||
|
||||
# linestyle
|
||||
# linestyle (style patterns depend on linewidth, therefore pin to 1)
|
||||
linestyle = 'dashed'
|
||||
ax = self.lines.plot(linestyle=linestyle)
|
||||
ax = self.lines.plot(linestyle=linestyle, linewidth=1)
|
||||
exp_ls = _style_to_linestring_onoffseq(linestyle)
|
||||
for ls in ax.collections[0].get_linestyles():
|
||||
assert ls[0] == exp_ls[0]
|
||||
assert tuple(ls[1]) == exp_ls[1]
|
||||
|
||||
ax = self.df.plot(linestyle=linestyle)
|
||||
ax = self.df.plot(linestyle=linestyle, linewidth=1)
|
||||
for ls in ax.collections[0].get_linestyles():
|
||||
assert ls[0] == exp_ls[0]
|
||||
assert tuple(ls[1]) == exp_ls[1]
|
||||
|
||||
ax = self.df.plot(column='values', linestyle=linestyle)
|
||||
ax = self.df.plot(column='values', linestyle=linestyle, linewidth=1)
|
||||
for ls in ax.collections[0].get_linestyles():
|
||||
assert ls[0] == exp_ls[0]
|
||||
assert tuple(ls[1]) == exp_ls[1]
|
||||
@@ -225,21 +221,20 @@ class TestPolygonPlotting:
|
||||
def test_single_color(self):
|
||||
|
||||
ax = self.polys.plot(color='green')
|
||||
_check_colors(2, ax.collections[0].get_facecolors(), ['green']*2, alpha=0.5)
|
||||
_check_colors(2, ax.collections[0].get_facecolors(), ['green']*2)
|
||||
# color only sets facecolor
|
||||
_check_colors(2, ax.collections[0].get_edgecolors(), ['k'] * 2, alpha=0.5)
|
||||
_check_colors(2, ax.collections[0].get_edgecolors(), ['k'] * 2)
|
||||
|
||||
ax = self.df.plot(color='green')
|
||||
_check_colors(2, ax.collections[0].get_facecolors(), ['green']*2, alpha=0.5)
|
||||
_check_colors(2, ax.collections[0].get_edgecolors(), ['k'] * 2, alpha=0.5)
|
||||
_check_colors(2, ax.collections[0].get_facecolors(), ['green']*2)
|
||||
_check_colors(2, ax.collections[0].get_edgecolors(), ['k'] * 2)
|
||||
|
||||
with warnings.catch_warnings(record=True) as _: # don't print warning
|
||||
# 'color' overrides 'values'
|
||||
ax = self.df.plot(column='values', color='green')
|
||||
_check_colors(2, ax.collections[0].get_facecolors(), ['green']*2, alpha=0.5)
|
||||
_check_colors(2, ax.collections[0].get_facecolors(), ['green']*2)
|
||||
|
||||
def test_vmin_vmax(self):
|
||||
|
||||
# when vmin == vmax, all polygons should be the same color
|
||||
|
||||
# non-categorical
|
||||
@@ -256,7 +251,7 @@ class TestPolygonPlotting:
|
||||
|
||||
# facecolor overrides default cmap when color is not set
|
||||
ax = self.polys.plot(facecolor='k')
|
||||
_check_colors(2, ax.collections[0].get_facecolors(), ['k']*2, alpha=0.5)
|
||||
_check_colors(2, ax.collections[0].get_facecolors(), ['k']*2)
|
||||
|
||||
# facecolor overrides more general-purpose color when both are set
|
||||
ax = self.polys.plot(color='red', facecolor='k')
|
||||
@@ -265,30 +260,30 @@ class TestPolygonPlotting:
|
||||
|
||||
# edgecolor
|
||||
ax = self.polys.plot(edgecolor='red')
|
||||
np.testing.assert_array_equal([(1, 0, 0, 0.5)],
|
||||
np.testing.assert_array_equal([(1, 0, 0, 1)],
|
||||
ax.collections[0].get_edgecolors())
|
||||
|
||||
ax = self.df.plot('values', edgecolor='red')
|
||||
np.testing.assert_array_equal([(1, 0, 0, 0.5)],
|
||||
np.testing.assert_array_equal([(1, 0, 0, 1)],
|
||||
ax.collections[0].get_edgecolors())
|
||||
|
||||
# alpha sets both edge and face
|
||||
ax = self.polys.plot(facecolor='g', edgecolor='r', alpha=0.4)
|
||||
_check_colors(2, ax.collections[0].get_facecolors(), ['g'] * 2, alpha=0.4)
|
||||
_check_colors(2, ax.collections[0].get_edgecolors(), ['r'] * 2, alpha=0.4)
|
||||
|
||||
def test_multipolygons(self):
|
||||
|
||||
# MultiPolygons
|
||||
ax = self.df2.plot()
|
||||
assert len(ax.collections[0].get_paths()) == 4
|
||||
_check_colors(4, ax.collections[0].get_facecolors(), [MPL_DFT_COLOR]*4)
|
||||
|
||||
ax = self.df2.plot('values')
|
||||
cmap = plt.get_cmap(lut=2)
|
||||
# colors are repeated for all components within a MultiPolygon
|
||||
expected_colors = [cmap(0), cmap(0), cmap(1), cmap(1)]
|
||||
# TODO multipolygons don't work yet when values are not specified
|
||||
# values are flattended, but color not yet (can fix, but we are
|
||||
# thinking to use uniform coloring by default, which would also fix
|
||||
# this)
|
||||
# _check_colors(4, ax.collections[0], expected_colors, alpha=0.5)
|
||||
|
||||
ax = self.df2.plot('values')
|
||||
# specifying values -> same as without values in this case.
|
||||
_check_colors(4, ax.collections[0].get_facecolors(), expected_colors, alpha=0.5)
|
||||
_check_colors(4, ax.collections[0].get_facecolors(), expected_colors)
|
||||
|
||||
|
||||
class TestPolygonZPlotting:
|
||||
@@ -321,18 +316,22 @@ class TestNonuniformGeometryPlotting:
|
||||
self.series = GeoSeries([poly, line, point])
|
||||
self.df = GeoDataFrame({'geometry': self.series, 'values': [1, 2, 3]})
|
||||
|
||||
def test_colormap(self):
|
||||
def test_colors(self):
|
||||
# default uniform color
|
||||
ax = self.series.plot()
|
||||
_check_colors(1, ax.collections[0].get_facecolors(), [MPL_DFT_COLOR])
|
||||
_check_colors(1, ax.collections[1].get_edgecolors(), [MPL_DFT_COLOR])
|
||||
_check_colors(1, ax.collections[2].get_facecolors(), [MPL_DFT_COLOR])
|
||||
|
||||
# colormap: different colors
|
||||
ax = self.series.plot(cmap='RdYlGn')
|
||||
cmap = plt.get_cmap('RdYlGn', 3)
|
||||
# polygon gets extra alpha. See #266
|
||||
_check_colors(1, ax.collections[0].get_facecolors(), [cmap(0)], alpha=0.5)
|
||||
_check_colors(1, ax.collections[1].get_facecolors(), [cmap(1)], alpha=1) # line
|
||||
_check_colors(1, ax.collections[2].get_facecolors(), [cmap(2)], alpha=1) # point
|
||||
cmap = plt.get_cmap('RdYlGn')
|
||||
exp_colors = cmap(np.arange(3) / (3 - 1))
|
||||
_check_colors(1, ax.collections[0].get_facecolors(), [exp_colors[0]])
|
||||
_check_colors(1, ax.collections[1].get_edgecolors(), [exp_colors[1]])
|
||||
_check_colors(1, ax.collections[2].get_facecolors(), [exp_colors[2]])
|
||||
|
||||
def test_style_kwargs(self):
|
||||
|
||||
# markersize -> only the Point gets it
|
||||
ax = self.series.plot(markersize=10)
|
||||
assert ax.collections[2].get_sizes() == [10]
|
||||
ax = self.df.plot(markersize=10)
|
||||
@@ -378,8 +377,7 @@ class TestPlotCollections:
|
||||
for i in range(self.N)])
|
||||
|
||||
def test_points(self):
|
||||
# scatterplot does not yet accept list of colors in matplotlib 1.4.3
|
||||
# if we change the default to uniform, this might work again
|
||||
# failing with matplotlib 1.4.3 (edge stays black even when specified)
|
||||
pytest.importorskip('matplotlib', '1.5.0')
|
||||
|
||||
from geopandas.plotting import plot_point_collection
|
||||
@@ -422,12 +420,11 @@ class TestPlotCollections:
|
||||
# default colormap
|
||||
fig, ax = plt.subplots()
|
||||
coll = plot_point_collection(ax, self.points, self.values)
|
||||
fig.canvas.draw_idle()
|
||||
cmap = plt.get_cmap()
|
||||
expected_colors = cmap(np.arange(self.N))
|
||||
|
||||
# not sure why this is failing (gives only a single color, when
|
||||
# testing outside of pytest, this works perfectly
|
||||
# _check_colors(self.N, coll.get_facecolors(), expected_colors)
|
||||
expected_colors = cmap(np.arange(self.N) / (self.N - 1))
|
||||
_check_colors(self.N, coll.get_facecolors(), expected_colors)
|
||||
# edgecolor depends on matplotlib version
|
||||
# _check_colors(self.N, coll.get_edgecolors(), expected_colors)
|
||||
|
||||
def test_linestrings(self):
|
||||
@@ -463,7 +460,8 @@ class TestPlotCollections:
|
||||
ax.cla()
|
||||
|
||||
# pass through of kwargs
|
||||
coll = plot_linestring_collection(ax, self.lines, linestyle='--')
|
||||
coll = plot_linestring_collection(ax, self.lines, linestyle='--',
|
||||
linewidth=1)
|
||||
exp_ls = _style_to_linestring_onoffseq('dashed')
|
||||
res_ls = coll.get_linestyle()[0]
|
||||
assert res_ls[0] == exp_ls[0]
|
||||
@@ -477,28 +475,28 @@ class TestPlotCollections:
|
||||
|
||||
# default colormap
|
||||
coll = plot_linestring_collection(ax, self.lines, self.values)
|
||||
fig.canvas.draw_idle()
|
||||
cmap = plt.get_cmap()
|
||||
expected_colors = cmap(np.arange(self.N))
|
||||
# failing, see above with points
|
||||
# _check_colors(self.N, coll.get_color(), expected_colors)
|
||||
expected_colors = cmap(np.arange(self.N) / (self.N - 1))
|
||||
_check_colors(self.N, coll.get_color(), expected_colors)
|
||||
ax.cla()
|
||||
|
||||
# specify colormap
|
||||
coll = plot_linestring_collection(ax, self.lines, self.values,
|
||||
cmap='RdBu')
|
||||
fig.canvas.draw_idle()
|
||||
cmap = plt.get_cmap('RdBu')
|
||||
expected_colors = cmap(np.arange(self.N))
|
||||
# failing, see above with points
|
||||
# _check_colors(self.N, coll.get_color(), expected_colors)
|
||||
expected_colors = cmap(np.arange(self.N) / (self.N - 1))
|
||||
_check_colors(self.N, coll.get_color(), expected_colors)
|
||||
ax.cla()
|
||||
|
||||
# specify vmin/vmax
|
||||
coll = plot_linestring_collection(ax, self.lines, self.values,
|
||||
vmin=3, vmax=5)
|
||||
fig.canvas.draw_idle()
|
||||
cmap = plt.get_cmap()
|
||||
expected_colors = cmap([0])
|
||||
# failing, see above with points
|
||||
# _check_colors(self.N, coll.get_color(), expected_colors)
|
||||
_check_colors(self.N, coll.get_color(), expected_colors)
|
||||
ax.cla()
|
||||
|
||||
def test_polygons(self):
|
||||
@@ -511,31 +509,28 @@ class TestPlotCollections:
|
||||
ax.cla()
|
||||
|
||||
# default: single default matplotlib color
|
||||
# but with default alpha of 0.5 and black edgecolor
|
||||
coll = plot_polygon_collection(ax, self.polygons)
|
||||
_check_colors(self.N, coll.get_facecolor(), [MPL_DFT_COLOR] * self.N,
|
||||
alpha=0.5)
|
||||
_check_colors(self.N, coll.get_edgecolor(), ['k'] * self.N, alpha=0.5)
|
||||
_check_colors(self.N, coll.get_facecolor(), [MPL_DFT_COLOR] * self.N)
|
||||
_check_colors(self.N, coll.get_edgecolor(), ['k'] * self.N)
|
||||
ax.cla()
|
||||
|
||||
# default: color sets both facecolor and edgecolor
|
||||
# TODO but test fails for edge (still black)
|
||||
coll = plot_polygon_collection(ax, self.polygons, color='g')
|
||||
_check_colors(self.N, coll.get_facecolor(), ['g'] * self.N, alpha=0.5)
|
||||
# _check_colors(self.N, coll.get_edgecolor(), ['g'] * self.N, alpha=0.5)
|
||||
_check_colors(self.N, coll.get_facecolor(), ['g'] * self.N)
|
||||
_check_colors(self.N, coll.get_edgecolor(), ['g'] * self.N)
|
||||
ax.cla()
|
||||
|
||||
# only setting facecolor keeps default for edgecolor
|
||||
coll = plot_polygon_collection(ax, self.polygons, facecolor='g')
|
||||
_check_colors(self.N, coll.get_facecolor(), ['g'] * self.N, alpha=0.5)
|
||||
_check_colors(self.N, coll.get_edgecolor(), ['k'] * self.N, alpha=0.5)
|
||||
_check_colors(self.N, coll.get_facecolor(), ['g'] * self.N)
|
||||
_check_colors(self.N, coll.get_edgecolor(), ['k'] * self.N)
|
||||
ax.cla()
|
||||
|
||||
# custom facecolor and edgecolor
|
||||
coll = plot_polygon_collection(ax, self.polygons, facecolor='g',
|
||||
edgecolor='r')
|
||||
_check_colors(self.N, coll.get_facecolor(), ['g'] * self.N, alpha=0.5)
|
||||
_check_colors(self.N, coll.get_edgecolor(), ['r'] * self.N, alpha=0.5)
|
||||
_check_colors(self.N, coll.get_facecolor(), ['g'] * self.N)
|
||||
_check_colors(self.N, coll.get_edgecolor(), ['r'] * self.N)
|
||||
ax.cla()
|
||||
|
||||
def test_polygons_values(self):
|
||||
@@ -545,39 +540,40 @@ class TestPlotCollections:
|
||||
|
||||
# default colormap, edge is still black by default
|
||||
coll = plot_polygon_collection(ax, self.polygons, self.values)
|
||||
fig.canvas.draw_idle()
|
||||
cmap = plt.get_cmap()
|
||||
exp_colors = cmap(np.arange(self.N))
|
||||
# failing, see above with points
|
||||
# _check_colors(self.N, coll.get_facecolor(), exp_colors, alpha=0.5)
|
||||
_check_colors(self.N, coll.get_edgecolor(), ['k'] * self.N, alpha=0.5)
|
||||
exp_colors = cmap(np.arange(self.N) / (self.N - 1))
|
||||
_check_colors(self.N, coll.get_facecolor(), exp_colors)
|
||||
# edgecolor depends on matplotlib version
|
||||
#_check_colors(self.N, coll.get_edgecolor(), ['k'] * self.N)
|
||||
ax.cla()
|
||||
|
||||
# specify colormap
|
||||
coll = plot_polygon_collection(ax, self.polygons, self.values,
|
||||
cmap='RdBu')
|
||||
fig.canvas.draw_idle()
|
||||
cmap = plt.get_cmap('RdBu')
|
||||
exp_colors = cmap(np.arange(self.N))
|
||||
# failing, see above with points
|
||||
# _check_colors(self.N, coll.get_facecolor(), exp_colors, alpha=0.5)
|
||||
exp_colors = cmap(np.arange(self.N) / (self.N - 1))
|
||||
_check_colors(self.N, coll.get_facecolor(), exp_colors)
|
||||
ax.cla()
|
||||
|
||||
# specify vmin/vmax
|
||||
coll = plot_polygon_collection(ax, self.polygons, self.values,
|
||||
vmin=3, vmax=5)
|
||||
fig.canvas.draw_idle()
|
||||
cmap = plt.get_cmap()
|
||||
exp_colors = cmap([0])
|
||||
# failing, see above with points
|
||||
# _check_colors(self.N, coll.get_facecolor(), exp_colors, alpha=0.5)
|
||||
_check_colors(self.N, coll.get_facecolor(), exp_colors)
|
||||
ax.cla()
|
||||
|
||||
# override edgecolor
|
||||
coll = plot_polygon_collection(ax, self.polygons, self.values,
|
||||
edgecolor='g')
|
||||
fig.canvas.draw_idle()
|
||||
cmap = plt.get_cmap()
|
||||
exp_colors = cmap(np.arange(self.N))
|
||||
# failing, see above with points
|
||||
# _check_colors(self.N, coll.get_facecolor(), exp_colors, alpha=0.5)
|
||||
_check_colors(self.N, coll.get_edgecolor(), ['g'] * self.N, alpha=0.5)
|
||||
exp_colors = cmap(np.arange(self.N) / (self.N - 1))
|
||||
_check_colors(self.N, coll.get_facecolor(), exp_colors)
|
||||
_check_colors(self.N, coll.get_edgecolor(), ['g'] * self.N)
|
||||
ax.cla()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user