How to change slider position in Makie animation? - animation

I want to create gif animation on my topoplot and I almost succeeded. The only problem is that slider position does not move. How to make it moving?
Here is my code:
xs = range(-0.3, length=size(dat_e, 2), step=1 ./ 128)
sg = SliderGrid(f[2, 1],
(label="time", range=xs, format = "{:.3f} ms", startvalue = 0),
)
time = sg.sliders[1].value
str = lift(t -> "[$(round(t, digits = 3)) ms]", time)
topo_slice = lift((t, data) -> mean(data[1:30, indexin(t, xs), :], dims=2)[:,1], time, dat_e)
topo_axis = Axis(f[1, 1], aspect = DataAspect(), title = "Interactive topoplot")
topo = eeg_topoplot!(topo_axis, topo_slice, # averaging all trial of 30 participants on Xth msec
raw.ch_names[1:30];
positions=pos, # produced automatically from ch_names
#interpolation=DelaunayMesh(),
enlarge=1,
extrapolation=GeomExtrapolation(enlarge=1.0, geometry=Circle),
label_text=true) # aspect ratio, correlation of height and width
text!(topo_axis, 1, 1, text = str, align = (:center, :center))
xlims!(-0.2, 1.2)
ylims!(-0.2, 1.2)
hidedecorations!(topo_axis)
hidespines!(topo_axis)
framerate = 1
timestamps = [-0.3, 0.0828125, 0.1609375, 0.2390625]
record(f, "animations/time_animation.gif", timestamps;
framerate = framerate) do z
sg.sliders[1].value[] = z
time[] = z

Maybe this will do the trick:
Makie.set_close_to!(sg.sliders[1], z)
(use this to set the value to z)

Related

How do I select a line by clicking in Makie?

I want to be able to select a line on the plot by clicking on it. Ideally, when I click on any line, the number of that line will appear on the screen.
I wrote my code based on the tutorial, but there is no example with lines, so I did what I did. https://docs.makie.org/v0.19/documentation/events/index.html#point_picking
At the moment I have no idea what these numbers are telling me and why. They are not even coordinates of clicked points.
P.S. Actually it is just a starting point. I want to create event interaction on series and topoplots. But for now it would be great to find out the basics.
f = Figure(backgroundcolor = RGBf(0.98, 0.98, 0.98), resolution = (1500, 700))
ax = Axis(f[1, 1], xlabel = "Time [s]", ylabel = "Voltage amplitude [µV]")
N = 1:length(pos)
positions = Observable(rand(Point2f, 10))
xs = 0:0.01:10
ys = 0.5 .* sin.(xs)
lines!(xs, ys)
lines!(xs, ys * 2)
hidedecorations!(ax, label = false, ticks = false, ticklabels = false)
hidespines!(ax, :t, :r)
hlines!(0, color = :gray, linewidth = 1)
vlines!(0, color = :gray, linewidth = 1)
i = Observable(0)
on(events(f).mousebutton, priority = 2) do event
if event.button == Mouse.left && event.action == Mouse.press
plt, i[] = pick(f)
str = lift(i -> "$(i)", i)
text!(ax, 1, -0.5, text = str, align = (:center, :center))
end
end
f
Below are some examples of the interaction between clicking and the number displayed (the red dot is where I click).
Check out the mouseposition variable here:
https://docs.makie.org/stable/api/#Events
or the registerInteraction! function here:
https://docs.makie.org/v0.19/examples/blocks/axis/index.html#registering_and_deregistering_interactions
You can use them both as below:
using GLMakie
f = Figure(backgroundcolor = RGBf(0.98, 0.98, 0.98), resolution = (1500, 700))
ax = Axis(f[1, 1], xlabel = "Time [s]", ylabel = "Voltage amplitude [µV]")
#N = 1:length(pos)
positions = Observable(rand(Point2f, 10))
xs = 0:0.01:10
ys = 0.5 .* sin.(xs)
lines!(xs, ys)
lines!(xs, ys * 2)
hidedecorations!(ax, label = false, ticks = false, ticklabels = false)
hidespines!(ax, :t, :r)
hlines!(0, color = :gray, linewidth = 1)
vlines!(0, color = :gray, linewidth = 1)
register_interaction!(ax, :my_interaction) do event, axis
if event.type === MouseEventTypes.leftclick
println("Graph axis position: $(event.data)")
end
end
i = Observable(0)
on(events(f).mousebutton, priority = 2) do event
if event.button == Mouse.left && event.action == Mouse.press
plt, i[] = pick(f)
str = lift(i -> "$(i)", i)
text!(ax, 1, -0.5, text = str, align = (:center, :center))
#show mouseposition(f)
end
end
f
Note that for some reason (perhaps it sees the first click as a selection?) Makie does not start registering the interaction on the graph until the first click within the graph, unlike the clicks on the figure which are all shown even the first one.

Yaw rotation of gear object in vpython

I was wondering how to yaw gear object about Y-axis in vpython. I have been following some tutorials and I have managed to rotate the gear. The gear rotates about Z axis in vpython. I want the gear to remain rotating about Z axis but I would like to yaw the gear around Y-axis. When xxx.rotate(axis=vector(0,0,1), it works as it should do. As soon as I alter anything it goes crazy. I am not sure what xxx.rotate(origin) is meant to do. In my case, I have messed around with the origin vector but it doesn't make any sense to me. I am not sure if the origin vector expects parameter values in x,y,z or some other sequence. I hope I am making makes sense.
The code below is a working code and you can see what I am trying to do here. I have been debugging for a while so please ignore unnecessary comments.
'
# https://www.youtube.com/watch?v=0Sw8sxsN984
# https://www.youtube.com/watch?v=MJiVtz4Uj7M
from vpython import *
import numpy as np
axisOpac = 0.4
def makeAxes(length):
global axes
xaxis = arrow(pos=vector(0, 0, 0), axis=length*vector(1,0,0), shaftwidth = 0.1*(length), color=color.red, opacity = axisOpac)
negXaxis = xaxis.clone()
negXaxis.axis *= -1
yaxis = arrow(pos=vector(0, 0, 0), axis=length*vector(0,1,0), color=color.green, opacity = axisOpac)
negYaxis = yaxis.clone()
negYaxis.axis *= -1
zaxis = arrow(pos=vector(0, 0, 0), axis=length*vector(0,0,1), color=color.magenta, opacity = axisOpac)
negZaxis = zaxis.clone()
negZaxis.axis *= -1
fudge = 0.01*length
xlabel = label(text = "x", color = xaxis.color, pos=xaxis.axis+vector(0, fudge, 0),box = False)
ylabel = label(text = "y", color = yaxis.color, pos=yaxis.axis+vector(0, fudge, 0),box = False)
zlabel = label(text = "-z", color = zaxis.color, pos=zaxis.axis+vector(0, fudge, 0),box = False)
# To make axes visible or invisible
axes = [xaxis, negXaxis, yaxis, negYaxis, zaxis, negZaxis, xlabel, ylabel, zlabel]
return
makeAxes(1)
g = shapes.gear(n = 20)
gear1 = extrusion (path = [vector(0, 0, 0), vector(0, 0, 0.1)], shape=g, opacity = 0.4)
# gear1.axis = vector(0, 0, 0)
debugArrow=arrow(length=6,shaftwidth=.1,color=color.white,axis=vector(0,0,0))
gearAxisArrow=arrow(shaftwidth=.1, color=color.red)
inputYawAngleYaxis = 0 # int(input("Enter an angle: "))
while True:
for cir in np.arange(0, 2*np.pi, 0.01):
rate(10)
# sleep(1)
pitch=0
# k = vector(cos(yaw)*cos(pitch), sin(pitch),sin(yaw)*cos(pitch)) ''' with pitch input '''
k = vector(cos(cir), 0 ,sin(cir)) # ''' without pitch input '''
y=vector(0,0,0)
s=cross(k,y)
v=cross(s,k)
rad = radians(45)
# gear1.axis = vector(1.23, -1.77418, 0) #vector(cos(inputYawAngleYaxis * pi/180), sin(pitch),sin(inputYawAngleYaxis* pi/180)*cos(pitch))
# gear1.pos = vector(-2.94957, 0, 2.70185)
# Gear Pos0: <0.707107, 0, 0.707107> Gear Axis0: <2.15647, 0.101243, -0.00237659>
gear1.pos = vector(0.707107, 0, 0.707107)
# gear1.pos = debugArrow.axis #frontArrow.axis # k # vector(0.707107, 0, 0.707107)
gear1.rotate(angle = -0.1, axis = vector(0, 0, 1), origin = vector(0, 0, 1 ))
# gear1.axis = vector(cos(radians(-45)), 0, sin(radians(-45)))
''' DebugArrow represents the position of the gear's center '''
debugArrow.axis = vector(cos(rad), 0, sin(rad))
''' Arrow inside the gear to track rotational axis of gear - This is to debug the yaw issue facing with gear object'''
gearAxisArrow.pos = gear1.pos
gearAxisArrow.axis = gear1.axis # vector(cos(radians(-45)), 0, sin(radians(-45))) # gear1.axis
gearAxisArrow.length = gear1.length/2
## Debugg
# print("Front Arrow Axis: ", frontArrow.axis, " K vec: ", k, " Ball pos: ", ball.pos )
print("Gear Pos0: ", gear1.pos, " Gear Axis0: ", gear1.axis, "gearAxisArrow: ", gearAxisArrow.pos, "gearAxisArrow: ", gearAxisArrow.axis)
'
I don't understand "I want the gear to remain rotating about Z axis but I would like to yaw the gear around Y-axis". If by "yaw" you mean that the axis of the gear should rotate about the y axis (while the gear itself rotates about that rotating axis), then obviously the axis of the gear can't remain in the direction of the z axis. Instead, the axis of the gear has to rotate. If it's of any help, here is the relevant page of the documentation:
https://www.glowscript.org/docs/VPythonDocs/rotation.html

Visualzing the solution of a differential equation with an animation in Julia

I have solved a system of two second-order differential equations using an implementation of Euler's method in Julia. The below code shows how Euler's method has been called to solve the system in question.
θ1 = 1.1900518004210798; θ2 = 0.3807445263738167
f(t, y) = [y[2], -2(y[1] - θ1) - 4y[2] + 0.5sin(3pi*t),
y[4], -2(y[3] - θ2) - 4(y[4] + abs(y[2])) + 0.5sin(3pi*t)]
y0 = [pi/2, 0, pi/6, 0]; t0 = 0; tFinal = 50; h = 0.001
res = euler(f, y0, t0, tFinal, h)
The result, res, is a vector of four numbers
1.18798735437173
-0.0458294959470722
0.31530569612003573
-0.049213402534541074
The first entry is the angle that the bottom line segment forms with the x-axis while the third entry is the angle that the two line segments form with one another (see below figure).
To create this plot I called plot_robotarm([res[1], res[3]]) which is implemented according to the below code.
function plot_robotarm(thetav)
# Plots a robotarm with angles thetav
R = 1;
xv=zeros(length(thetav)+1)
yv=zeros(length(thetav)+1)
for i in 1:length(thetav)
xv[i+1]=xv[i]+R*cos(thetav[i])
yv[i+1]=yv[i]+R*sin(thetav[i])
end
# Plot with colors
opts = (:circle, 10, 1., :blue, stroke(7, 1., :red))
plt = plot(xv, yv,
marker = opts,
c = :red,
w = 5,
legend = false,
xlims = (0, 2.0),
ylims = (0, 2.0))
display(plt)
end
How can I create an animation that visualizes how consecutive iterations of Euler's method make the robot arm (i.e. the two line segments) move toward the final point at t = 50? (I do not need to plot every iteration, just enough so that it makes for an animation that captures the movement of the robot arm.)
You can use ffmpeg and Luxor.jl's animation features to make an animated GIF. The frame function needs to be modified to reflect graphical display of each step in your program. See the docs for Luxor for more.
using Luxor
using Colors
using BoundaryValueDiffEq
# constants for differential equations and movie
const g = 9.81
const L = 1.0 # pendulum length in meters
const bobd = 0.10 # pendulum bob diameter in meters
const framerate = 50.0 # intended frame rate/sec
const t0 = 0.0 # start time (s)
const tf = 2.3 # end simulation time (s)
const dtframe = 1.0/framerate # time increment per frame
const tspan = LinRange(t0, tf, Int(floor(tf*framerate))) # array of time points in animation
const bgcolor = "black" # gif background
const leaderhue = (0.80, 0.70, 0.20) # gif swing arm hue light gold
const hslcolors = [HSL(col) for col in (distinguishable_colors(
Int(floor(tf*framerate)+3),[RGB(1,1,1)])[2:end])]
const giffilename = "pendulum.gif" # output file
# differential equations copied from docs of DifferentialEquations.jl
simplependulum!(du, u, p, t) = (θ=u[1]; dθ=u[2]; du[1]=dθ; du[2]=-(g/L)*sin(θ))
bc1!(residual, u, p, t) = (residual[1] = u[div(end,2)][1] + pi/2; residual[2] = u[end][1] - pi/2)
bvp1 = TwoPointBVProblem(simplependulum!, bc1!, [pi/2,pi/2], (tspan[1],tspan[end]))
sol2 = solve(bvp1, GeneralMIRK4(), dt=dtframe)
# movie making background
backdrop(scene, framenumber) = background(bgcolor)
function frame(scene, framenumber)
u1, u2 = sol2.u[framenumber]
y, x = L*cos(u1), L*sin(u1)
sethue(leaderhue)
poly([Point(-4.0, 0.0), Point(4.0, 0.0),
Point(160.0x,160.0y)], :fill)
sethue(Colors.HSV(framenumber*4.0, 1, 1))
circle(Point(160.0x,160.0y), 160bobd, :fill)
text(string("frame $framenumber of $(scene.framerange.stop)"),
Point(0.0, -190.0),
halign=:center)
end
muv = Movie(400, 400, "Pendulum Demo", 1:length(tspan))
animate(muv, [Scene(muv, backdrop),
Scene(muv, frame, easingfunction=easeinoutcubic)],
creategif=true, pathname=giffilename)

Matlab - Scale Colorbar of Image

How can I scale the colorbar axis of a false color image?
I read this post,and copied the code but it seems not to work correctly:
MATLAB Colorbar - Same colors, scaled values
Please see the two images below. In the first (without the scaling) the coloraxis goes
[1 2 3 4 5 6]*10^4
In the second image, it goes
[0.005 0.01 0.015 0.02 0.025]
The correct scaling (with C = 100000) would be
[0.1 0.2 0.3 0.4 0.5 0.6]
Without scaling
Wrong scaling
I want that the coloraxis is scaled by 1/C and I can freely choose C, so that when the pixel value = 10^4 and C=10^6 the scale should show 10^-2.
The reason why I multiply my image first by C is to get more decimals places, because all values below 1 will be displayed as zero without the C scaling.
When I run the code I get yticks as a workspace variable with the following values:
[500 1000 1500 2000 2500]
My code:
RGB = imread('IMG_0043.tif');% Read Image
info = imfinfo('IMG_0043.CR2'); % get Metadata
C = 1000000; % Constant to adjust image
x = info.DigitalCamera; % get EXIF
t = getfield(x, 'ExposureTime');% save ExposureTime
f = getfield(x, 'FNumber'); % save FNumber
S = getfield(x, 'ISOSpeedRatings');% save ISOSpeedRatings
date = getfield(x,'DateTimeOriginal');
I = rgb2gray(RGB); % convert Image to greyscale
K = 480; % Kamerakonstante(muss experimentel eavaluiert werden)
% N_s = K*(t*S)/power(f,2))*L
L = power(f,2)/(K*t*S)*C; %
J = immultiply(I,L); % multiply each value with constant , so the Image is Calibrated to cd/m^2
hFig = figure('Name','False Color Luminance Map', 'ToolBar','none','MenuBar','none');
% Create/initialize default colormap of jet.
cmap = jet(16); % or 256, 64, 32 or whatever.
% Now make lowest values show up as black.
cmap(1,:) = 0;
% Now make highest values show up as white.
cmap(end,:) = 1;
imshow(J,'Colormap',cmap) % show Image in false color
colorbar % add colorbar
h = colorbar; % define colorbar as variable
y_Scl = (1/C);
yticks = get(gca,'YTick');
set(h,'YTickLabel',sprintfc('%g', [yticks.*y_Scl]))
ylabel(h, 'cd/m^2')% add unit label
title(date); % Show date in image
caxis auto % set axis to auto
datacursormode on % enable datacursor
img = getframe(gcf);
nowstr = datestr(now, 'yyyy-mm-dd_HH_MM_SS');
folder = 'C:\Users\Taiko\Desktop\FalseColor\';
ImageFiles = dir( fullfile(folder, '*.jpg') );
if isempty(ImageFiles)
next_idx = 1;
else
lastfile = ImageFiles(end).name;
[~, basename, ~] = fileparts(lastfile);
file_number_str = regexp('(?<=.*_)\d+$', basename, 'match' );
last_idx = str2double(file_number_str);
next_idx = last_idx + 1;
end
newfilename = fullfile( folder, sprintf('%s_%04d.jpg', nowstr, next_idx) );
imwrite(img.cdata, newfilename);
Problems:
1) You are getting YTick of the figure (gca) but not the color bar. That would give you the "pixel" coordinates of the graph, instead of the actual values. Use yticks = get(h,'YTick');.
2) caxis auto Should come before overwriting YTicks (and after enabling the color bar); otherwise the scale and ticks will mismatch.
3) Do you mean C = 100000?
Result:

MATLAB finding average RGB value across all pixels in image

Code is below. I'm looping through an input image 1 pixel at a time and determining its RGB value. Afterwards i'm trying to find the average RGB value for the image overall. For some reason the averaging portion of my code isnt working though.
im = imread(filename);
[width, height, depth] = size(im);
count = 0;
r=0;
g=0;
b=0;
for x = 1 : width
for y = 1: height
r = r + im(x,y,1);
g = g + im(x,y,2);
b = b + im(x,y,3);
count = count + 1;
end
end
%find averages of each RGB value.
r2 = r/count;
g2 = g/count;
b2 = b/count;
Why not vectorizing and using mean?
mean( reshape( im, [], 3 ), 1 )
The following code would work as well;
pep = imread('peppers.png');
mean(mean(pep))
This will return a 1x1x3 vector which will be the mean values of R, G, and B respectively.

Resources