Change point labels on plot created by plotTangentSpace in "geomorph" package - arrays

Here is a classical example found on the help page for plotTangentSpace in package geomorph. I just add two lines: the construction of the vector Myname and the following line that name one dimension of the array Y.gpa$coords according to Myname.
library (geomorph)
data(plethodon)
Y.gpa<-gpagen(plethodon$land) #GPA-alignment
ref<-mshape(Y.gpa$coords)
Myname = 41:80
dimnames(Y.gpa$coords)=list(NULL, NULL, Myname)
plotTangentSpace(Y.gpa$coords, label=T)
As you can see, on the plot created by plotTangentSpace the points are labeled 1:40 rather than 41:80 as I aimed to do by renaming Y.gpa$coords. I'd like to label the points according to Myname. For this example my name is just a vector of numbers but I'd like it to works for character type also. How can I achieve this?

If you have a look at the code for plotTangentSpace (just type it in the R console), you first find the 'argument list':
function (A, axis1 = 1, axis2 = 2, warpgrids = TRUE, label = FALSE)
As you see you can turn labels 'on' or 'off' (label = TRUE or FALSE), but there is no argument for setting the actual value of the labels. Further down you find the code for the default, hard-coded labels (seq(1, n)) in two places:
if (label == T) {
text(pcdata[, axis1], pcdata[, axis2], seq(1, n),
adj = c(-0.7, -0.7))
...where pcdata, axis1, and n are defined in the beginning of the function.
Thus, if you want to set the value of the labels, it seems that you need to rewrite the function slightly. One possibility is to add a labels argument to the arglist:
function (A, axis1 = 1, axis2 = 2, warpgrids = TRUE, label = FALSE, labels = NULL)
...and change the arguments in both text calls:
text(pcdata[, axis1], pcdata[, axis2], labels,
adj = c(-0.7, -0.7))
You also need to access the tps function in the geomorph namespace. This can be achived by adding geomorph::: before both instances of tps:
geomorph:::tps(ref, shape.min, 20)
geomorph:::tps(ref, shape.max, 20)
Then assign the updated function to a new function name:
plotTangentSpace2 <- function (A, axis1 = 1, axis2 = 2, warpgrids = TRUE, label = FALSE, labels = NULL){
lots-of-stuff
text(pcdata[, axis1], pcdata[, axis2], labels,
adj = c(-0.7, -0.7)) # in both places
more-stuff
geomorph:::tps(ref, shape.min, 20)
geomorph:::tps(ref, shape.max, 20)
}
Plot with the updated function, using 'Myname' as labels:
plotTangentSpace2(Y.gpa$coords, label = TRUE, labels = Myname)

Related

why are there no objects added to my table

I'm working on a lua script where I need a list of buttons to display. I have the following method to add a button to the list buttons:
function addButton(name, text, func, activeColor, passiveColor, xmin, xmax, ymin, ymax, type)
buttons[name] = {}
buttons[name]["text"] = text
buttons[name]["func"] = func
buttons[name]["active"] = false
buttons[name]["activeColor"] = getColorOrDefault(activeColor, ACTIVECOLORDEFAULT)
buttons[name]["passiveColor"] = getColorOrDefault(passiveColor, PASSIVECOLORDEFAULT)
buttons[name]["xmin"] = xmin
buttons[name]["xmax"] = xmax
buttons[name]["ymin"] = ymin
buttons[name]["ymax"] = ymax
buttons[name]["type"] = type
print("added: "..table.getn(buttons))
end
This function is called twice to add 2 buttons, but the output is:
added: 0
added: 0
what could be a reason my elements are not added to the table?
They're being added--You're just using the wrong method to detect them.
As you can read about in this question, using table.getn only returns the amount of array slots (numeric indexes, such as buttons[0] or buttons[23]. Note that this only counts as an array slot if there are no null indexes in between buttons[1] and buttons[23]!
Using this debugging code, we'll see that your items are indeed being added to the buttons table:
for name, button in pairs(buttons) do
print(name, button)
end
This is also how you'd get a list of your buttons :-)

Rearranging a cell array

I'm programming a task for a research study. The problem I have is the following: I have a dictionary with names and with one picture per cell. Like that:
nameCues1 = {'Lisa','Anna', 'Sarah', 'Nina', 'resized_1.jpg' };
nameCues2 = {'Emma', 'Lena', 'Gabi', 'Steffi', 'resized_2.jpg' };
I have loaded them into a cell array, created a random sequence:
nameCuesAll = {nameCues1,nameCues2};
randSeq3 = nameCuesAll(randperm(size(nameCuesAll,2)));
Then I loop over it to read in the names of the dictionary and the corresponding picture:
for i = 1:numel(nameCuesAll)
pics3{i} = imread(randSeq3{i}{1,5});
ind{i}=randSeq3{i}(randperm(numel(randSeq3{i})));
end
Then I prompt it on the screen via Psychtoolbox, a toolbox specialized in creating tasks for research, for those who don't know:
for j = 1:4
% (left out unnecessary other functions)
DrawFormattedText(window,ind{i}(j), 'center', 'center', white, [], [], [], [], [], rect);
end
The problem is that the names of the dictionary are not shown in randomized order, and every try I had until now has thrown errors.
The main problem is that I don't know how to correctly randomize/index
the dictionary-names.
Thanks for any ideas!
To reorder the elements of a cell array, you should reference elements using ():
nameCues1 = {'Lisa','Anna', 'Sarah', 'Nina', 'resized_1.jpg' };
rIdx = randperm(numel(nameCues1));
mixedCues = nameCues1(rIdx)
which yields for the case of rIdx = [3 5 1 4 2]:
mixedCues =
1×5 cell array
{'Sarah'} {'resized_1.jpg'} {'Lisa'} {'Nina'} {'Anna'}
Then use mixedCues instead of nameCues1.
See also: Access Data in Cell Array.

Saving ouput in the form of array using matlab?

% Find a VISA-GPIB object.
obj1 = instrfind('Type', 'visa-gpib', 'RsrcName', 'GPIB8::1::INSTR', 'Tag', '');
% Create the VISA-GPIB object if it does not exist
% otherwise use the object that was found.
if isempty(obj1)
obj1 = visa('TEK', 'GPIB8::1::INSTR');
else
fclose(obj1);
obj1 = obj1(1);
end
% Connect to instrument object, obj1.
fopen(obj1);
t = timer;
t.TasksToExecute = 3;
t.Period = 30;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = #(myTimerObj, thisEvent)disp(query(obj1,'CALCulate:SPECtrum:MARKer0:Y?'));
start(t)
This is my program where I have to save the output values which displays
Query('CALCulate:SPECtrum:MARKer0:Y?') in a array.
You will need to create a variable to hold the outputs of query(obj1, 'CALCulate:SPECtrum:MARKer0:Y?'). You can then append to this variable from within the timer callback function.
%// Initialize a cell array (because I'm not sure of your datatype)
results = {};
%// Define a function to be called when the timer fires
function timerCallback(varargin)
newresult = query(obj1,'CALCulate:SPECtrum:MARKer0:Y?');
%// Display the result (like you currently are)
disp(newresult)
%// Append the result to your results container
results{end+1} = newresult;
end
%// Then set your timer callback
t = timer('TasksToExecute', 3, ...
'Period', 30, ...
'ExecutionMode', 'FixedRate', ...
'TimerFcn', #timerCallback);
start(t)
All of your other setup code would remain the same.

Stopping physics body from movement in Corona SDK

I'm learning Corona SDK and I'm making small project in that purpose.
So, my problem is next one:
I managed to create 2 physics objects and make one of them "explode" when it collides with the other one. My question is how to make other object (it has linear impulse applied) stop when it collides? Also, when it stops, it has to be removed from the screen to avoid colliding with other objects...
Here is a part with removing first object on collision:
nloDrop = function()
local nlo = display.newImageRect("nlo.png", 65, 25)
nlo.x = 35 + mRand(410) ; nlo.y = -60
physics.addBody(nlo, "dynamic", {density=1, bounce = 0, friction = 0, filter = {maskBits = 4, categoryBits = 2}})
nlo:applyLinearImpulse(0, 0.8, nlo.x, nlo.y)
nlo.isSensor = true
nlo.collision = nloCollision
nlo:addEventListener("collision", nlo)
nlo.name = "nlo"
toFront()
end
And here is 'collision' function:
function nloCollision(self, event)
if ((event.other.myName == "weaponName") then
print("funkc")
self:removeSelf()
self:removeEventListener("collision", nlo)
self = nil
if weapon ~= nil then
-- stop moving of weapon
end
end
end
Thanks!
You can make the object bodyActive false and then it will not respond to physics. You cant remove a body from physics within the active screen so its a better option to keep that object out of the screen.
I made it setting the object like local variable and making a function that deletes/removes each variable (object) after some interaction or collision.
1st function contains object creating (that is a local type under function) and applying physics to that object.
2nd function contains deleting (self:removeSelf()) that works because each object is object for itself and when deleting it, physics stuff will continue to work because new local object is going to be created.
function create(event)
local weap1 = display.newImage("weap1.png", 0, 0)
weap1.x = turret.x ; weap1.y = turret.y
weap1.rotation = turret.rotation
weap1.collision = weap1Collision
weap1:addEventListener("collision", weap1)
physics.addBody(weap1, "dynamic", {density = 1, friction = 0, bounce = 0, filter = {maskBits = 2, categoryBits = 4}})
weap1:applyLinearImpulse(forceWeap1*xComp, forceWeap1*yComp, weap1.x, weap1.y)
function weap1Collision(self,event)
if (event.other.name == "collisionObject") then
self:removeSelf()
self:removeEventListener("collision", weap1)
self = nil
end
end
local type of variable (object) makes it work.
P.S.: vanshika, thanks for your answer, it's useful ;)

Amcharts SerialChart multiple line graphs different category value member paths (Silverlight)

EDIT I rewrote my question to make it more understandable after the conversation below with Tony (thanks!).
GOAL Render multiple line graphs (let's say 2) in the same chart. The charts have different x/y value pairs. For one x-value, I do not know both y-values.
I am using Silverlight. The classes available for this are SerialChart and LineGraph. The data source for both graphs is the same and is set at the SerialChart level. The name of the property for the x-axis is also defined there for both graphs (CategoryValueMemberPath).
As suggested by the amCharts documentation, we need to create objects that have a property for the category axis (x-axis) and then one property per graph. Let's call them "Graph1" and "Graph2". So the data source looks something like this:
List<MyClass> data = new List<MyClass>()
{
new MyClass() { Category = 0.1, Graph1 = 0.14, Graph2 = ??? }
,new MyClass() { Category = 0.15, Graph1 = ???, Graph2 = 0.05 }
,new MyClass() { Category = 0.2, Graph1 = 0.35, Graph2 = ??? }
,new MyClass() { Category = 0.18, Graph1 = ???, Graph2 = 0.12 }
... and so on ...
}
PROBLEM What am I supposed to do about the "???" values? I do not have the actual value for that graph for that category value.
If I do not set a value, the default value of 0.0 is assumed and it draws a spike to the x-axis. If I set the previously known Graph1/Graph2 value, then it creates a horizontal connection where there is not supposed to be one. I am basically altering the graph which leads to a wrong result.
So how do I solve this? I am getting the feeling that amCharts do not support this scenario.
You need to add two 'value' axes, one in the X direction and one in the Y direction (imagine, like a bubble chart).
// AXES
// X
var xAxis = new AmCharts.ValueAxis();
xAxis.position = "bottom";
xAxis.gridAlpha = 0.1;
xAxis.autoGridCount = true;
chart.addValueAxis(xAxis);
// Y
var yAxis = new AmCharts.ValueAxis();
yAxis.position = "left";
yAxis.gridAlpha = 0.1;
yAxis.autoGridCount = true;
chart.addValueAxis(yAxis);
Merge all your data points into one array with a common X axis field name ('x' in my example) and for points on line 1, add a property of 'line1' with its value, and for points on line 2, add a property of 'line2'.
For example, your data would look like this:
var chartData = [
{x:0.1,line1:0.25},
{x:0.246,line1:0.342},
{x:0.12,line2:0.16},
{x:0.3,line2:0.485}
];
Then add a 'graph' for each line to your chart specifying where to get the value from in the object array.
// GRAPHS
var graph = new AmCharts.AmGraph();
graph.xField = "x";
graph.yField = "line1";
graph.lineAlpha = 1;
graph.lineColor = '#FF9E01';
chart.addGraph(graph);
var graph2 = new AmCharts.AmGraph();
graph2.xField = "x";
graph2.yField = "line2";
graph.lineAlpha = 1;
graph2.lineColor = '#9EFF01';
chart.addGraph(graph2);
I've put all this into a Fiddle for you - http://jsfiddle.net/64EWx/

Resources