Plotting a 3D Surface

How would I plot the surface f(x,y)=xy-y-x+1 between \sqrt2\leq y\leq2

using PyPlot;
x = collect(Float16, range(-2,length=100,stop=2));
y = collect(Float16, range(sqrt(2),length=100, stop=2));
z = (x.*y).-y.-x.+1;
surf(x,y,z);

Figure_1-1

3 Likes

It is not quite clear to me what the question is. However, you can use Plots as follows:

using Plots; pyplot()
x=range(-2,stop=2,length=100)
y=range(sqrt(2),stop=2,length=100)
f(x,y) = x*y-x-y+1
plot(x,y,f,st=:surface,camera=(-30,30))

with result:
image
Here, st is short hand for seriestype (or something similar). Keyword camera sets the camera/viewing angles. I have used the default heatmap.
If you want to plot contours, you can plot contour lines (st=:contour) or filled countours (st=:contour).

10 Likes

…if you want to use another heatmap, just set the color (or c) argument to some color gradient, e.g., a built in such as :blues or make your own, say:

my_cg = cgrad([:red,:blue])

thus

plot(x,y,f,st=:surface,c=my_cg,camera=(-30,30))

leading to:
image

5 Likes

I think using PyPlot.surf was misguided since I had tried.

using PyPlot;
x = collect(Float16, range(-2,length=100,stop=2));
y = collect(Float16, range(sqrt(2),length=100, stop=2));
f(x,y) = x*y-x-y+1
surf(x,y,f);
ERROR: MethodError: no method matching 
surf(::Array{Float16,1}, ::Array{Float16,1}, ::typeof(f))

Clearly PyPlot \neq {Plots,pyplot()}

Well, it is possible that Plots with pyplot() sets some defaults for PyPlot, so that the Plots results are uniform for different backends such as pyplot(), gr(), etc. In any way, I’ve changed the camera angle — I think you often need to do that to get ok plots with 3D surface plots. Here is the default camera angle, with c = :blues:
image

2 Likes

I do notice that my way of plotting lets f(x,y) range from ca. -3 and upwards, while your plot seems to range from -1. Perhaps that is why it looks differently? I’ve checked the function plot in WolframAlpha, and the result I have looks very similar to that plot. I haven’t tried to use PyPlot directly from Julia.

1 Like

I’m trying to figure out how to do the equivalent of Matlab fill3, which draws a filled 3D polygon, in Julia Plots.

I can do with PyPlot (although I don’t understand the diagonal stripe):

using PyPlot
xc = [0;0;1;1]
yc = [0;1;1;0]
zc = [1;1;2;2]
plt = PyPlot.surf(xc,yc,zc)

image

When I try the same thing in Julia Plots, with plot type :surface, I get this.

import Plots
Plots.plotlyjs()
xc = [0;0;1;1]
yc = [0;1;1;0]
zc = [1;1;2;2]
plt = Plots.plot(xc,yc,zc,st=:surface)

First, it’s zoomed out way too far. But it’s not just a limits thing – if I set the limits to zoom in on where the polygon is supposed to be, there’s nothing there:

plt = Plots.plot(xc,yc,zc,st=:surface,xlims=(-1,2),ylims=(-1,2),zlims=(0,3))

image

I’ve seen this example Plotting a 3D Surface, which includes a generator function for z, but I can’t figure out how to supply my own z coordinates.

I’ve tried supplying my own colormap, but that doesn’t help either.

Any tips on what I’m doing wrong?

Thanks,
Brad

2 Likes

Oops, I paste in the wrong image in the wrong place. Pyplot output looks like this:

image

A suggestion: when you insert code, it looks much better if you use mark-up. In-line code is typeset by enclosing it with single back-tic. Displayed code should be enclosed in triple back-tics, and the first triple back-tic allows to specify the language in case you want syntax high-lighting.

The following code uses Plots and pyplot as back-end:

using Plots; pyplot();

xc = [0,0,1,1]
yc = [0,1,1,0]
zc = [1,1,2,2];

plot(xc,yc,zc,st=:surface,camera=(-30,30))

The result is as follows:

A few comments:

  1. In your first case, you use raw PyPlot. An alternative is to use pyplot as a back-end to the Plots API – as I’ve done.
  2. In your case of using Plots, you use the plotlyjs back-end. I used the pyplot back-end. There is also a gr back-end, etc. The gr back-end is the default for Plots. In my view, gr gives the purest/prettiest lines, etc. However, pyplot seems to have slightly better support of the Plots API, and also has the best \LaTeX support.
  3. Your plot using plotlyjs back-end doesn’t really show any plot in my browser. I don’t know why; in any way, I use pyplot as back-end to Plots.
  4. You import Plots using statement import Plots. That is fine; if you do so, you need to use the package name when issuing the command, i.e., Plots.plot. I import Plots by statement using Plots – the advantage is that then you don’t need to specify the package name. Such import is less “dangerous” in Julia than in, say, Python, because of Julia’s multiple dispatch idea.
  5. Observe that I used the camera option in plot – sometimes it is necessary to do this to rotate the coordinate system to get a good view of the object.
  6. Finally, I prefer to use comma (",") to separate vector elements; you have used semicolon (";"). This is not a big thing here.
4 Likes

Thanks so much! This works for me. Thanks also for the tips on composing messages.

Now I’m on to another question, which is “how do I see my plot”? The example (which I am running using Shift-Enter in Atom) pops up in my Atom Plots pane, but when I try to run my program, I get errors. The plot displays fine if I use plotly or plotlyjs.


Here’s the backdrop.

I went from my example program back to my real program, which I have changed to say

  import Plots
  Plots.pyplot()

But when I get to the end of my program, where I call

  Plots.gui()

to display the plot, I get

sys:1: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.

In an earlier run - I thought everything was the same, I can’t quite figure out what was different - I got

Warning: _display is not defined for this backend.
└ @ Plots C:\Users\brad\.julia\packages\Plots\Ih71u\src\output.jl:186

When I was using straight PyPlot, if I recall correctly, I could say pygui(:qt) or the like to get a plot, but that doesn’t work.

I have tried all three of these, but I either get “UndefVarError” or “type #pyplot has no field”:

  pygui(:qt)
  Plots.pygui(:qt)
  Plots.pyplot.pygui(:qt)

This is the kind of thing that can drive a person crazy while trying to get up to speed on Julia. It seems like the system should just default to something that “works”, whatever that means.

I am running in the Atom/Juno environment. I’ve heard suggestions before to “just run Julia”. I hadn’t really groked what that meant, but I did just open a standalone Julia shell and was able to run my program.

When I do that, I get the

┌ Warning: _display is not defined for this backend.
└ @ Plots C:\Users\brad\.julia\packages\Plots\Ih71u\src\output.jl:186

error when I get to Plots.gui()

I’ve also seen suggestions to type gcf(). But both Plots.gcf() and gcf() give "UndefVarError`

I’ve also read that "when using PyPlot in Atom, you need to uncheck Settings/Packages/Julia Client/UI Options/Enable Plot Pane. Or, if you want to display your PyPlot plots in Atom with Juno (without changing the settings), you could also add gcf() at the end of your plotting code.

I seem to recall that at least the first of these worked with raw PyPlot. But when I just tried it now with Plots.pyplot, nothing happens at all.


Can anybody help me diagnose what these error messages mean or how to fix them? I could try to boil this down to a MWE, but in truth it will be faster for me to rip out Plots and go to raw PyPlot than to try to do that, and I’ve a got an end of week deadline for my client.

Thanks for taking the time to read through all this.

Brad

Three more questions about 3D, for anyone that still has patience.

I wonder if some of these may devolve into a question of “how do I use the extra_kwargs to pass args to the underlying engine?” Are there any examples of that that anyone knows of? Can you nest them - i.e., can I pass args to PyPlot, that it then passes on to matplotlib?

  1. Does anybody know how to plot a 3D polygon with holes in it? (I am doing a solar tracking sim and using the Clipper library (http://www.angusj.com/delphi/clipper.php), which I’ve used before in Matlab.) Certain reflection patterns from my group of mirrors can lead to checkerboard illumination patterns (polygons with holes). Clipper can compute these complex shapes. I’d like to then plot the illumination pattern on the target.

(In 2D you could just draw the enclosing shape in, say, solid black, and then draw the “holes” as white. But in 3D you can’t do that because the polygons never quite lie in the same plane at the 10th decimal place, so the scene ends up changing depending on the viewpoint.)

  1. I’d like more control over the camera than I get from just az/el. The engine seems to choose its own zoom regardless of what I set for xlims/ylims/zlims. (Although that might have only been for plotly - will have to check pyplot once I figure out how to see the plots.) I would make an animation of a full day, and the scale was constantly changing as my light rays changed position during the day. (It’s an animation of a full day of solar tracking.)

At least with plotly and plotlyjs, I had to resort to a trick to control the zoom. I draw invisible (white) lines at the extents of my scene, and that seems to prevent unwanted zooming.

  1. Similarly, I’d like to control the amount of perspective applied. (This is more or less equivalent to setting a viewpoint and a zoom.) So I’d like to control the camera eyepoint, not just az/el, and also either zoom or perspective. (That is, to minimize perspective effects, I can look from a long way off and zoom in.) With my solar tracker sim, there are times during they day when rays that should be parallel turn into a cone (below). It’s a bit embarrassing to explain to my client that I don’t know how to fix that.

Here’s what happens when I look from a viewpoint too close to where the sun is in the sky:

image

You can see that the perspective effect is rather severe - the two axes are well off from 90 degrees from each other.

Here’s what happens at a slightly different time of year when the sun is further from the viewpoint. You can see that the effect is still there, but not as bad. You can see how the rays tend to lean towards the axes on either side rather than running parallel to one another.

As always, thanks for your patience and interest in reading through all this.

Brad

I normally use Jupyter/IJulia in my exploration. When I use Juno (Atom with addition), I do the same thing as in IJulia:

using Plots; pyplot();
plot(sin,range(-2pi,2pi,length=50))

produces a plot in Juno’s plot window. I don’t use pygui, etc.

I would guess that when you use the command Plots.pyplot() etc., you are essentially using "raw PyPlot", and not the plot() API of Plots, but I’m not sure. I used Python and dug into Matplotlib some 7-8 years ago, but after I switched to Julia, I have mainly used the Plots API based on Plots.plot() with pyplot() backend, and have not really used PyPlot directly. Maybe someone else have better information on this.

Since I don’t use PyPlot() directly, someone else would need to answer this.

Hi, I am starting with ploting.
My first plot 3d:
using Plots
pyplot()
a=rand(10);b=rand(10),c=rand(10)
scatter(a,b,c,size=(500,500))
a

How to use diffrent colors (R,G,B ), for aeach ny series (a,b,c)
Thx, Paul

add the call zcolor=??? I think.

Something like this? First (assuming 5 data sets) do:

using Plots
#
N=5
M = [:o,:v,:^,:x,:+]
seed=colorant"blue"
COL = distinguishable_colors(N,seed)

which leads to:
image

and then (in IJulia):

plot()
for i in 1:N
    a = rand(10); b = rand(10); c = rand(10);
    plot!(a,b,c,seriestype=:scatter,markercolor=COL[i],markersize=8,markerstrokecolor=COL[i],marker=M[i],label="Data set $i")
end
plot!()

leading to:

[You can, e.g., use ms as short form for markersize, mc as short form for markercolor, st as short form of seriestype, etc. Your syntax scatter is just a short form of plot(..., seriestype=:scatter)).

6 Likes