Julia - plot with 2 arrays of same size - plot

I have two arrays:
sigma = logspace(-4,4,5)
which looks like = [10^-4,10^-2,10,10^2,10^4]
and some other array that contains 5 values which were generated from norm-2 of some 5 different vectors.
assume this is the second array:
Xnorm = [1,2,3,4,5]
I'm trying to plot those two arrays:
figure()
plot(Xnorm,sigma)
I would like that sigma will represent the X-axis and Xnorm the y-axis.
The result right now is an empty graph. (I've tried to swap between both of them also).
Unfortunately, I did not found any good documentation for plotting with array.

You need to import the plotting library
sigma = logspace(-4,4,5)
Xnorm = [1,2,3,4,5]
# Pkg.add("Plots") # Do this only the first time to install.
using Plots
plot(Xnorm,sigma)

Related

What is the equivalent of Matlab's mesh function in Julia Plots.jl

In Matlab, we would first use [x, y] = meshgrid to generate the grid, then use mesh(x, y, z) to plot the 3D plot. I want to use the same funtionality in Julia Plots.jl, which API should I use? And how can I achieve that?
Thanks a lot in advance!!!
use surface
using Plots
xs = range(-2, stop=2, length=100)\
ys = range(-pi, stop=pi, length=100)
f(x,y) = x*sin(y)
surface(xs, ys, f)
In modern Julia, v1.17, the approach is to create x and y ranges. Julia has changed over the years, and used to have linspace - it doesn't anymore.
There are three ways to create a range:
x = start:step:end
x = range(start,end,step=step)
x = range(start,end,length=npts)
You will also need Plots. If you precompile it, it takes less time to load.
]
pkg > add Plots
pkg > precompile
pkg > Ctrl-C
You need to select your backend for Plots. Choices are:
pyplot() to select PyPlot (also requires Python's MatPlotLib)
plotly() to select Plotly (displays in web browser)
gr() to select GR, the default
Finally, you need to use surface to draw the surface. The function surface can take either a function or a matrix of z values. The function takes two parameters, x and y. Either the function is supplied directly, or it is applied to the ranges:
z = f.(x',y);
One of the ranges is transposed with ', and output suppressed with ;
Surface also takes optional parameters:
fill = :fillname
legend = true | false
size = (width,height)
clims = (lowlimit,highlimit)
An example:
using Plots
plotly()
x=range(-5,5,length=101)
y=range(-5,5,length=101)
function f(x,y)
r = sqrt(x^2+y^2)
sinc(r)
end
z = f.(x',y);
surface(x,y,z,size=(1600,1000),fill=:greens,legend=false)

How can I push to a specific series in a Julia plot?

I'm trying to create an animation in Julia where a satellite orbits Earth. Earth in this case is represented by a static circle and the satellite's trajectory is a path extending from the launch point to the satellite's current position.
If I understand the process correctly, to create a gif in Julia, I need to use the #gif macro with a loop and create the next gif frame on each iteration of the loop. I've been attempting to plot Earth, then plot the launch point, then push the next position in the satellite's trajectory on each loop iteration, but it's pushing data to the Earth dataset.
I also have other plots that I would like to animate, but the animation examples that use multiple data series don't specify any x values. I need to specify x and y values for each datapoint in each series.
How can I specify the series to push a new point to?
Well, while trying to put together a small example script, I figured it out.
To begin, the conditions under which you can use push! with a plot are fairly specific. You can't use an Int64 (or any other type of integer) as an x value or push! will try to access the plot like an array at the "index" specified by your x data. This means you have to ensure every input is a Float (I didn't try this with more exotic data types for plotting like Bools, but I assume that that wouldn't go well either).
Also, the x and y (and z) data in a plot can't be something that push! doesn't work on normally, like a StepRangeLen (e.g. t = 0:10). Unfortunately this introduces an extra layer of complexity; if you need to use StepRangeLens in your plots, you'll have to convert them to Arrays: t = Array{Float64}(0:10).
Finally, it's probably good practice to pass in as many x and y values on each call to push! as you have series (if this wording is awkward, see the example below). Some of the examples for the Plots package add complexity in specifying a single x value for multiple y values, which is fine if your x values are the same for both series, but becomes a problem if they're different.
Putting all of this together, here's a minimal example of pushing to different series:
using Plots
# Let x and z be two different-valued, different-length vectors
x = Array{Float64}(range(0, stop=π, length=30))
z = Array{Float64}(range(0, stop=-π, length=20))
p = plot(x,sin.(x))
plot!(p, z, cos.(z))
# Pushing a single x,y pair goes to the first series:
push!(p, 0.0, -0.5)
# Pushing a single x value and a 2x1 Array sends the x value to
# both series, the first y value to the first series, and the
# second y value to the second series.
push!(p, -0.2, [-0.75, 0.2])
# Note: comma ^ is important
# Pushing two x values and two y values sends the first x value to
# the first series and the second x value to the second series.
# Same for the y values, which is the same as the previous example
push!(p, [-π/4, π/4], [0.1, 0.2])
# If you want to push only to one series, send a NaN to the others:
push!(p, [NaN, -3π/2], [NaN, 1.0])
display(p)
The plot is pretty incoherent if you run this as-is. I recommend commenting out each of the push! statements and uncommenting each one individually to see its effect on the plot.

Return the frequency in a bin of a 2D histogram in Julia

Suppose I have some 2D data points, and using the Plots package in Julia, a 2D histogram can be easily plotted. My task is to define a function that maps between a data point to the frequency of data points of the bin to which that point belongs to. Are there any functions that serve well for this task?
For example, as in the following 2D histogram:
And I would like to define a function, such that when I input an arbitrary data points that is within the domain of this histogram, the function will output the frequency of the corresponding bin. In the image above, when I input (0.1, 0.1), the function should output, say, 375 (I suppose the brightest grid there represents the frequency of 375). Are there any convenient functions in Julia to achieve the aforementioned task?
Edit:
using Plots
gr()
histogram2d(randn(10000), randn(10000), nbins=20)
A histogram is created from 10000 2D data points generated from standard normal distribution. Is there any function in Julia to input a 2D point and output the frequency of the bin to which the point belongs to? It is possible to write one myself by creating arrays and bins and counting the number of elements in the bin of an inputted data point but this will be the tedious way.
I'm not 100% sure whether this is what StatsPlots is doing, but one approach could be to use StatsBase's histogram which works for N dimensions:
using StatsBase, StatsPlots, Distributions
# Example data
data = (randn(10_000), randn(10_000))
# Plot StatsPlots 2D histogram
histogram2d(data)
# Fit a histogram with StatsBase
h = fit(Histogram, data)
x = searchsortedfirst(h.edges[1], 0.1) # returns 10
y = searchsortedfirst(h.edges[2], 0.1) # returns 11
h.weights[x, y] # returns 243
# Or as a function
function get_freq(h, xval, yval)
x = searchsortedfirst(h.edges[1], xval)
y = searchsortedfirst(h.edges[2], yval)
h.weights[x, y]
end
get_freq(h, 1.4, 0.6) # returns 32

How to animate 3D scatter plot by adding each point at a time in R or MATLAB

I have a set of 3D coordinates here. The data has 52170 rows and 4 columns. Each row represent one point. The first column is point index number, increasing from 1 to 52170. The second to fourth columns are coordinates for x, y, and z axis, respectively. The first 10 lines are as follow:
seq x y z
1 7.126616 -102.927567 19.692112
2 -10.546907 -143.824966 50.77417
3 7.189214 -107.792068 18.758278
4 7.148852 -101.784027 19.905006
5 -14.65788 -146.294952 49.899158
6 -37.315742 -116.941185 12.316169
7 8.023512 -103.477882 19.081482
8 -14.641933 -145.100098 50.182739
9 -14.571636 -141.386322 50.547684
10 -15.691803 -145.66481 49.946281
I want to create a 3D scatter plot in which each point is added sequentially to this plot using R or MATLAB. The point represented by the first line is added first, then the point represented by the second line, ..., all the way to the last point.
In addition, I wish to control the speed at which points are added.
For 2D scatter plot, I could use the following code:
library(gganimate)
x <- rnorm(50, 5, 1)
y <- 7*x +rnorm(50, 4, 4)
ind <- 1:50
data <- data.frame(x, y, ind)
ggplot(data, aes(x, y)) + geom_point(aes(group = seq_along(x))) + transition_reveal(ind)
But I cannnot find information on how to do this for 3D scatter plot. Can anyone show me how this could be done? Thank you.
This is an answer for MATLAB
In a general fashion, animating a plot (or 3d plot, or scatter plot, or surface, or other graphic objects) can be done following the same approach:
Do the first plot/plot3/scatter/surf, and retrieve its handle. The first plot can incorporate the first "initial" sets of points or even be empty (use NaN value to create a plot with invisible data point).
Set axis limits and all other visualisation options which are going to be fixed (view point, camera angle, lightning...). No need to set the options which are going to evolove during the animation.
In a loop, update the minimum set of plot object properties: XData, YData ( ZData if 3D plot, CData if the plot object has some and you want to animate the color).
The code below is an implementation of the approach above adapted to your case:
%% Read data and place coordinates in named variables
csvfile = '3D scatter plot.csv' ;
data = csvread(csvfile,2) ;
% [optional], just to simplify notations further down
x = data(:,2) ;
y = data(:,3) ;
z = data(:,4) ;
%% Generate empty [plot3] objects
figure
% create an "axes" object, and retrieve the handle "hax"
hax = axes ;
% create 2 empty 3D point plots:
% [hp_new] will contains only one point (the new point added to the graph)
% [hp_trail] will contains all the points displayed so far
hp_trail = plot3(NaN,NaN,NaN,'.b','Parent',hax,'MarkerSize',2) ;
hold on
hp_new = plot3(NaN,NaN,NaN,'or','Parent',hax,'MarkerSize',6,'MarkerEdgeColor','r','MarkerFaceColor','g','LineWidth',2) ;
hold off
%% Set axes limits (to limit "wobbling" during animation)
xl = [min(x) max(x)] ;
yl = [min(y) max(y)] ;
zl = [min(z) max(z)] ;
set(hax, 'XLim',xl,'YLim',yl,'ZLim',zl)
view(145,72) % set a view perspective (optional)
%% Animate
np = size(data,1) ;
for ip=1:np
% update the "new point" graphic object
set( hp_new , 'XData',x(ip), 'YData',y(ip), 'ZData',z(ip) )
% update the "point history" graphic object
% we will display points from index 1 up to the current index ip
% (minus one) because the current index point is already displayed in
% the other plot object
indices2display = 1:ip-1 ;
set(hp_trail ,...
'XData',x(indices2display), ...
'YData',y(indices2display), ...
'ZData',z(indices2display) )
% force graphic refresh
drawnow
% Set the "speed"
% actually the max speed is given by your harware, so we'll just set a
% short pause in case you want to slow it down
pause(0.01) % <= comment this line if you want max speed
end
This will produce:

How to count line segment occurrences by pixel in R?

I am trying to convey the concentration of lines in 2D space by showing the number of crossings through each pixel in a grid. I am picturing something similar to a density plot, but with more intuitive units. I was drawn to the spatstat package and its line segment class (psp) as it allows you to define line segments by their end points and incorporate the entire line in calculations. However, I'm struggling to find the right combination of functions to tally these counts and would appreciate any suggestions.
As shown in the example below with 50 lines, the density function produces values in (0,140), the pixellate function tallies the total length through each pixel and takes values in (0, 0.04), and as.mask produces a binary indictor of whether a line went through each pixel. I'm hoping to see something where the scale takes integer values, say 0..10.
require(spatstat)
set.seed(1234)
numLines = 50
# define line segments
L = psp(runif(numLines),runif(numLines),runif(numLines),runif(numLines), window=owin())
# image with 2-dimensional kernel density estimate
D = density.psp(L, sigma=0.03)
# image with total length of lines through each pixel
P = pixellate.psp(L)
# binary mask giving whether a line went through a pixel
B = as.mask.psp(L)
par(mfrow=c(2,2), mar=c(2,2,2,2))
plot(L, main="L")
plot(D, main="density.psp(L)")
plot(P, main="pixellate.psp(L)")
plot(B, main="as.mask.psp(L)")
The pixellate.psp function allows you to optionally specify weights to use in the calculation. I considered trying to manipulate this to normalize the pixels to take a count of one for each crossing, but the weight is applied uniquely to each line (and not specific to the line/pixel pair). I also considered calculating a binary mask for each line and adding the results, but it seems like there should be an easier way. I know that you can sample points along a line, and then do a count of the points by pixel. However, I am concerned about getting the sampling right so that there is one and only one point per line crossing of a pixel.
Is there is a straight-forward way to do this in R? Otherwise would this be an appropriate suggestion for a future package enhancement? Is this more easily accomplished in another language such as python or matlab?
The example above and my testing has been with spatstat 1.40-0, R 3.1.2, on x86_64-w64-mingw32.
You are absolutely right that this is something to put in as a future enhancement. It will be done in one of the next versions of spatstat. It will probably be an option in pixellate.psp to count the number of crossing lines rather than measure the total length.
For now you have to do something a bit convoluted as e.g:
require(spatstat)
set.seed(1234)
numLines = 50
# define line segments
L <- psp(runif(numLines),runif(numLines),runif(numLines),runif(numLines), window=owin())
# split into individual lines and use as.mask.psp on each
masklist <- lapply(1:nsegments(L), function(i) as.mask.psp(L[i]))
# convert to 0-1 image for easy addition
imlist <- lapply(masklist, as.im.owin, na.replace = 0)
rslt <- Reduce("+", imlist)
# plot
plot(rslt, main = "")

Resources