1

I am trying to draw a surface plot in Julia. What I want is for the color of the surface to match the vertical-axis value, and for this to range from deep red (negative) to deep blue (positive), with white when vertical (pi - c) = 0.

I am able to draw the graph no problem, and even adjust the clim in the Plot function. However, the actual colors on the graph do not match the colorbar in the legend: clim only affects the legend but does not change the color of the surface.

Here is an image to fix ideas. Note that all values on the vertical-axis are negative, yet the surface is white even when the vertical value = -0.9, while the legend on the right is doing what I want it to do.

enter image description here

And here is the code:

using Plots

# Paramters
A = 1
αω = 0.5
αz = 0.5
β1 = 1
β2 = 1
β0 = 0
γ = 1

# Functions
π(ω,z) = A*ω^(αω)*z^(-αz)
c(x) = β1*x + β2*x^2 + β0
p(x) = 1 - exp(-γ*x);
F(x,Ω=Ω, Z=Z) = [π(ω_val, z_val) for ω_val in Ω, z_val in Z] .- [c(x) for ω_val in Ω, z_val in Z]

# Grids
Ω = range(0, 1, length=101)
Z = range(0.4, 1, length=101)

function plot_f(x, Ω=Ω, Z=Z)
    # Compute f(ω,z) = π(ω,z) - c(x) for each pair of ω and z values
    f_values = F(x,Ω,Z)

    # Compute the maximum absolute value of f_values
    max_abs = float(maximum(abs.(f_values)))

    # Create a 3D surface plot of f(ω,z) for the given value of x, with the colormap fixed at 0 for the white portion
    plot(Z,Ω,f_values,xlabel="z", ylabel="ω", zlabel="π(ω,z) - c($x)",
        st=:surface,camera=(30,30),
        cmap=:RdBu,clim=(-max_abs, max_abs),
        title="Current-period profit when x=$x")
end
plot_f(0.9)

I am sure I am doing something silly. How do I make the surface match the legend?

Aaron Wolf
  • 337
  • 3
  • 13

2 Answers2

1

Couldn't find a complete answer, but managed to perhaps replace one problem with another. Try:

using Plots, ColorSchemes

function plot_f(x, Ω=Ω, Z=Z)
    # Compute f(ω,z) = π(ω,z) - c(x) for each pair of ω and z values
    f_values = F(x,Ω,Z)

    # Compute the maximum absolute value of f_values
    f_min, f_max = extrema(f_values)
    f_max_abs = max(f_max, -f_min)
    f_cmap = cgrad(ColorSchemes.RdBu[range(([f_min, f_max]./(2*f_max_abs) .+ 0.5)...,length=11)])

    # Create a 3D surface plot of f(ω,z) for the given value of x, with the colormap fixed at 0 for the white portion
    l = @layout [grid(1,1) a{0.035w}]
    p = plot(Z,Ω,f_values,xlabel="z", ylabel="ω", zlabel="π(ω,z) - c($x)",
      st=:surface,camera=(30,30),
      cmap=f_cmap,
      cb = false,
      title="Current-period profit when x=$x")
    mycb = scatter([0,0], [0,1], zcolor=[0,3], clims=(-f_max_abs,f_max_abs),
                               xlims=(1,1.1), label="", c=:RdBu, colorbar_title="a-title-here", framestyle=:none)
    plot(p, mycb; layout=l)
end

The surface colors look better, but the colormap is not completely right. Almost there:

latest version of chart

Dan Getz
  • 17,002
  • 2
  • 23
  • 41
0

I transformed the colorscheme created by @Dan Getz into a PlotlyJS colorscheme, and defined the surface via PlotlyJS and got:

enter image description here

with the following code:

using PlotlyJS, ColorSchemes
import Plots:cgrad, RGB, hex

plotly_cmap(colorscheme)= [[s, hex(RGB(color))] for (s, color) in 
            zip(colorscheme.values, colorscheme.colors)]
A = 1
αω = 0.5
αz = 0.5
β1 = 1
β2 = 1
β0 = 0
γ = 1

# Functions
π(ω,z) = A*ω^(αω)*z^(-αz)
c(x) = β1*x + β2*x^2 + β0
p(x) = 1 - exp(-γ*x);
F(x,Ω=Ω, Z=Z) = [π(ω_val, z_val) for ω_val in Ω, z_val in Z] .- [c(x) for ω_val in Ω, z_val in Z]

# Grids
Ω = range(0, 1, length=101)
Z = range(0.4, 1, length=101)

function plot_f(x, Ω=Ω, Z=Z)
    f_values = F(x,Ω,Z)
    zm, zM=extrema(f_values)
    z_max_abs = max(zM, -zm)
    f_cmap = cgrad(ColorSchemes.RdBu[range(([zm, zM]./(2*z_max_abs) .+ 0.5)...,length=11)])

    # Create a 3D surface plot of f(ω,z) for the given value of x, with the colormap fixed at 0 for the white portion
    fig=Plot(surface(x=Z, y=Ω, z=f_values, 
             colorscale=plotly_cmap(f_cmap), colorbar_thickness=24),
             Layout(scene=attr(xaxis_title="z", yaxis_title="ω", zaxis_title="π(ω,z) - c($x)",
                    camera_eye=attr(x=-1.85, y=1.85, z=1)),
        
        title_text="Current-period profit when x=$x", title_x=0.5, width=500, height=500))
end
plot_f(0.9)

The surface corresponding to plot_f(0.4) is his one: enter image description here

xecafe
  • 740
  • 6
  • 12