How to plot linear regression lines on scatterplots in plotmatrix function in Matlab/Octave GNU? - plot

Data, Plotmatrix, Scatterplot properties, and Histogram properties
clear all; close all; clc;
estudiantes=10;
materias=3;
E=410+fix(rand(1,estudiantes)*(510-410+1));
I=610+fix(rand(1,estudiantes)*(710-610+1));
M=510+fix(rand(1,estudiantes)*(610-510+1));
Y=[E; I; M]'
X=[1:10;1:10;1:10]'; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%h=figure('Position',[1 21 1366 670], ...
h=figure('Position',[1 21 1920 986], ...
'Name',strcat('Correlación entre Materias - ',...
'Pruebas Estandarizadas'));
[s, sax, bigax, h, hax]=plotmatrix(Y);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%s = scatterplot properties
Xlabel=['Español';'Español';'Inglés';'Inglés';'Matemáticas';'Matemáticas'];
Ylabel=['Inglés';'Matemáticás';'Español';'Matemáticas';'Español';'Inglés'];
for i=1:length(s)
set(s(i),'color',[1 0 0],'marker','*','markersize',20, ...
'markerfacecolor','none','markeredgecolor','auto')
set(sax(i),'xlabel',Xlabel(i,:),...
'fontsize',18,'fontweight','bold','fontsizemode','manual')
set(sax(i),'ylabel',Ylabel(i,:),...
'fontsize',18,'fontweight','bold','fontsizemode','manual')
endfor
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%h=histogram properties
Xlabel=['Español';'Inglés';'Matemáticas'];
Ylabel=['Cantidad';'Cantidad';'Cantidad'];
for i=1:length(h)
set(h(i),'edgecolor',[0 0 0],'facecolor',[0 0 1],...
'linestyle','-','linewidth',1,'horizontal','off', ...
'showbaseline','on')
set(hax(i),'xlabel',Xlabel(i,:),...
'fontsize',18,'fontweight','bold','fontsizemode','manual')
set(hax(i),'ylabel',Ylabel(i,:),...
'fontsize',18,'fontweight','bold','fontsizemode','manual')
endfor
This is the output plotmatrix and properties.
randi: Return random integers in the range 1:imax.
fix: Truncate fractional portion of x and return the integer portion.
rand: Return a matrix with random elements uniformly distributed on the interval (0, 1).
figure: Create a new figure window for plotting.
i

Related

How to create julia color scheme for displaying Ct scan Makie.jl

I use makie.jl with slicesNumb for visualization of PET/CT scans, I have 3d array of attenuation values and I display heatmap with changing slices using slider - this works well I have two problems
I do not know how to be able to define custom colormaps (basically I need to be able to specify that all above some threshold value will be black and all below white and values between will have grey values proportional to attenuation value).
2)I would like to be able to display to display over my image (tachnically heatmap) another ones where I would be able to controll transparency - alpha value of pixels - in order to display some annotations/ PET ...
code that works but without those 2 functionalities and how it looks
using GLMakie
```#doc
simple display of single image - only in transverse plane
```
function singleCtScanDisplay(arr ::Array{Number, 3})
fig = Figure()
sl_x = Slider(fig[2, 1], range = 1:1:size(arr)[3], startvalue = 40)
ax = Axis(fig[1, 1])
hm = heatmap!(ax, lift(idx-> arr[:,:, floor(idx)], sl_x.value) ,colormap = :grays)
Colorbar(fig[1, 2], hm)
fig
end
Thanks for help !
You can use Colors and ColorSchemeTools, but you will need to add the top and bottom of the scheme according to your thresholds.
using Colors, ColorSchemeTools
truemin = 0
truemax = 600
max_shown_black = 20
min_shown_white = 500
data = rand(truemin:truemax, (500, 500, 20))
grayscheme = [fill(colorant"black", max_shown_black - truemin + 1);
collect(make_colorscheme(identity, identity, identity,
length = min_shown_white - max_shown_black - 1));
fill(colorant"white", truemax - min_shown_white + 1)]
For controlling alpha, I would add a popup window with an alpha slider. Take a look at some of the distributable DICOM tools for examples.
I finally managed it basically I load 3 dimensional data stored in hdf5 (I loaded it into hdf5 from raw using python)
It enables viewing transverse slices and annotate 3d pathes in a mask that will be displayed over main image
exmpleH = #spawnat persistenceWorker Main.h5manag.getExample()
minimumm = -1000
maximumm = 2000
arrr= fetch(exmpleH)
imageDim = size(arrr)
using GLMakie
maskArr = Observable(BitArray(undef, imageDim))
MyImgeViewer.singleCtScanDisplay(arrr, maskArr,minimumm, maximumm)
Now definition of the required modules
```#doc
functions responsible for displaying medical image Data
```
using DrWatson
#quickactivate "Probabilistic medical segmentation"
module MyImgeViewer
using GLMakie
using Makie
#using GeometryBasics
using GeometricalPredicates
using ColorTypes
using Distributed
using GLMakie
using Main.imageViewerHelper
using Main.workerNumbers
## getting id of workers
```#doc
simple display of single image - only in transverse plane we are adding also a mask that
arrr - main 3 dimensional data representing medical image for example in case of CT each voxel represents value of X ray attenuation
minimumm, maximumm - approximately minimum and maximum values we can have in our image
```
function singleCtScanDisplay(arrr ::Array{Number, 3}, maskArr , minimumm, maximumm)
#we modify 2 pixels just in order to make the color range constant so slices will be displayed in the same windows
arrr[1,1,:].= minimumm
arrr[2,1,:].= maximumm
imageDim = size(arrr) # dimenstion of the primary image for example CT scan
slicesNumb =imageDim[3] # number of slices
#defining layout variables
scene, layout = GLMakie.layoutscene(resolution = (600, 400))
ax1 = layout[1, 1] = GLMakie.Axis(scene, backgroundcolor = :transparent)
ax2 = layout[1, 1] = GLMakie.Axis(scene, backgroundcolor = :transparent)
#control widgets
sl_x =layout[2, 1]= GLMakie.Slider(scene, range = 1:1: slicesNumb , startvalue = slicesNumb/2 )
sliderXVal = sl_x.value
#color maps
cmwhite = cgrad(range(RGBA(10,10,10,0.01), stop=RGBA(0,0,255,0.4), length=10000));
greyss = createMedicalImageColorSchemeB(200,-200,maximumm, minimumm )
####heatmaps
#main heatmap that holds for example Ct scan
currentSliceMain = GLMakie.#lift(arrr[:,:, convert(Int32,$sliderXVal)])
hm = GLMakie.heatmap!(ax1, currentSliceMain ,colormap = greyss)
#helper heatmap designed to respond to both changes in slider and changes in the bit matrix
currentSliceMask = GLMakie.#lift($maskArr[:,:, convert(Int32,$sliderXVal)])
hmB = GLMakie.heatmap!(ax1, currentSliceMask ,colormap = cmwhite)
#adding ability to be able to add information to mask where we clicked so in casse of mit matrix we will set the point where we clicked to 1
indicatorC(ax1,imageDim,scene,maskArr,sliderXVal)
#displaying
colorB = layout[1,2]= Colorbar(scene, hm)
GLMakie.translate!(hmB, Vec3f0(0,0,5))
scene
end
```#doc
inspired by https://github.com/JuliaPlots/Makie.jl/issues/810
Generaly thanks to this function the viewer is able to respond to clicking on the slices and records it in the supplied 3 dimensional AbstractArray
ax - Axis which store our heatmap slices which we want to observe wheather user clicked on them and where
dims - dimensions of main image for example CT
sc - Scene where our axis is
maskArr - the 3 dimensional bit array that has exactly the same dimensions as main Array storing image
sliceNumb - represents on what slide we are on currently on - ussually it just give information from slider
```
function indicatorC(ax::Axis,dims::Tuple{Int64, Int64, Int64},sc::Scene,maskArr,sliceNumb::Observable{Any})
register_interaction!(ax, :indicator) do event::GLMakie.MouseEvent, axis
if event.type === MouseEventTypes.leftclick
println("clicked")
##async begin
#appropriately modyfing wanted pixels in mask array
#async calculateMouseAndSetmaskWrap(maskArr, event,sc,dims,sliceNumb)
#
#
# println("fetched" + fetch(maskA))
# finalize(maskA)
#end
return true
#print("xMouse: $(xMouse) yMouse: $(yMouse) compBoxWidth: $(compBoxWidth) compBoxHeight: $(compBoxHeight) calculatedXpixel: $(calculatedXpixel) calculatedYpixel: $(calculatedYpixel) pixelsNumbInX $(pixelsNumbInX) ")
end
end
end
```#doc
wrapper for calculateMouseAndSetmask - from imageViewerHelper module
given mouse event modifies mask accordingly
maskArr - the 3 dimensional bit array that has exactly the same dimensions as main Array storing image
event - mouse event passed from Makie
sc - scene we are using in Makie
```
function calculateMouseAndSetmaskWrap(maskArr, event,sc,dims,sliceNumb)
maskArr[] = calculateMouseAndSetmask(maskArr, event,sc,dims,sliceNumb)
end
end #module
and helper methods
```#doc
functions responsible for helping in image viewer - those functions are meant to be invoked on separate process
- in parallel
```
using DrWatson
#quickactivate "Probabilistic medical segmentation"
module imageViewerHelper
using Documenter
using ColorTypes
using Colors, ColorSchemeTools
using Makie
export calculateMouseAndSetmask
export createMedicalImageColorSchemeB
# using AbstractPlotting
```#doc
given mouse event modifies mask accordingly
maskArr - the 3 dimensional bit array that has exactly the same dimensions as main Array storing image
event - mouse event passed from Makie
sc - scene we are using in Makie
```
function calculateMouseAndSetmask(maskArr, event,sc,dims,sliceNumb)
#position from top left corner
xMouse= Makie.to_world(sc,event.data)[1]
yMouse= Makie.to_world(sc,event.data)[2]
#data about height and width in layout
compBoxWidth = 510
compBoxHeight = 510
#image dimensions - number of pixels from medical image for example ct scan
pixelsNumbInX =dims[1]
pixelsNumbInY =dims[2]
#calculating over which image pixel we are
calculatedXpixel =convert(Int32, round( (xMouse/compBoxWidth)*pixelsNumbInX) )
calculatedYpixel = convert(Int32,round( (yMouse/compBoxHeight)*pixelsNumbInY ))
sliceNumbConv =convert(Int32,round( sliceNumb[] ))
#appropriately modyfing wanted pixels in mask array
return markMaskArrayPatch( maskArr ,CartesianIndex(calculatedXpixel, calculatedYpixel, sliceNumbConv ),2)
end
```#doc
maskArr - the 3 dimensional bit array that has exactly the same dimensions as main Array storing image
point - cartesian coordinates of point around which we want to modify the 3 dimensional array from 0 to 1
```
function markMaskArrayPatch(maskArr, pointCart::CartesianIndex{3}, patchSize ::Int64)
ones = CartesianIndex(patchSize,patchSize,patchSize) # cartesian 3 dimensional index used for calculations to get range of the cartesian indicis to analyze
maskArrB = maskArr[]
for J in (pointCart-ones):(pointCart+ones)
diff = J - pointCart # diffrence between dimensions relative to point of origin
if cartesianTolinear(diff) <= patchSize
maskArrB[J]=1
end
end
return maskArrB
end
```#doc
works only for 3d cartesian coordinates
cart - cartesian coordinates of point where we will add the dimensions ...
```
function cartesianTolinear(pointCart::CartesianIndex{3}) :: Int16
abs(pointCart[1])+ abs(pointCart[2])+abs(pointCart[3])
end
```#doc
creating grey scheme colors for proper display of medical image mainly CT scan
min_shown_white - max_shown_black range over which the gradint of greys will be shown
truemax - truemin the range of values in the image for which we are creating the scale
```
#taken from https://stackoverflow.com/questions/67727977/how-to-create-julia-color-scheme-for-displaying-ct-scan-makie-jl/67756158#67756158
function createMedicalImageColorSchemeB(min_shown_white,max_shown_black,truemax,truemin ) ::Vector{Any}
# println("max_shown_black - truemin + 1")
# println(max_shown_black - truemin + 1)
# println(" min_shown_white - max_shown_black - 1")
# println( min_shown_white - max_shown_black - 1)
# println("truemax - min_shown_white + 1")
# println(truemax - min_shown_white + 1)
return [fill(colorant"black", max_shown_black - truemin + 1);
collect(make_colorscheme(identity, identity, identity,
length = min_shown_white - max_shown_black - 1));
fill(colorant"white", truemax - min_shown_white + 1)]
end
end #module

How to find the filter coefficients for a DVBS2 shaping SRRC?

in the DVBS2 Standard the SRRC filter is defined as
How can i find the filter's time domain coefficients for implementation? The Inverse Fourier transform of this is not clear to me.
For DVBS2 signal you can use RRC match filter before timing recovery. For match filter, you can use this expression:
For example for n_ISI = 32 and Roll of factor = 0.25 with any sample per symbol you can use this Matlab code:
SPS = 4; %for example
n_ISI=32;
rolloff = 0.25;
n = linspace(-n_ISI/2,n_ISI/2,n_ISI*SPS+1) ;
rrcFilt = zeros(size(n)) ;
for iter = 1:length(n)
if n(iter) == 0
rrcFilt(iter) = 1 - rolloff + 4*rolloff/pi ;
elseif abs(n(iter)) == 1/4/rolloff
rrcFilt(iter) = rolloff/sqrt(2)*((1+2/pi)*sin(pi/4/rolloff)+(1-2/pi)*cos(pi/4/rolloff)) ;
else
rrcFilt(iter) = (4*rolloff/pi)/(1-(4*rolloff*n(iter)).^2) * (cos((1+rolloff)*pi*n(iter)) + sin((1-rolloff)*pi*n(iter))/(4*rolloff*n(iter))) ;
end
end
But if you want to use SRRC, there are two ways: 1. You can use its frequency representation form if you use filtering in the frequency domain. And for implementation, you can use the expression that you've noted. 2. For time-domain filtering, you should define the FIR filter with its time representation sequence. The time representation of such SRRC pulses is shown to adopt the following form:

plot average of n'th rows in gnuplot

I have some data that I want to plot them with gnuplot. But I have for the same x value many y values, I will show you to understand well:
0 0.650765 0.122225 0.013325
0 0.522575 0.001447 0.010718
0 0.576791 0.004277 0.104052
0 0.512327 0.002268 0.005430
0 0.530401 0.000000 0.036541
0 0.518333 0.001128 0.017270
20 0.512864 0.001111 0.005433
20 0.510357 0.005312 0.000000
20 0.526809 0.001089 0.033523
20 0.527076 0.000000 0.034215
20 0.507166 0.001131 0.000000
20 0.513868 0.001306 0.004344
40 0.531742 0.003295 0.0365
In this example, I have 6 values for each x value.So how can I draw the average and the confidence bar(interval) ??
thanks for help
To do this, you will need some kind of external processing. One possibility would be to use gawk to calculate the required quantities and the feed this auxiliary output to Gnuplot to plot it. For example:
set terminal png enhanced
set output 'test.png'
fName = 'data.dat'
plotCmd(col_num)=sprintf('< gawk -f analyze.awk -v col_num=%d %s', col_num, fName)
set format y '%0.2f'
set xr [-5:25]
plot \
plotCmd(2) u 1:2:3:4 w yerrorbars pt 3 lc rgb 'dark-red' t 'column 2'
This assumes that the script analyze.awk resides in the same directory from which Gnuplot is launched (otherwise, it would be necessary to modify the path in the -f option of gawk. The script analyze.awk itself reads:
function analyze(x, data){
n = 0;mean = 0;
val_min = 0;val_max = 0;
for(val in data){
n += 1;
delta = val - mean;
mean += delta/n;
val_min = (n == 1)?val:((val < val_min)?val:val_min);
val_max = (n == 1)?val:((val > val_max)?val:val_max);
}
if(n > 0){
print x, mean, val_min, val_max;
}
}
{
curr = $1;
yval = $(col_num);
if(NR==1 || prev != curr){
analyze(prev, data);
delete data;
prev = curr;
}
data[yval] = 1;
}
END{
analyze(curr, data);
}
It directly implements the online algorithm to calculate the mean and for each distinct value of x prints this mean as well as the min/max values.
In the Gnuplot script, the column of interest is then passed to the plotCmd function which prepares the command to be executed and the output of which will be plotted with u 1:2:3:4 w yerrorbars. This syntax means that the confidence interval is stored in the 3rd/4th columns while the value itself (the mean) resides in the second column.
In total, the two scripts above produce the picture below. The confidence interval on the last point is not visible since the example data in your question contain only one record for x=40, thus the min/max values coincide with the mean.
You can easily plot the average in this case:
plot "myfile.dat" using ($1):($2 + $3 + $4)/3
If you want average of only second and fourth column for example, you can write ($2+$4)/2 and so on.

Scatter 3d overlaid on the surface or wireframe plot?

I have 10,000 x, y, z points with 20 of them are as follow, lets called it as data A.
0.242745297 0.970090058 0
0.891863203 0.452305209 0.000157095
0.382557235 0.923931742 0.000314191
0.988602615 0.150547827 0.000471286
0.990418256 0.138098816 0.000628381
0.985286122 0.170911207 0.000785477
0.813594577 0.581431832 0.000942572
0.072447325 0.997371634 0.001099667
0.442898837 0.896570712 0.001256762
0.390410171 0.92063994 0.001413858
0.94424855 0.32922972 0.001570953
0.823242628 0.567687052 0.001728048
0.951142253 0.308747244 0.001885143
0.834598707 0.550854633 0.002042238
0.9551501 0.296113912 0.002199333
0.466621761 0.884453831 0.002356428
0.399454286 0.916749669 0.002513523
0.847106351 0.53141669 0.002670618
0.998468109 0.05525793 0.002827712
0.559509437 0.828818606 0.002984807
Now, I also have much much less data, called data B, with the same number of column, x y z, as follow:
1.09E-16 1.785718947 0
0.019294497 0.30674191 1.118939202
0.077017367 0.913349082 0.621713321
0.402044713 1.391556608 0.01362025
0.274220861 1.67026197 0
0.923642324 0.313530314 0.424167555
1.022371899 0.301758616 0.062661655
1.27727567 0.4131242 0
0.192434487 1.217507707 0.061631979
0.287144078 1.114175886 0.294906802
0.56787764 1.186676548 0.004689697
0.143854651 1.058776687 0.427695299
7.32E-17 1.19517985 0.624420229
0.297763481 1.017599598 0.407829845
0.201402889 1.205216298 0.383356118
0.379563712 0.598453545 0.78331148
0.399108958 0 1.121468066
1.015175114 0.108070734 0.074322688
1.08251008 0 0.241371942
0.240891894 0.739967202 0.710831521
Now, I want to plot something like this:
[Data A looks like a sphere or wireframe, and on top of that is data B]
I have tried something like this:
plot3d(dataA, type = "wire")
par(new=TRUE)
plot3d(datab, type = "p")
but it did not look like the one that I wanted.

Percentage from negative target

I have these set of targets and actuals:
Actual: "-20" / Target: "-10"
Actual" "50" / Target: "-5"
Actual: "-10" / target: "30"
Target values are anticipated values for each of the 3 categories and actual values are year to date actual values.
On the first category; in was anticipated that there would be -10 sales compared to the previous period. It turned out to be -20 at the end of the current period. The answer could be -100% or -200%. None of these percentages make sense since percentage completed shouldn't be a negative amount. Another reason that makes the percentages unreasonable is that I cannot perceive the difference between 100% and -100% in this case.
On the 2nd category, it was anticipated that there would be 5 less sales in the current period but turns out there was actually 50 sales in the current period. The answer should be +1100% if we agree that every amount of 5 is a 100%.
EDIT: Same as above, the answer for the third category should be -133%
I want to see how much of the target is fulfilled. If actual=target then the answer is 100% although this doesn't make sense if both the actual and the target are negative amount.
If I use (actual/target)*100 negative amounts are always wrong. I need a general formula to calculate the correct answer. I don't mind if the formula has many conditional definitions. How can I do this?
When involving negative amount, you should always know what it is that you are looking for.
example 1:
if you use the absolute value, you should agree that target=10 and actual=-5 is and should be 50%. however, the 'pure' mathematical way to look at it is -50%.
A logical explanation for this is that actual=0 is, as logic predicts, 0%, -5 is even worse! since not only no progress was made, but rather a regression occurred, hence -50% is an understandable result.
example 2:
When both are negative then for target=-10 and actual=-20, since anchoring point is 0, the 'pure' mathematical result is 200% - and is correct (depending on your point of view of course) since you wanted a decrease of 10 and got a decrease of 20.
Note:if you want to define your wanted output differently, do so and we will try and come up with a 'custom' percentage calculation method.
Edit:
What you could try in your case (Although I must say I don't agree with this approach):
if target>0 and actual > 0 : (the usual) :
(actual/target)*100
if target < 0 and actual < 0 : (the usual negative) :
if (target>actual) - actual is worse than expected :
-(actual/target)*100
if (target < actual) - actual is better than expected :
(actual/target)*100
if target>0 and actual < 0 :
((actual-target)/target)*100
corresponds with target=50 , actual = -100 -> result = -300%
if target<0 and actual > 0 :
(abs(target)+actual)/abs(target))*100
so that for target = -50 , but actual = 100 -> result = 300%
I believe that covers your options and suits your needs.
Edit:
A good approach to your issue from my point of view is to look at absolute values (rather than differential values):
Lets say your sales in month A is 200, and you want a 10% increase in month A+1 -> set your target at 220 and then compare the actual to it, you can also compare it month's A actual and overall a report would use the absolute values for comparison, those are always positive, and can be understood more clearly.
now this:
target = -10% , actual +5% and base value of last month 100
will simply be this:
target = 90 actual =105 => Overall performance of 105/90 , or (105/90)-1 higher than expected.
If you want to treat Actual “-50” / Target “50” as 100% fulfilled, you should use the absolute value function in your formula.
| ((actual / target) * 100) |
How you use it in your code depends on the language. In JavaScript, your formula would be like this:
Math.abs((actual / target) * 100)
If this is not how you want your scoring to work, please provide an example of what the score should be when the target or actual is negative.
Based on your edit with more details about what you want, here is some JavaScript that implements that formula:
function percent_difference(target, actual) {
if (target === 0 || actual === 0) {
if (actual > target) {
return 100;
} else if (actual < target) {
return -100;
} else {
return 0;
}
}
var relative_to = Math.min(Math.abs(actual), Math.abs(target));
var distance_from_target_to_actual = actual - target;
var fraction_difference = distance_from_target_to_actual / relative_to;
return 100 * fraction_difference;
}
I tried to avoid unnecessary if statements to keep the code simple.
The function passes these tests:
function test_percent_difference() {
console.log("percent_difference(-10, -20)", percent_difference(-10, -20), "should be", -100);
console.log("percent_difference(-5, 50)", percent_difference(-5, 50), "should be", 1100);
console.log("percent_difference(30, -10)", percent_difference(30, -10), "should be", -400);
console.log("percent_difference(15, 0)", percent_difference(15, 0), "should be", 100);
console.log("percent_difference(0, 0)", percent_difference(0, 0), "should be", 0);
}
You can run it for yourself in your browser in this jsFiddle.
Here is the solution with R.
Assume your data is sample with Target and Actual columns:
sample<-structure(list(Actual = c(-20L, 50L, -10L), Target = c(-10L,
-5L, 30L)), .Names = c("Actual", "Target"), row.names = c(NA,
-3L), class = "data.frame")
sample<-
Actual Target
1 -20 -10
2 50 -5
3 -10 30
#first I compute the percentage deviation as ((Actual-Target)/Actual)*100
#then I will use following two conditions:
# if Actual<0 and Target>0 multiply by -1
#if Actual<0 and Target<0 and if absolute(Actual)>absolute(Target) multiply by -1 else leave as original percent
sample$diff<-with(sample,((Actual-Target)/Actual)*100)
> sample
Actual Target diff
1 -20 -10 50
2 50 -5 110
3 -10 30 400
sample$percent<-with(sample,ifelse((Actual<0 & Target>0),diff*(-1),ifelse((Actual<0 & Target<0),ifelse((abs(Actual)>abs(Target)),diff*-1,diff),diff)))
> sample
Actual Target diff percent
1 -20 -10 50 -50
2 50 -5 110 110
3 -10 30 400 -400
#delete diff column
sample$diff<-NULL
#your final output
> sample
Actual Target percent
1 -20 -10 -50
2 50 -5 110
3 -10 30 -400
Updated:
To match your answers:
sample$diff<-with(sample,((Actual-Target)/Target)*100)
sample$percent<-with(sample,ifelse((Actual<0 & Target>0),diff,ifelse((Actual<0 & Target<0),ifelse((abs(Actual)>abs(Target)),diff*(-1),diff),diff*(-1))))
> sample
Actual Target diff percent
1 -20 -10 100.0000 -100.0000
2 50 -5 -1100.0000 1100.0000
3 -10 30 -133.3333 -133.3333

Resources