Skip to content

Commit

Permalink
Merge ecd17ea into a54cf2a
Browse files Browse the repository at this point in the history
  • Loading branch information
sarahclaude committed Apr 4, 2024
2 parents a54cf2a + ecd17ea commit e5dc5e6
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 30 deletions.
3 changes: 2 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ Changelog

0.4.0 (unreleased)
------------------
Contributors to this version: Trevor James Smith (:user:`Zeitsperre`), Marco Braun (:user:`vindelico`)
Contributors to this version: Trevor James Smith (:user:`Zeitsperre`), Marco Braun (:user:`vindelico`), Sarah-Claude Bourdeau-Goulet (:user:`Sarahclaude`)

New features and enhancements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Use list or ndarray as levels for colorbar in gridmap and small bug fixes (:pull:`176`).
* Fix NaN issues in ``fg.matplotlib.scattermap`` and extreme values in sizes legend (:pull:`184`).

Internal changes
^^^^^^^^^^^^^^^^
Expand Down
9 changes: 7 additions & 2 deletions docs/notebooks/figanos_docs.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,10 @@
"lat = 45 + np.random.rand(10)*3\n",
"lon = np.linspace(-76,-70, 10)\n",
"tas = 20 + np.random.rand(10)*7\n",
"yrs = (30 * np.random.rand(10)).astype(int)\n",
"tas[9] = np.nan\n",
"yrs = (10+30 * np.random.rand(10))\n",
"yrs[0] = np.nan\n",
"\n",
"attrs = {'units': 'degC', 'standard_name': 'air_temperature', 'long_name': 'Near-Surface Daily Maximum Air Temperature'}\n",
"\n",
"tas = xr.DataArray(data=tas,\n",
Expand Down Expand Up @@ -659,7 +662,9 @@
" features=features,\n",
" plot_kw={\n",
" \"xlim\": (-78,-68),\n",
" \"ylim\": (43,50)},\n",
" \"ylim\": (43,50),\n",
" \"edgecolor\": 'black'\n",
" },\n",
" fig_kw={'figsize': (9,6)},\n",
" legend_kw={'loc': 'lower left',\n",
" 'title': 'Number of years of data'},\n",
Expand Down
73 changes: 47 additions & 26 deletions figanos/matplotlib/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1526,15 +1526,17 @@ def scattermap(
if "row" not in plot_kw and "col" not in plot_kw:
use_attrs.setdefault("title", "description")

# extract plot_kw from dict if needed
if isinstance(data, dict) and plot_kw and list(data.keys())[0] in plot_kw.keys():
plot_kw = plot_kw[list(data.keys())[0]]

plot_kw_pop = plot_kw.copy() # copy plot_kw to modify and pop info in it

# figanos does not use xr.plot.scatter default markersize
if "markersize" in plot_kw.keys():
if not sizes:
sizes = plot_kw["markersize"]
plot_kw.pop("markersize")

# extract plot_kw from dict if needed
if isinstance(data, dict) and plot_kw and list(data.keys())[0] in plot_kw.keys():
plot_kw = plot_kw[list(data.keys())[0]]
plot_kw_pop.pop("markersize")

# if data is dict, extract
if isinstance(data, dict):
Expand Down Expand Up @@ -1574,13 +1576,13 @@ def scattermap(
elif ax is not None and ("col" in plot_kw or "row" in plot_kw):
raise ValueError("Cannot use 'ax' and 'col'/'row' at the same time.")
elif ax is None:
plot_kw = {"subplot_kws": {"projection": projection}} | plot_kw
plot_kw_pop = {"subplot_kws": {"projection": projection}} | plot_kw_pop
cfig_kw = fig_kw.copy()
if "figsize" in fig_kw: # add figsize to plot_kw for facetgrid
plot_kw.setdefault("figsize", fig_kw["figsize"])
plot_kw_pop.setdefault("figsize", fig_kw["figsize"])
cfig_kw.pop("figsize")
if len(cfig_kw) >= 1:
plot_kw = {"subplot_kws": {"projection": projection}} | plot_kw
plot_kw_pop = {"subplot_kws": {"projection": projection}} | plot_kw_pop
warnings.warn(
"Only figsize and figure.add_subplot() arguments can be passed to fig_kw when using facetgrid."
)
Expand All @@ -1600,9 +1602,9 @@ def scattermap(
cbar_label = get_attributes(use_attrs["cbar_label"], data)

if "add_colorbar" not in plot_kw or plot_kw["add_colorbar"] is not False:
plot_kw.setdefault("cbar_kwargs", {})
plot_kw["cbar_kwargs"].setdefault("label", wrap_text(cbar_label))
plot_kw["cbar_kwargs"].setdefault("pad", 0.015)
plot_kw_pop.setdefault("cbar_kwargs", {})
plot_kw_pop["cbar_kwargs"].setdefault("label", wrap_text(cbar_label))
plot_kw_pop["cbar_kwargs"].setdefault("pad", 0.015)

# colormap
if isinstance(cmap, str):
Expand Down Expand Up @@ -1635,7 +1637,7 @@ def scattermap(
if hasattr(data, "name") and getattr(data, "name") == sizes:
sdata = plot_data
elif sizes in list(data.coords.keys()):
sdata = data[sizes]
sdata = plot_data[sizes]
else:
raise ValueError(f"{sizes} not found")
else:
Expand All @@ -1650,46 +1652,65 @@ def scattermap(
mask = smask

pt_sizes = norm2range(
data=sdata.values,
data=sdata.where(mask).values,
target_range=size_range,
data_range=None,
)
plot_kw.setdefault("add_legend", False)
plot_kw_pop.setdefault("add_legend", False)
if ax:
plot_kw.setdefault("s", pt_sizes)
plot_kw_pop.setdefault("s", pt_sizes)
else:
plot_kw.setdefault("s", pt_sizes[0])
plot_kw_pop.setdefault("s", pt_sizes[0])

# norm
plot_kw.setdefault("vmin", np.nanmin(plot_data.values))
plot_kw.setdefault("vmax", np.nanmax(plot_data.values))
plot_kw_pop.setdefault("vmin", np.nanmin(plot_data.values[mask]))
plot_kw_pop.setdefault("vmax", np.nanmax(plot_data.values[mask]))

norm = custom_cmap_norm(
cmap,
vmin=plot_kw["vmin"],
vmax=plot_kw["vmax"],
vmin=plot_kw_pop["vmin"],
vmax=plot_kw_pop["vmax"],
levels=levels,
divergent=divergent,
)

# set defaults and create copy without vmin, vmax (conflicts with norm)
plot_kw = {
plot_kw_pop = {
"cmap": cmap,
"norm": norm,
"transform": transform,
"zorder": 8,
"marker": "o",
"edgecolor": "none",
} | plot_kw
} | plot_kw_pop

# chek if edgecolors in plot_kw and match len of plot_data
if "edgecolors" in plot_kw:
if matplotlib.colors.is_color_like(plot_kw["edgecolors"]):
plot_kw_pop["edgecolors"] = np.repeat(
plot_kw["edgecolors"], len(plot_data.where(mask).values)
)
elif len(plot_kw["edgecolors"]) != len(plot_data.values):
plot_kw_pop["edgecolors"] = np.repeat(
plot_kw["edgecolors"][0], len(plot_data.where(mask).values)
)
warnings.warn(
"Length of edgecolors does not match length of data. Only first edgecolor is used for plotting."
)
else:
if isinstance(plot_kw["edgecolors"], list):
plot_kw_pop["edgecolors"] = np.array(plot_kw["edgecolors"])
plot_kw_pop["edgecolors"] = plot_kw_pop["edgecolors"][mask]
else:
plot_kw_pop.setdefault("edgecolors", "none")

plot_kw_pop = plot_kw.copy()
for key in ["vmin", "vmax"]:
plot_kw_pop.pop(key)
# plot
plot_kw_pop = {"x": "lon", "y": "lat", "hue": plot_data.name} | plot_kw_pop
if ax:
plot_kw_pop.setdefault("ax", ax)
im = data.plot.scatter(**plot_kw_pop)
v = plot_data.where(mask).to_dataset()
im = v.plot.scatter(**plot_kw_pop)

# add features
if ax:
Expand Down Expand Up @@ -1752,7 +1773,7 @@ def scattermap(
np.resize(sdata.values[mask], (sdata.values[mask].size, 1)),
np.resize(pt_sizes[mask], (pt_sizes[mask].size, 1)),
max_entries=6,
marker=plot_kw["marker"],
marker=plot_kw_pop["marker"],
)
# legend spacing
if size_range[1] > 200:
Expand Down
2 changes: 1 addition & 1 deletion figanos/matplotlib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1338,7 +1338,7 @@ def size_legend_elements(
lw=0,
markerfacecolor="w",
label=label,
markersize=np.sqrt(s),
markersize=np.sqrt(np.abs(s)),
)
)

Expand Down

0 comments on commit e5dc5e6

Please sign in to comment.