Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support plotting surface data #11

Closed
jebej opened this issue Jun 9, 2017 · 16 comments · Fixed by #57
Closed

Support plotting surface data #11

jebej opened this issue Jun 9, 2017 · 16 comments · Fixed by #57

Comments

@jebej
Copy link
Contributor

jebej commented Jun 9, 2017

This would require a method for Coordinates that takes x,y, and z where z is a matrix such that size(z,1)==length(x) and size(z,2)==length(y)

@KristofferC
Copy link
Owner

Good suggestion. Could you for reference link to an example or a stackoverflow post with some code so I can see how the tex should look.

@jebej
Copy link
Contributor Author

jebej commented Jun 9, 2017

The answers to this question show the format, and a use both with "matrix plot" and "surf". Basically you need to give x y z points.

I am personally trying to do a matrix plot (page 171 of the manual), but I find that doing

Plot(data,
    {
        "matrix plot"
    })

does not work.

The code for the data coordinates looks like this, which is what the Coordinates method could do automatically given x,y,z:

xx = repmat(x,length(y))
yy = vec(repmat(y.',length(x))
zz = vec(z)
data = Coordinates(xx,yy,zz)

@KristofferC
Copy link
Owner

Are the empty lines needed for the output to be correct or are they just for clarity in the examples?

@jebej
Copy link
Contributor Author

jebej commented Jun 9, 2017

I think there needs to be one, although the number of rows or columns can be specified in which case it's not necessary:

Limitations: Due to current implementational restrictions, matrix plot can only update axis limits
successfully if the length of the matrix scanlines is known in advance. The example above contains
mesh/cols=3, and a “scanline” is a row (with 3 columns each). Consequently, the example above works
fine. However, If mesh/cols=3 would be unknown in advance, the current implementation assumes that
end-of-scanline markers are given in the input file according to empty line=scanline. As a rule of
thumb, you have to follow the following guidelines when using matrix plot:

  1. The input matrix should have an empty line whenever one line of input is finished.
  2. If there is no empty line, the length of each scanline must be given. For the standard con-
    figuration mesh/ordering=x varies, pgfplots expects mesh/cols. For the alternative choice
    mesh/ordering=y varies, pgfplots expects mesh/rows to be set.
  3. The input matrix must have at least 2 rows and at least 2 columns. This allows pgfplots to
    interpolate/extrapolate the vertices in a well-defined way

@jebej
Copy link
Contributor Author

jebej commented Jun 9, 2017

I think my case will be easier with a table. Will make an example as soon as I figure it out.

@pevnak
Copy link

pevnak commented Aug 21, 2017

I have encountered the same problem.
at the moment the package produces output like this

\RequirePackage{luatex85}
\documentclass[tikz]{standalone}
% Default preamble
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepgfplotslibrary{groupplots}
\usepgfplotslibrary{polar}
\usepgfplotslibrary{statistics}
\begin{document}
\begin{tikzpicture}[]
\begin{axis}[xlabel={trnuses}, ylabel={tstuses}]
\addplot[matrix plot*, point meta=explicit]
table [x={trnuses}, y={tstuses}, meta={tsterr}]
{ trnuses tstuses tsterr
0.01 0.01 0.0241
0.01 0.02 0.0237
0.01 0.05 0.023600000000000003
0.01 0.1 0.040600000000000004
0.01 0.2 0.2051
0.01 0.5 0.45289999999999997
0.01 1.0 0.49420000000000003
0.02 0.01 0.024399999999999998
0.02 0.02 0.023799999999999998
0.02 0.05 0.023899999999999998
0.02 0.1 0.0403
0.02 0.2 0.1996
0.02 0.5 0.45099999999999996
0.02 1.0 0.49450000000000005
0.05 0.01 0.0242
0.05 0.02 0.0242
0.05 0.05 0.0237
0.05 0.1 0.042
0.05 0.2 0.2113
0.05 0.5 0.4574
0.05 1.0 0.49450000000000005
0.1 0.01 0.0256
0.1 0.02 0.0257
0.1 0.05 0.0253
0.1 0.1 0.0361
0.1 0.2 0.1131
0.1 0.5 0.378
0.1 1.0 0.4755000000000001
0.2 0.01 0.036500000000000005
0.2 0.02 0.037000000000000005
0.2 0.05 0.036500000000000005
0.2 0.1 0.042600000000000006
0.2 0.2 0.05720000000000001
0.2 0.5 0.2472
0.2 1.0 0.3833
0.5 0.01 0.0867
0.5 0.02 0.0869
0.5 0.05 0.0865
0.5 0.1 0.0891
0.5 0.2 0.09729999999999998
0.5 0.5 0.1554
0.5 1.0 0.27549999999999997
1.0 0.01 0.146
1.0 0.02 0.14609999999999998
1.0 0.05 0.1458
1.0 0.1 0.1473
1.0 0.2 0.15430000000000002
1.0 0.5 0.1793
1.0 1.0 0.2505
}
;
\end{axis}
\end{tikzpicture}
\end{document}

which does not compile. After you add the blank lines

\RequirePackage{luatex85}
\documentclass[tikz]{standalone}
% Default preamble
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepgfplotslibrary{groupplots}
\usepgfplotslibrary{polar}
\usepgfplotslibrary{statistics}
\begin{document}
\begin{tikzpicture}[]
\begin{axis}[xlabel={trnuses}, ylabel={tstuses}]
\addplot[matrix plot*, point meta=explicit]
table [x={trnuses}, y={tstuses}, meta={tsterr}]
{ trnuses tstuses tsterr
0.01 0.01 0.0241
0.01 0.02 0.0237
0.01 0.05 0.023600000000000003
0.01 0.1 0.040600000000000004
0.01 0.2 0.2051
0.01 0.5 0.45289999999999997
0.01 1.0 0.

       0.02	0.01	0.024399999999999998
       0.02	0.02	0.023799999999999998
       0.02	0.05	0.023899999999999998
       0.02	0.1	0.0403
       0.02	0.2	0.1996
       0.02	0.5	0.45099999999999996
       0.02	1.0	0.49450000000000005

       0.05	0.01	0.0242
       0.05	0.02	0.0242
       0.05	0.05	0.0237
       0.05	0.1	0.042
       0.05	0.2	0.2113
       0.05	0.5	0.4574
       0.05	1.0	0.49450000000000005

       0.1	0.01	0.0256
       0.1	0.02	0.0257
       0.1	0.05	0.0253
       0.1	0.1	0.0361
       0.1	0.2	0.1131
       0.1	0.5	0.378
       0.1	1.0	0.4755000000000001

       0.2	0.01	0.036500000000000005
       0.2	0.02	0.037000000000000005
       0.2	0.05	0.036500000000000005
       0.2	0.1	0.042600000000000006
       0.2	0.2	0.05720000000000001
       0.2	0.5	0.2472
       0.2	1.0	0.3833

       0.5	0.01	0.0867
       0.5	0.02	0.0869
       0.5	0.05	0.0865
       0.5	0.1	0.0891
       0.5	0.2	0.09729999999999998
       0.5	0.5	0.1554
       0.5	1.0	0.27549999999999997
       
       1.0	0.01	0.146
       1.0	0.02	0.14609999999999998
       1.0	0.05	0.1458
       1.0	0.1	0.1473
       1.0	0.2	0.15430000000000002
       1.0	0.5	0.1793
       1.0	1.0	0.2505
       }
   ;

\end{axis}
\end{tikzpicture}

\end{document}

it works.

I apologize for broken formatting, just do not know, how to do it properly.

@tpapp
Copy link
Collaborator

tpapp commented Jan 10, 2018

Supporting the table format would also allow contour plots. See the countour prepared keywords in Section 4.6.8 of the pgfplots manual. A tool like Contour.jl would allow the computation of the curves without external tools.

@KristofferC
Copy link
Owner

Using Contour.jl already works (see last example in https://github.com/KristofferC/PGFPlotsXExamples/blob/master/examples/custom_types.ipynb).

@tpapp
Copy link
Collaborator

tpapp commented Jan 13, 2018

@jebej: this reproduces the first example on p 171:

x = repeat(0:2, outer = 3)
y = repeat(0:2, inner = 3)
meta = ["color=$c" for c in ["red", "blue", "yellow", "black", "brown", "magenta", "green", "red", "white"]]
c = Coordinates(Float64.(hcat(x, y))'; metadata = meta)
p = @pgf Axis(Plot(c,
          {
            matrix_plot,
            mark = "*",
            nodes_near_coords = raw"\coordindex",
            "mesh/color input" = "explicit",
            "mesh/cols" = 3,
        }), { enlargelimits = false })

Will make a PR to the examples repo soon.

tpapp added a commit that referenced this issue Feb 3, 2018
This is a step towards fixing #44, and is in accordance with the
principles laid out there, but not the exact syntax proposed there
since it was found to be impractical. Also fixes #11.

1. Introduce the `Coordinate` type for individual coordinates. Validate
arguments and fail early.

2. Introduce `EmptyLine` for jumps/scanlines. This addresses #11.

3. Rewrite `Coordinates` to contain the above. (`<: OptionType` was
removed, because it has no options).

4. Convenience constructors for creating coordinates from vectors,
matrices, iterable objects, with or without error bars. Docstrings for
the API.

5. Add examples of all the new syntax to the gallery (some of this
should be moved to the documentation eventually, that will come later
after other changes).

6. 2D histograms now work (example will be added later, when `Table`
are redesigned similarly).
KristofferC pushed a commit that referenced this issue Feb 6, 2018
* Rework coordinates.

This is a step towards fixing #44, and is in accordance with the
principles laid out there, but not the exact syntax proposed there
since it was found to be impractical. Also fixes #11.

1. Introduce the `Coordinate` type for individual coordinates. Validate
arguments and fail early.

2. Introduce `EmptyLine` for jumps/scanlines. This addresses #11.

3. Rewrite `Coordinates` to contain the above. (`<: OptionType` was
removed, because it has no options).

4. Convenience constructors for creating coordinates from vectors,
matrices, iterable objects, with or without error bars. Docstrings for
the API.

5. Add examples of all the new syntax to the gallery (some of this
should be moved to the documentation eventually, that will come later
after other changes).

6. 2D histograms now work (example will be added later, when `Table`
are redesigned similarly).

* Fixed missing packages in REQUIRE.

* small formatting changes
@CarolinGao12
Copy link

I have the same problem, but in my case, my x,y, are not easily to be formed in a table. Is there any solution for x, y, z , which are all matrix , so that it is accepted by surface plot ?

@tpapp
Copy link
Collaborator

tpapp commented Apr 16, 2018

@CarolinGao12 : please provide a minimal working example. There is a

Table([options], ::AbstractVector, ::AbstractVector, ::AbstractMatrix; ...)

constructor (implemented by TableData) but I don't know how you specify coordinates from matrices.

@CarolinGao12
Copy link

CarolinGao12 commented Apr 17, 2018

it seems the x, y input should be a vector , and z can be a matrix
but in my case, the xp_k and yp_k are matrixs

for k = 1: numAnt
    xp_k=[xp[k,:,:];reshape(xp[k,1,:],(1,91))]
    yp_k=[yp[k,:,:];reshape(yp[k,1,:],(1,91))]
    zp_k=[zp[k,:,:];reshape(zp[k,1,:],(1,91))]
    @pgf Plot3(
    {
        surf,
    },
    Coordinates(xp_k,yp_k,zp_k)
    )
end     

@KristofferC
Copy link
Owner

So perhaps we should add:

function Coordinates(x::AbstractMatrix, y::AbstractMatrix, z::AbstractMatrix;
                     meta::Union{Void, AbstractMatrix} = nothing)
    @argcheck size(x) == size(y) == size(z)
    meta ≠ nothing && @argcheck size(meta) == size(z)
    insert_scanlines(Coordinates(vec(x), vec(y), vec(z);
                     meta = meta ≠ nothing ? vec(meta) : meta),
                     size(z, 2))
end

giving

julia> print_tex(Coordinates([1 1; 2 2], [1 2; 1 2], [1 2; 3 4]))
coordinates {
    (1, 1, 1)
    (2, 1, 3)

    (1, 2, 2)
    (2, 2, 4)
}

But what if both x and y is changing in one "scan line", not sure what happens then.

@CarolinGao12
Copy link

thanks, I change the matrix to the vector and this problem solved

@tpapp
Copy link
Collaborator

tpapp commented Apr 17, 2018

  1. Following the pgfplots manual, I would suggest the Table constructors.

  2. @CarolinGao12, it would be great if you could provide a self-contained minimal working example. I am assuming you are generating the x and y somehow by repeating elements, that step could be omitted.

  3. @KristofferC: interesting question. Apparently pgfplots will just omit the node that does not belong there. Example:

using PGFPlotsX
@pgf Plot3({ surf, shader = "interp" },
           Table([:x => vec([1 1; 2 2]),
                  :y => vec([1 2; 1 2]),
                  :z => vec([1 2; 3 4])],
                 scanlines = 2))
pgfsave("/tmp/regular.png", ans)
@pgf Plot3({ surf, shader = "interp" },
           Table([:x => vec([1 1; 1 2]),
                  :y => vec([1 2; 2 2]),
                  :z => vec([1 2; 3 4])],
                 scanlines = 2))
pgfsave("/tmp/irregular.png", ans)

regular
irregular

I don't think we should add a constructor for this, as it would just be confusing.

@CarolinGao12
Copy link

    @pgf begin 
     
    p1=Plot3(
    {
        surf,
        opacity=0.6,
        "colormap/jet",
           shader=>"faceted interp",
            "faceted color= black",
            
   }, 
   Table([:x => vec(xp_1),
                  :y => vec(yp_1),
                  :z => vec(zp_1)],
                 scanlines = 2)
   )

    

it works fine
download

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants