pythonmatplotliblinestyledrawnow

MatPlotLib Python - RGB values from color sensor used to change color of line point


So I'm working with a TCS3200 color sensor and Arduino Mega 2560 to generate specific RGB values. Then, through the serial cable, I'm sending data to VIDLE for Python, splitting the 3 data points, and storing them in an array (updating the MatPlotLib plot every 50 data points (per RGB).)

Originally I was plotting the R, G, B values on three separate lines...now I'm plotting a different line, based on a (255,255,255) coordinate system (y-limit is 255*sqrt(3)).

What I want to do is this: if my RGB values are (220, 60, 140), I want to be able to change the color of the data point based on those values.

The graph point would be sqrt(pow(220,2.0)+pow(60,2.0)+pow(140,2.0)), but the color needs to reflect the RGB value.

How do I do this?

Here's my current plot setup:

import serial
import numpy as np
import matplotlib.pyplot as plt
from drawnow import *

distance = []
s = serial.Serial(port='/dev/cu.usbmodem1421', baudrate=115200)
plt.ion()
cnt = 0
limit = 255*sqrt(3);
r = 0
g = 0
b = 0

def makeFig():
        plt.ylim(0,limit)
        plt.title('My Live Streaming Sensor Data')
        plt.grid(True)
        plt.ylabel('RGB Values')
        plt.xlabel('Time')
        # somewhere in the line below I think the RGB dynamics should be reflected
        plt.plot(distance, '-', label='Distance')
        plt.ticklabel_format(useOffset=True)
        plt.legend(loc='upper left')

while True:
        while (s.inWaiting()):
               myDataString = s.readline()
               try:
                       dataArray = myDataString.split(',')
                       print (dataArray)
                       r = float(dataArray[0])
                       g = float(dataArray[1])
                       b = float(dataArray[2])
                       d = float(dataArray[3].strip('\r\n')
                       distance.append(d)
                       # before this 'drawnow' gets called, should the RGB values be incorporated into the plot?
                       drawnow(makeFig)
                       plt.pause(0.000001)
                       cnt = cnt + 1
                       if (cnt > 50):
                               distance.pop(0)
               except ValueError:
                       print (myDataString)

Solution

  • Here is a way to plot some dots at the positions corresponding to the distance from the origin in the RGB cube. Their color will be set to the rgb value tuple.

    import numpy as np
    import matplotlib.pyplot as plt
    
    # Mockup Serial
    class Serial():
        n = 0
        def __init__(self, **kwargs):
            self.maxN = kwargs.get("maxN", 1000)
            self.cols = np.arange(0,240,1)
        def inWaiting(self):
            self.n+=1
            return (self.n<self.maxN)
        def readline(self):
            a = np.random.choice(self.cols,size=3)
            a = list(map(str, a))
            b = str(np.random.randint(0,10))
            return ",".join(a)+","+b+'\r\n'
    
    distance = []
    colors = []
    s = Serial(port='/dev/cu.usbmodem1421', baudrate=115200)
    plt.ion()
    cnt = 0
    limit = 255.*np.sqrt(3)
    r = 0
    g = 0
    b = 0
    
    
    plt.ylim(0,limit)
    plt.title('My Live Streaming Sensor Data')
    plt.grid(True)
    plt.ylabel('RGB Values')
    plt.xlabel('Time')
    
    line,   = plt.plot([],[], '-', color="gray",label='Distance')
    scatter  = plt.scatter([],[], s=40, marker='o', label='Hit', zorder=3)
    plt.ticklabel_format(useOffset=True)
    plt.legend(loc='upper left')
    
    
    while (s.inWaiting()):
        myDataString = s.readline()
        dataArray = myDataString.split(',')
        r = int(dataArray[0])
        g = int(dataArray[1])
        b = int(dataArray[2])
        d = int(dataArray[3].strip('\r\n'))
        distance.append(np.sqrt(r**2+b**2+g**2))
        color = (r/255.,g/255.,b/255.)
        colors.append(color)
        x = range(len(distance))
        line.set_data(x, distance)
        scatter.set_offsets(np.c_[x,distance])
        scatter.set_color(colors)
        plt.xlim(min(x), max(x))
        plt.pause(0.01)
        cnt = cnt + 1
        if (cnt > 50):
            distance.pop(0)
            colors.pop(0)
        plt.draw()
    

    enter image description here