Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Matplotlib subplots not working with seaborn distplot #26

Closed
tommylees112 opened this issue Jul 18, 2019 · 5 comments
Closed

Matplotlib subplots not working with seaborn distplot #26

tommylees112 opened this issue Jul 18, 2019 · 5 comments
Labels

Comments

@tommylees112
Copy link

Code sample, a copy-pastable example if possible

A "Minimal, Complete and Verifiable Example" will make it much easier for maintainers to help you.

import pandas as pd
import xarray as xr
import numpy as np


def drop_nans_and_flatten(dataArray: xr.DataArray) -> np.ndarray:
    """flatten the array and drop nans from that array. Useful for plotting histograms.

    Arguments:
    ---------
    : dataArray (xr.DataArray)
        the DataArray of your value you want to flatten
    """
    # drop NaNs and flatten
    return dataArray.values[~np.isnan(dataArray.values)]


# create dimensions of xarray object
times = pd.date_range(start='1981-01-31', end='2019-04-30', freq='M')
lat = np.linspace(0, 1, 224)
lon = np.linspace(0, 1, 176)

rand_arr = np.random.randn(len(times), len(lat), len(lon))

# create xr.Dataset
coords = {'time': times, 'lat':lat, 'lon':lon}
dims = ['time', 'lat', 'lon']
ds = xr.Dataset({'precip': (dims, rand_arr)}, coords=coords)
ds['month'], ds['year'] = ds['time.month'], ds['time.year']

Making plot using proplot

import proplot as plot
import calendar

f, axs = plot.subplots(nrows=4, ncols=3, axwidth=1.5, figsize=(8,12), share=2) # share=3, span=1,
axs.format(
    xlabel='Precip', ylabel='Density', suptitle='Distribution', 
)

month_abbrs = list(calendar.month_abbr)
mean_ds = ds.groupby('time.month').mean(dim='time')
flattened = []
for mth in np.arange(1, 13):
    ax = axs[mth - 1]
    ax.set_title(month_abbrs[mth])
    print(f"Plotting {month_abbrs[mth]}")
    flat = drop_nans_and_flatten(mean_ds.sel(month=mth).precip)
    flattened.append(flat)
    sns.distplot(flat, ax=ax, **{'kde': False})

Actual result vs. expected result

This should explain why the current behavior is a problem and why the expected result is a better solution.

The proplot returns a plot like follows:
download-25

It looks empty plot. Also the axes are only sharing the x-axis for each column but I want it to be shared across all subplots.

The matplotlib version does what I expect.

fig, axs = plt.subplots(4, 3, figsize=(8, 12), sharex=True, sharey=True)

month_abbrs = [m for m in calendar.month_abbr if m != '']

for mth in range(0, 12):
    ax_ix = np.unravel_index(mth, (4, 3))
    ax = axs[ax_ix]
    mth_str = month_abbrs[mth]
    sns.distplot(flattened[mth], ax=ax)
    ax.set_title(mth_str)

fig.suptitle('Distribution of Rainfall each Month');

download-26

@lukelbd
Copy link
Collaborator

lukelbd commented Jul 18, 2019

Thanks for the examples (and your interest)! Never thought of using seaborn with ProPlot. This is probably related to my fill_between_wrapper overrides. All of ProPlot's plotting wrappers are supposed to be strict supersets/not interfer with usage of the existing matplotlib API, but I appear to have overlooked something. Will get to it within the next few days.

@tommylees112
Copy link
Author

tommylees112 commented Jul 19, 2019 via email

@lukelbd
Copy link
Collaborator

lukelbd commented Jul 30, 2019

Sorry for the delay -- the latest commit (c45c88a) fixes this. The source of the bug is complicated, but basically I was wrapping the matplotlib.axes.Axes.hist method improperly. Try running pip uninstall proplot then re-installing with pip install git+https://github.com/lukelbd/proplot.git#egg=proplot (when ProPlot is officially released it will use a versioning system, but for now I'm just pushing bugfixes directly to master).

Also note that you cannot specify both the figure dimensions and the axes dimensions. If you input the former the latter will be ignored. ProPlot now issues a warning when this happens.

@lukelbd lukelbd closed this as completed Jul 30, 2019
@lukelbd
Copy link
Collaborator

lukelbd commented Jul 31, 2019

And thanks again for posting the example, you made it a very quick fix.

@lukelbd lukelbd added the bug label Sep 14, 2019
@Ntkrell
Copy link

Ntkrell commented Apr 9, 2020

@tommylees112 maybe you can help me with this. When I try and run your code above I get ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all(). Did you ever run into this error?

I just installed proplot so I have version 0.5.0.

Here's the code I used:

import pandas as pd
import xarray as xr
import numpy as np
import seaborn as sns

import proplot as plot
import calendar

def drop_nans_and_flatten(dataArray: xr.DataArray) -> np.ndarray:
    """flatten the array and drop nans from that array. Useful for plotting histograms.

    Arguments:
    ---------
    : dataArray (xr.DataArray)
        the DataArray of your value you want to flatten
    """
    # drop NaNs and flatten
    return dataArray.values[~np.isnan(dataArray.values)]


# create dimensions of xarray object
times = pd.date_range(start='1981-01-31', end='2019-04-30', freq='M')
lat = np.linspace(0, 1, 224)
lon = np.linspace(0, 1, 176)

rand_arr = np.random.randn(len(times), len(lat), len(lon))

# create xr.Dataset
coords = {'time': times, 'lat':lat, 'lon':lon}
dims = ['time', 'lat', 'lon']
ds = xr.Dataset({'precip': (dims, rand_arr)}, coords=coords)
ds['month'], ds['year'] = ds['time.month'], ds['time.year']

f, axs = plot.subplots(nrows=4, ncols=3, axwidth=1.5, figsize=(8,12), share=2) # share=3, span=1,
axs.format(
    xlabel='Precip', ylabel='Density', suptitle='Distribution', 
)

month_abbrs = list(calendar.month_abbr)
mean_ds = ds.groupby('time.month').mean(dim='time')
flattened = []
for mth in np.arange(1, 13):
    ax = axs[mth - 1]
    ax.set_title(month_abbrs[mth])
    print(f"Plotting {month_abbrs[mth]}")
    flat = drop_nans_and_flatten(mean_ds.sel(month=mth).precip)
    flattened.append(flat)
    sns.distplot(flat, ax=ax, **{'kde': False})

And the error:

Plotting Jan
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-1-bea6a445aa3a> in <module>
     46     flat = drop_nans_and_flatten(mean_ds.sel(month=mth).precip)
     47     flattened.append(flat)
---> 48     sns.distplot(flat, ax=ax, **{'kde': False})
     49

~/miniconda3/envs/maize-Toff/lib/python3.7/site-packages/seaborn/distributions.py in distplot(a, bins, hist, kde, rug, fit, hist_kws, kde_kws, rug_kws, fit_kws, color, vertical, norm_hist, axlabel, label, ax)
    226         ax.hist(a, bins, orientation=orientation,
    227                 color=hist_color, **hist_kws)
--> 228         if hist_color != color:
    229             hist_kws["color"] = hist_color
    230

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Bringing this up because I'm trying to make a similar plot (proplot subplots + sns.distplot()) but am running into that ValueError for my code as well. Hoping it's an easy fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants