4sght
4sght

Reputation: 11

Is it possible to make a colour-blind friendly RGB option in "color" for ax.scatter?

I have scatter plot in which I have colour coded the scatter points according to the relative contribution of 3 factors. I use the red, green and blue channels to represent this. This works really nicely in terms of highlighting problematic configurations.

The issue I have is that in order to make this more widely readable I need to make it colour-blind friendly. Intuitively I feel like this should be possible by replacing the base red, green and blue with other colours. However, I can't see how to achieve this.

For context, the solution that worked the best for my application was to create a smaller 3D subplot which shows the physical meaning behind the different colours. The code below shows the creation of that key, which is itself a scatter plot.

import numpy as np # version 1.19.2
import matplotlib as mp # version 3.3.2
import matplotlib.pyplot as plt
import matplotlib.animation as anim
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d
import mpl_toolkits.mplot3d.art3d as art3d
import scipy.misc as misc
import glob
import pdb
 
####### 3D cube legend ####
class Arrow3D(FancyArrowPatch):
    def __init__(self, xs, ys, zs, *args, **kwargs):
        FancyArrowPatch.__init__(self, (0,0), (0,0), *args, **kwargs)
        self._verts3d = xs, ys, zs

    def draw(self, renderer):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
        self.set_positions((xs[0],ys[0]),(xs[1],ys[1]))
        FancyArrowPatch.draw(self, renderer)


fig1 = plt.figure()
ax2 = fig1.add_axes([0.,0.,1,1],projection='3d')
r = np.arange(0,101,1)[::2]

ax2.invert_xaxis()
intr = 4
X, Y = np.meshgrid(r, r)
XX,YY = np.meshgrid(r[::-1],r[::-1])
for i in r:
    for j in r:
        rot = 40
        # see the commented out lines here
        ax2.scatter(i,0,j,s=50,color=(i/100.,0,j/100.),marker=(4,0,rot))#, cmap="viridis")
        ax2.scatter(i,j,0,s=50,color=(i/100.,j/100.,0),marker=(4,0,rot))#, cmap="viridis")
        ax2.scatter(0,i,j,s=50,color=(0,i/100.,j/100.),marker=(4,0,rot))#, cmap="viridis")

ax2.view_init(-30,-45)
a = Arrow3D([0,110],[0,0],[0,0],mutation_scale=20,lw=3,arrowstyle='-|>',zorder=6*len(r)**2+1,color='grey')
ax2.add_artist(a)
a = Arrow3D([0,0],[0,110],[0,0],mutation_scale=20,lw=3,arrowstyle='-|>',zorder=6*len(r)**2+1,color='grey')
ax2.add_artist(a)
a = Arrow3D([0,0],[0,0],[0,110],mutation_scale=20,lw=3,arrowstyle='-|>',zorder=6*len(r)**2+1,color='grey')
ax2.add_artist(a)
ax2.patch.set_visible(False)

for i in np.arange(10,110,10):
    ax2.plot([0,101.5],[i,i],[0,0],lw=1,color='grey',zorder=6*len(r)**2+1,linestyle='--') # x
    ax2.plot([0,101.5],[0,0],[i,i],lw=1,color='grey',zorder=6*len(r)**2+1,linestyle='--') # x
    ax2.plot([i,i],[0,101.5],[0,0],lw=1,color='grey',zorder=6*len(r)**2+1,linestyle='--') # y
    ax2.plot([0,0],[0,101.5],[i,i],lw=1,color='grey',zorder=6*len(r)**2+1,linestyle='--') # y
    ax2.plot([0,0],[i,i],[0,101.5],lw=1,color='grey',zorder=6*len(r)**2+1,linestyle='--') # z
    ax2.plot([i,i],[0,0],[0,101.5],lw=1,color='grey',zorder=6*len(r)**2+1,linestyle='--') # z

for i in np.arange(20,120,20):
    ax2.text(i+5,110,0,str(float(i)/400.),zorder=6*len(r)**2+2,fontsize=12)
    ax2.text(115,i,0,str(float(i)/100.),zorder=6*len(r)**2+2,fontsize=12)
    ax2.text(0,105,i,str(float(i)/100.),zorder=6*len(r)**2+2,fontsize=12)

ax2.text2D(0.07,0.04,r"Variable a",zorder=6*len(r)**2+3,transform=ax2.transAxes,rotation=-23,fontsize=35)
ax2.text2D(0.56,0.04,r"Variable b",zorder=6*len(r)**2+3,transform=ax2.transAxes,rotation=23,fontsize=35)
ax2.text2D(0.96,0.33,r"Variable c",zorder=6*len(r)**2+3,transform=ax2.transAxes,rotation=-88,fontsize=35)

plt.axis("off")
fig1.set_size_inches(11, 9)
plt.draw()
plt.show()

I have tried to change the colour map to something else (e.g. see the hashed out cmap="viridis") but this is ignored. I feel like something along the lines of this is the way to go, i.e. changing the base colours from red-green-blue, but only if it is not ignored once created.

Effectively, what I want to be able to do is have the ax2.scatter(...,color=(R,G,B)) point to a colour map which is colour-blind friendly.

Upvotes: 1

Views: 35

Answers (1)

Matteo Gomez
Matteo Gomez

Reputation: 1

Actually yes there color codes for this Here some color codes

    (0, 114, 178),   # Blue
    (230, 159, 0),   # Orange
    (86, 180, 233),  # Sky Blue
    (0, 158, 115),   # Bluish Green
    (240, 228, 66),  # Yellow
    (204, 121, 167), # Reddish Purple
    (213, 94, 0),    # Vermillion
    (0, 0, 0),       # Black
]

# Normalize to RGB [0, 1] for matplotlib
colorblind_palette = [(r / 255, g / 255, b / 255) for r, g, b in colorblind_palette]```

Upvotes: 0

Related Questions