Search code examples
pythonmatplotlibcolormap

Matplotlib Colormaps – Choosing a different color for each graph/line/subject


I created a script that reads and plots .txt files and their content (numbers/values). Each .txt file is located in a different folder. Each folder, in turn, represents one subject from which the data stems.

This code works fine. Python reads each single .txt. file and plots 23 individual graphs/lines into one single plot. Python uses some standard colors here, i.e., each graph is automatically presented in a different color.

What I would like to do is the following: Instead of using the standard colors that are assigned by python automatically without adding any color related code, I would like to use a specific colormap (for example "plasma") from matplotlib.

The problem: no matter what code from the internet I use, all graphs/lines/subjects always receive the same color (e.g. the first color or last color from the plasma colormap).

How do I specify the code so that every line gets one distinct color from a colormap of choice?

Here is my code:

# Initialize
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
from matplotlib.pyplot import cm

# Numpy.loadtxt – Loads data from a textfile. Scipy.signal.welch – Creation of the FFT/power-spectrum. f, Pxx_den creates the ideal frequencies/FFT (f, Welch = Power Spectrum or Power Spectral Density)
Subjects = ["Subject1", "Subject2", "Subject3", "Subject4", "Subject5", "Subject7", "Subject8", "Subject9", "Subject10", "Subject11", "Subject12", "Subject13",
            "Subject14", "Subject15", "Subject16", "Subject17", "Subject18", "Subject19", "Subject20", "Subject22", "Subject23", "Subject24", "Subject25"]

for Subject in Subjects:

    Subject = np.loadtxt("/volumes/SanDisk2/fmri/dataset/processed/extracted_timeseriespython/restingstate/{0}/TimeSeries.SPC.Core_ROI.{0}.txt".format(Subject), comments="#", delimiter=None,
                         converters=None, skiprows=0, usecols=0, unpack=False, ndmin=0, encoding=None, max_rows=None, like=None)

    f, Welch = signal.welch(Subject, fs=1.0, window="hann", nperseg=None, noverlap=None, nfft=1024, detrend="constant", return_onesided=True, scaling="density", axis=-1, average="mean")

    cmap = plt.get_cmap("inferno")
    slicedCM = cmap(np.linspace(0, 1, len(Subjects)))

    plt.plot(f, Welch, c=slicedCM[Subjects.index(Subject)]) 
    

# Grid labels
plt.title("Power Spectrum for all subjects", fontsize=12, fontweight="bold")
plt.xlabel("Log Frequency [Hz]", fontsize=11, fontweight="bold")
plt.ylabel("Log Power [Hz]", fontsize=11, fontweight="bold")

# Grid dimenions and style
plt.xlim([0.005, 0.2]) # x-axis range
plt.ylim([0, 100]) # y-axis range

plt.xticks(np.arange(0, 0.21, 0.025)) # x ticks range (start, end, step)
plt.yticks(np.arange(0, 101, 10)) # y ticks range (start, end, step)

plt.grid(True) # Show grid
plt.rc("axes", axisbelow=True) # Grid behind figures
plt.rc("grid", linestyle="-", color="black") # Grid look

# Show result
plt.show()

Here is the resulting screenshot, showing that the standard colors are used instead of the desired plasma colormap:

screenshot

I'm running matplotlib 3.5.0 with MacOSX as backend.


Solution

  • One way to achieve your goal is to slice-up a colormap and then plot each line with one of the resulting colors. See the lines below that can be integrated in your code in appropriate places.

    import numpy as np
    import matplotlib.pyplot as plt
    
    # 1. Choose your desired colormap
    cmap = plt.get_cmap('plasma')
    
    # 2. Segmenting the whole range (from 0 to 1) of the color map into multiple segments
    slicedCM = cmap(np.linspace(0, 1, len(Subjects))) 
    
    # 3. Color the i-th line with the i-th color, i.e. slicedCM[i]
    plt.plot(f, Welch, c=slicedCM[Subjects.index(Subject)]) 
    

    (The first two lines can be put in the beginning and you can replace the line plotting curves in your code with the third line of code suggested above.)

    Alternatively, and perhaps a neater approach, is using the below lines inside your main loop through Subjects:

    cmap = plt.get_cmap('inferno')
    plt.plot(f, Welch, c=cmap(Subjects.index(Subject)/len(Subjects))) 
    

    (I see in your question that you are changing Subject when you load the file again into Subject. Just use another variable name, say, data = np.loadtxt... and then f, Welch = signal.welch(data, ..... Keep the codes for plotting with different colors as suggested above and you won't have any problem.)