Daniela Osorio
Daniela Osorio

Reputation: 3

How to make a plot of a circle with dashed coloured border in MATLAB?

So i have this code to obtain radial gravity on Earth in function of the latitude:

G=6.6e-11; 

M=5.976e24; 

N=1000;

r=6371000; 

w=2*pi/(24*3600); 

for i=1:1:360
  Theta=i*pi/180;
  x(i)=i;
  Vi(i)=-G*M/(r*r);
  Phii(i)=r*w*w*sin(Theta)*sin(Theta);
  gr(i)=Vi(i)+Phii(i);
end

plot(x,gr)

And it runs well. I want to make a graph of a circle made of a border of points (representing angle (i)) that change colour according to the value of gr(I want to set ranges of values of gr so that if the value obtained falls in a specific category, the point will have a specific colour). I'm really new to MATLAB. Is there any possible way to make this?

Thanks in advance.

Upvotes: 0

Views: 700

Answers (1)

rayryeng
rayryeng

Reputation: 104504

Here is the basic algorithm that I would do:

  1. Determine how many colours you want to represent in your plot.
  2. Create a colour map that has this many points for what you want to compute.
  3. Determine a linearly increasing vector that varies from the minimum value of gr to the maximum value of gr with as many points as you have determined in Step #2
  4. For each point in gr:

    a. Determine which point yields the closest distance of this point to the vector in Step #3

    b. Use this to index which colour you want.

    c. Convert your angle into Cartesian co-ordinates, then plot this point with the colour found in Step 4b.

Let's tackle each point in detail.


Step #1 - Determine how many colours you want

This is pretty simple. Just determine how many colours you want. For now, let's assume that you want 20 colours, so:

num_colours = 20;

Step #2 - Create a colour map

What we can do is create a 20 x 3 matrix where each row determines a RGB tuple that denotes the amount of red, green and blue that each colour will occupy. MATLAB has built-in colour maps that will help you facilitate this. Here are all of the available colour maps that MATLAB has:

Each colour map has a special variable where you can provide it an integer number, and it'll return this 2D matrix of as many rows as the number you have provided. Each row gives you an RGB triplet which denotes the proportion of red, green and blue respectively. This matrix varies from the beginning of the colour map (top row) to the end (bottom row). All you have to do is use any name seen in the figure I've shown you above to create a colour map of that type. For example, if you wanted to get a bones colour map of 15 points, simply do:

colour_map = bones(15);

If you wanted to get a jet colour map of 25 points, simply do:

colour_map = jet(25);

.... you get the idea right? I like hsv so let's use the HSV colour map. You can use any colour map you want, but let's just stick with HSV for the sake of this example.

As such:

colour_map = hsv(num_colours);

Step #3 - Get that linearly increasing vector

You want certain colours to map into certain ranges, which is why this step is important. Given a value in gr, we want to figure out which colour we want to choose, and all you have to do is determine which value in gr is the closest to a value in this vector in Step #3. Therefore, you can use linspace to do this for you:

bin_vector = linspace(min(gr), max(gr), num_colours);

This will create a num_colours 1D array where the beginning of this array starts at the minimum value of gr and varies up to the maximum value of gr and each value is equally spaced such that we generate a num_colours array.

Step #4 - Bring it all home

Now, for each point in gr, we need to figure out which point is the closest to that vector in Step #3, we then use this to figure out the colour we want, then we need to convert our angle into Cartesian co-ordinates, then plot this point.

For illustration purposes, I'm going to assume your radius is 1. You can figure out how to get the x and y co-ordinates by simply doing cos(theta) and sin(theta), where theta is the angle you are examining. Since your gr array has 360 slots, I'm going to assume a resolution of 1 degree per slot. Therefore, you can easily do this in a for loop. Make sure you use hold on because we are going to call plot multiple times, and we don't want to overwrite the plot each time we call plot. You want all of the points to stay in the plot.

Without further ado:

figure; %// Create blank figure
hold on; %// Remember all points

%// For each point in our array...
for idx = 1 : 360

    %// Find the closest slot between gr and our vector in Step #3
    [~,min_idx] = min(abs(gr(idx) - bin_vector));

    %// Grab this colour
    clr = colour_map(min_idx,:);

    %// Plot the point with this colour
    plot(cosd(idx), sind(idx), '.', 'Color', clr, 'MarkerSize', 10);
end

Take notice that cosd and sind take in degrees as the input argument while cos and sin take in radians. Also, take note that I also changed the size of the point so that it's bigger. With the above logic, and your array in gr, this is what I get:

enter image description here

If you want the radius to get larger, all you have to do is multiply each cosd and sind term with your radius. Therefore, you can do something like this:

radius = 2;

for idx = 1 : 360
    ... %// Insert colour code here 
    ...
    ...

    %// Now plot
    plot(radius*cosd(idx), radius*sind(idx), '.', 'Color', clr, 'MarkerSize', 10);
end

Just leave the code the same, but for the plot command, just multiply each x and y value by the radius.


Minor note in efficiency

The way you're calculating your gr array is using an inefficient for loop. There are some situations (like mine above) where you need to use a for loop, but for simple computations there is no need. It's better if you vectorize its creation. Therefore, you can get rid of the for loop to calculate your gr array like so:

x = 1 : 360;
Theta = x*pi/180;
Phii = r*w*w*sin(Theta).*sin(Theta);
Vi = -G*M/(r*r);
gr = Vi + Phii;

x is simply a vector going from 1 to 360, and that's done in the first line. Also, Vi is just an array which contains a single value and if you know how operations work between a scalar and an array, you can just do an addition with this single value and it'll add every value in your array by this much. As such, there's no need to create an array for Vi. Also, take a look at how I calculated Phii. I'm using element-by-element operations as Theta is now an array. You want to create an array Phii that takes corresponding values of Theta, and applies that formula to each value in Theta to produce Phii.


Hope this helps. Good luck!

Upvotes: 3

Related Questions