Home > Back-end >  How to make a 1d array be the color of two 2d arrays in a scatter plot
How to make a 1d array be the color of two 2d arrays in a scatter plot

Time:11-16

The question is not the clearest, but I am basically getting this error when I try to plot different colors vi a colormap on a scatter plot. I have two 2d arrays (x and y) and they are both a size of 42,100. I would like to plot the color but based on a 1D array and the size of 42. However I get a recurrent error:

Please note that this is just an example for reproducibility!

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

# test 

x = np.random.rand(42,100)
y = np.random.rand(42,100)

color = np.arange(0,42,1)

# scatter plot of x and y with no colormap!
plt.scatter(x,y,s=5)
plt.show()

enter image description here

# error occurs when trying to plot the 1D array as the color
plt.scatter(x,y,s=5,c=color,cmap='jet')
plt.show()

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/matplotlib/axes/_axes.py in _parse_scatter_color_args(c, edgecolors, kwargs, xsize, get_next_color_func)
   4349             try:  # Is 'c' acceptable as PathCollection facecolors?
-> 4350                 colors = mcolors.to_rgba_array(c)
   4351             except (TypeError, ValueError) as err:

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/matplotlib/colors.py in to_rgba_array(c, alpha)
    384     else:
--> 385         rgba = np.array([to_rgba(cc) for cc in c])
    386 

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/matplotlib/colors.py in <listcomp>(.0)
    384     else:
--> 385         rgba = np.array([to_rgba(cc) for cc in c])
    386 

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/matplotlib/colors.py in to_rgba(c, alpha)
    205     if rgba is None:  # Suppress exception chaining of cache lookup failure.
--> 206         rgba = _to_rgba_no_colorcycle(c, alpha)
    207         try:

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/matplotlib/colors.py in _to_rgba_no_colorcycle(c, alpha)
    283     if not np.iterable(c):
--> 284         raise ValueError(f"Invalid RGBA argument: {orig_c!r}")
    285     if len(c) not in [3, 4]:

ValueError: Invalid RGBA argument: 0.0

The above exception was the direct cause of the following exception:

ValueError                                Traceback (most recent call last)
/tmp/ipykernel_2811997/1837670260.py in <module>
----> 1 plt.scatter(x,y,s=5,c=color,cmap='jet')
      2 plt.show()

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/matplotlib/pyplot.py in scatter(x, y, s, c, marker, cmap, norm, vmin, vmax, alpha, linewidths, edgecolors, plotnonfinite, data, **kwargs)
   3066         vmin=None, vmax=None, alpha=None, linewidths=None, *,
   3067         edgecolors=None, plotnonfinite=False, data=None, **kwargs):
-> 3068     __ret = gca().scatter(
   3069         x, y, s=s, c=c, marker=marker, cmap=cmap, norm=norm,
   3070         vmin=vmin, vmax=vmax, alpha=alpha, linewidths=linewidths,

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs)
   1359     def inner(ax, *args, data=None, **kwargs):
   1360         if data is None:
-> 1361             return func(ax, *map(sanitize_sequence, args), **kwargs)
   1362 
   1363         bound = new_sig.bind(ax, *args, **kwargs)

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/matplotlib/axes/_axes.py in scatter(self, x, y, s, c, marker, cmap, norm, vmin, vmax, alpha, linewidths, edgecolors, plotnonfinite, **kwargs)
   4514             orig_edgecolor = kwargs.get('edgecolor', None)
   4515         c, colors, edgecolors = \
-> 4516             self._parse_scatter_color_args(
   4517                 c, edgecolors, kwargs, x.size,
   4518                 get_next_color_func=self._get_patches_for_fill.get_next_color)

~/miniconda3/envs/py3_std_maps/lib/python3.9/site-packages/matplotlib/axes/_axes.py in _parse_scatter_color_args(c, edgecolors, kwargs, xsize, get_next_color_func)
   4354                 else:
   4355                     if not valid_shape:
-> 4356                         raise invalid_shape_exception(c.size, xsize) from err
   4357                     # Both the mapping *and* the RGBA conversion failed: pretty
   4358                     # severe failure => one may appreciate a verbose feedback.

ValueError: 'c' argument has 42 elements, which is inconsistent with 'x' and 'y' with size 4200.

It looks like the error has something to do with the shape of the 2d array (reshaped it to 4200...).

The error goes away if you change the color array to match the shape of 4200:

color_but_not_accurate = np.linspace(0,42,4200)

plt.scatter(x,y,s=5,c=color_but_not_accurate,cmap='jet')
plt.show()

But in my real program, I sort of need to retain the color array to be a shape of 42 for the colorbar to make sense. Is there a workaround to this problem? Goal is to plot the scatter plot of x and y (two-d arrays of size 42,100) and then plot the color based on the size of 42? Thanks!

CodePudding user response:

You could use color = np.repeat(np.arange(42), 100), repeating each color value as many times as there are columns in the data.

Here is an example. The number of rows is reduced to 4 and columns to 10 for easier debugging:

import matplotlib.pyplot as plt
import numpy as np

x = np.tile(np.arange(10), 4).reshape(4, 10)
y = (np.random.randn(4, 10)   0.1).cumsum(axis=1)   np.arange(0, 40, 10)[:, np.newaxis]

color = np.repeat(np.arange(x.shape[0]), x.shape[1])

plt.scatter(x, y, s=50, c=color, cmap='plasma')
plt.colorbar(ticks=np.arange(x.shape[0]))
plt.show()

scatter plot of 2D array with colors per row

With the original size of the data, the example would look like:

import matplotlib.pyplot as plt
import numpy as np

x = np.tile(np.arange(100), 42).reshape(42, 100)
y = (np.random.randn(42, 100)   0.01).cumsum(axis=1)   np.arange(0, 420, 10)[:, np.newaxis]

color = np.repeat(np.arange(x.shape[0]), x.shape[1])

plt.scatter(x, y, s=5, c=color, cmap='plasma')
plt.colorbar(ticks=np.arange(x.shape[0]))
plt.show()

scatterplot with 42x100 points colored per row

  • Related