How to change color of line within multiple ranges of same line

Lets say I have the following 1xn matrix:
mat =
2
4
8
6
32
64
28
256
512
1024
2048
4096
How can I plot the line to display specific colors along certain ranges (ie. default blue from 1:3, green from 4:7, white/invisible from 8:10, red 11:12)?
The solutions I have found are for x,y plots but I am not sure how apply these display alterations to a matrix/vector (insofar as that is concerned, I do not really understand how Matlab creates x,y plots from one dimensional vectors).
Thanks for any help.

 Accepted Answer

This looks a bit strange, but it does what you want:
mat = [ 2
4
8
16
32
64
128
256
512
1024
2048
4096];
x = [1:size(mat,1)];
rmat = reshape(mat, 3, 4);
rx = reshape(x, 3, 4);
c = [0 0 1; 0 1 0; 1 1 1; 1 0 0];
figure(1)
semilogy(rx(:,1), rmat(:,1), 'Color',c(1,:))
hold on
for k1 = 2:size(rmat,2)
plot(rx(:,k1), rmat(:,k1), 'Color',c(k1,:))
end
hold off
grid
I did a semilogy plot so I could verify that it worked.

15 Comments

Star Strider, thanks for your help. Indeed, your code returns a result that looks like what I had intended.
However, I have come back to the code several times over the past day and cannot fully understand how it is functioning.
I'm to Matlab (and coding in general) and I am learning on my own, so any apologies for seemingly obvious questions - but, here goes:
1). Why is plot(x,y) not sufficient/appropriate for this - why is semilogy necessary?
2). In your for loop, I recognized the structure
m = size(X,dim)
but I am unsure how the scalar of 2 functions here.
3). I'm guessing its a No, but is there a simplified way of achieving a similar result. For ex:
plot(mat(1:3,:), 'Color', 'b', mat(4:7,:), 'Color', 'g', etc...)
4). Is your proposed approach still the most suitable one for a larger matrix? I used a simplified example in my original question hoping to replicate the process with my real matrix, but I've been unsuccessful.
Below is a screen shot of the 32x7 matrix I am working with and another shot of the plot of the 5th column of that matrix. The third screen shot shows how I would like the plot to appear - with a 'gap' between elements 16-17, as opposed to the spike that is currently being plotted.
My data represents two separate events that need to be visually separated (albeit adjacently) in the plot. The plot of this matrix only requires one section to be 'whited-out' but I will also need to white-out multiple sections of other plots. That said, an easier way to implement this kind of display change would be much appreciated.
Thanks for all the help
My pleasure.
1. Using plot will work. It’s difficult to see the smaller values of the plotted line using plot, so I used semilogy to be certain it did what I wanted it to. You can use any plotting function you want.
2. The second argument in size tells it the dimension (here, number of rows) I want to count. For a vector, the length function would work as well. I’m used to using size because then I know exactly what dimension I’m measuring.
3. The way I coded it is about as simple as it gets. What you wrote will work, but my code is a bit more flexible. In your code, you don’t have to use the specific 'Color','b' name value pair, however, since rx(:,k1), rmat(:,k1), 'b' would work as well.
4. I would use my approach with your matrix, although you will have to select the column interval for your independent and dependent variables, and how you want to split them, since I use reshape to make the plotting loop much simpler, and my code design also produces the gaps you want. You have an even number of rows in your matrix, so you can use reshape to plot a specific range of each column from it that you want, as I did with your sample data. (Options for your ‘rx’ and ‘rmat’ sizes are for example (2x16), (4x8), etc.) See the documentation on the reshape function to understand its use and its restrictions.
I can’t follow what your’re plotting, so I’ll stop here.
Thanks for all the info and for helping me along in understanding how this all works.
Ill give it try and hopefully will get it all working.
By changing the white portion of the color plot to magenta, I realized that the code you provided plots on a regular pattern that is repeated 4 times:
skip a data point plot 2 data points
I can see how my question might have insinuated that I was after even/patterned color changes, but that is actually not the case.
In trying to plot uneven lengths of color, I am getting errors and am not sure how to tweak your code to get the result.
How would I achieve:
Red from 1:3 Green from 3:9 Magenta from 11:12
Thanks again
‘Red from 1:3 Green from 3:9 Magenta from 11:12’
Those are irregular indices, so you would have to just kludge it (rather than my more elegant initial solution). This is as efficient a way to do what you want as I can come up with:
mat = [ 2
4
8
16
32
64
128
256
512
1024
2048
4096];
x = [1:size(mat,1)];
ix_mtx = [1 3; 3 9; 11 12];
cv = ['-r'; '-g'; '-m'];
figure(1)
plot(x(ix_mtx(1,:)), mat(ix_mtx(1,:)), cv(1,:))
hold on
for k1 = 2:3
plot(x(ix_mtx(k1,:)), mat(ix_mtx(k1,:)), cv(k1,:))
end
hold off
grid
It creates two matrices, one an index range matrix ‘ix_rng’ and the other a colour vector matrix ‘cv’, plots the first set to create the axes object, then the others with a loop. You can add other colours and line styles and markers to ‘cv’ with the caveat that they all have to have the same number of columns (as a string matrix), or convert it to a cell array (and change the addressing to curly brackets {} in the loop) if the individual rows have different numbers of elements.
Star Strider
Thanks again, but I seem to be getting even further entrenched.
Your explanation of the code appears to make sense and I think I understand how the for loop is creating the plot. However, replicating the process exactly (but with my own matrix data), I end up with an erroneous result.
It looks like my figure is plotting only the first value of range 1:16, the spike between 16:17, the first value of range 17:32.
I have doubled checked for errors, cut/paste, er-typed and typed again for hours and I have no idea how the plotting is different when I use my matrix vs the simple test matrix from your code.
What am I missing here?
Here's the actual matrix
perfectVel = [4
17.4286
30.8572
44.2858
57.7144
71.143
84.5716
98
98
84.5714
71.1428
57.7142
44.2856
30.857
17.4284
4
98
84.5714
71.1428
57.7142
44.2856
30.857
17.4284
4
4
17.4286
30.8572
44.2858
57.7144
71.143
84.5716
98];
Thanks again.
You left out some details that would help me, specifically what you want to do. I infer this:
mat = perfectVel;
x = 1:length(mat);
ix_mtx = [1 16; 16 17; 17 32];
cv = ['-r'; '-g'; '-m'];
figure(1)
plot([x(ix_mtx(1,1):ix_mtx(1,2))], [mat(ix_mtx(1,1):ix_mtx(1,2))], cv(1,:))
hold on
for k1 = 2:3
plot([x(ix_mtx(k1,1):ix_mtx(k1,2))], [mat(ix_mtx(k1,1):ix_mtx(k1,2))], cv(k1,:))
end
hold off
grid
The plot looks a bit strange, but it definitely conforms to your data. I tweaked my code to update it to what I believe you want to do. The original version was intended to work with the data in my original Answer, but your current version is different.
Thank you, the new plot does achieve what I had intended.
I am going to spend some time with this to see if I can understand how it is plotting and to catch what I overlooked when trying to do it on my own.
My pleasure.
A short description of how it works is that it uses one matrix, ‘ix_mtx’ to store the start and end indices as rows (start index in the first column, end index in the second), and the other matrix, ‘cv’, to store the colours and line styles.
The first plot call sets the axes (otherwise hold can give strange results) and plots the data in ‘mat’ defined by the first row of ‘ix_mtx’. The hold on call then allows subsequent overplotting on the same axes. The loop (using ‘k1’ as the counter variable) then does the same thing for the remaining rows of ‘ix_mtx’ and the data they refer to. The hold off call then toggles the hold state so that nothing else plots on those axes. The grid call plots the grid lines.
I have learned over the years to number the figure windows so as not to erase what I’ve already plotted with a subsequent plot call, let the first plot call define the axes before the hold on call, and then specifically do a hold off call. The grid call is optional, but makes reading the plots a lot easier.
The square brackets [] in the plot calls are not necessary and you can remove them. They date from an earlier version of the script (when they were necessary).
Thanks again - I've spent some time understanding how this code is plotting and it just about makes sense (that is, I seem to be able to replicate the desired results).
However, I am curious as to why you had to modify the plot parameters from the first example matrix
mat = [2 4 8 16 32...]
in order to properly plot my actual data. Initially, this was the code you proposed:
figure(1)
plot(x(ix_mtx(1,:)), mat(ix_mtx(1,:)), cv(1,:))
hold on
for k1 = 2:3
plot(x(ix_mtx(k1,:)), mat(ix_mtx(k1,:)), cv(k1,:))
end
However, in order to get the desired results for my actual data you changed it to
figure(1)
plot([x(ix_mtx(1,1):ix_mtx(1,2))], [mat(ix_mtx(1,1):ix_mtx(1,2))], cv(1,:))
hold on
for k1 = 2:3
plot([x(ix_mtx(k1,1):ix_mtx(k1,2))], [mat(ix_mtx(k1,1):ix_mtx(k1,2))], cv(k1,:))
end
The simplified example data mat=[2 4 8 16...] was a 12x1 matrix and my actual data was a 32x1 matrix. Since the essential characteristics of both matrices was the same, why did the plot code have to be altered to work properly? In other words, why was it necessary to more explicitly specify the plotting range for my actual data?
In your original code, all the intervals were equal, so I simply did a reshape call and did the plot.
In your last code, the intervals were not equal, so I created ‘ix_mtx’ to accommodate them. Instead of doing a reshape call (that would have failed), I simply defined your start and end indices, and used those. (My later approach could work with your original data. I had no reason to test that, so I didn’t.)
There are significant differences between what you wanted to do at the start and what you wanted to do at the end. Those changes required a different approach and different code.
Sorry not to have been clear - I was actually referring to this bit of code:
mat = [ 2
4
8
16
32
64
128
256
512
1024
2048
4096];
x = [1:size(mat,1)];
ix_mtx = [1 3; 3 9; 11 12];
cv = ['-r'; '-g'; '-m'];
figure(1)
plot(x(ix_mtx(1,:)), mat(ix_mtx(1,:)), cv(1,:))
hold on
for k1 = 2:3
plot(x(ix_mtx(k1,:)), mat(ix_mtx(k1,:)), cv(k1,:))
end
hold off
grid
Simply substituting the matrix data, I am still not seeing why this code would succeed for an evenly growing matrix, but result in an incorrect plot for an unpatterned matrix (such as with my actual data).
There were errors I didn’t immediately catch in the interim code becasue I didn’t entirely understand what you’re doing. The ‘good’ code is at the beginning and the end, not in between.
I realize which code is best suited for my task, however I am trying to more clearly understand the differences between the code that plots the evenly spaced matrix:
mat = [ 2
4
8
16
32
64
128
256
512
1024
2048
4096];
x = [1:size(mat,1)];
ix_mtx = [1 3; 3 9; 11 12];
cv = ['-r'; '-g'; '-m'];
figure(1)
plot(x(ix_mtx(1,:)), mat(ix_mtx(1,:)), cv(1,:))
hold on
for k1 = 2:3
plot(x(ix_mtx(k1,:)), mat(ix_mtx(k1,:)), cv(k1,:))
end
and the code code that properly plots my data:
mat = perfectVel;
x = 1:length(mat);
ix_mtx = [1 16; 16 17; 17 32];
cv = ['-r'; '-g'; '-m'];
figure(1)
plot([x(ix_mtx(1,1):ix_mtx(1,2))], [mat(ix_mtx(1,1):ix_mtx(1,2))], cv(1,:))
hold on
for k1 = 2:3
plot([x(ix_mtx(k1,1):ix_mtx(k1,2))], [mat(ix_mtx(k1,1):ix_mtx(k1,2))], cv(k1,:))
end
Why is it that I get the following undesired result (image below) when I use the code meant for the evenly spaced matrix? In other words, how is it that an evenly spaced matrix of values allows for the simplified code; why doesn't the same code work for an unpatterned matrix (since it is also n-by-1).
The only thing that I changed in the code for the plot below is the matrix data and the color ranges. I can't see why the code should be different.
It’s because the latest code was written to be more general. The early (particularly first) code was written only for that specific example. The latest code is correct, but you have to make the appropriate changes to it (specifically ‘ix_mtx’) to use it with other data.
You have 32 data in your actual data. To use my original code with it, you would have to do a reshape call that divided it into either a (16x2) or (8x4) matrix (or the obvious transposes of those). The data would not divide as you want them to here.
Not all code is robust, or intended to be. Frequently, here on MATLAB Answers, we write code to Answer only a specific Question. If the actual application is significantly different from the ‘example’ Question, as it was here, the original code will quite likely not work in the code's eventually intended application.
The only reasonably robust code you will find contributed by many of the user community is on the File Exchange. It is robust because it was designed to be, and not as a one-off, as most MATLAB Answers code are.

Sign in to comment.

More Answers (0)

Asked:

JZ
on 5 Dec 2015

Commented:

on 12 Dec 2015

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!