pax_global_header00006660000000000000000000000064122613172150014512gustar00rootroot0000000000000052 comment=711fa6f037e7ae612909e319bb487b200f405e50 matlab2tikz-0.4.4/000077500000000000000000000000001226131721500137435ustar00rootroot00000000000000matlab2tikz-0.4.4/AUTHORS000066400000000000000000000001321226131721500150070ustar00rootroot00000000000000Nico Schlömer designed and implemented the intial version and is the current maintainer. matlab2tikz-0.4.4/COPYING000066400000000000000000000024741226131721500150050ustar00rootroot00000000000000Copyright (c) 2008--2012 Nico Schlömer All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. matlab2tikz-0.4.4/ChangeLog000066400000000000000000000206241226131721500155210ustar00rootroot000000000000002013-10-20 Nico Schlömer * Version 0.4.4. * Support for color maps with scatter plots. * Support for different-length up-down error bars. * Input options validation. * Bugfixes: - legends for both area and line plots - invisible text fields 2013-10-20 Nico Schlömer * Version 0.4.3. * Support for 3D quiver plots. * Extended support for colorbar axis options. * New logo! * Bugfixes: - text generation - extraCode option - join strings - ... 2013-09-12 Nico Schlömer * Version 0.4.2. * Support for explicit color specification in 3D plots. * Better color handling for patch plots. * Support for various unicode characters. * Bugfixes: - edge colors for bar plots - multiple color bars - ... 2013-08-14 Nico Schlömer * Version 0.4.1. * Replaced option `extraTikzpictureCode` by `extraCode` for inserting code at the beginning of the file. * Support for relative text positioning. * Improved documentation. * Code cleanup: moved all figure manipulations over to cleanfigure() * Bugfixes: - error bars - empty tick labels - ... 2013-06-26 Nico Schlömer * Version 0.4.0. * Added cleanfigure() for removing unwanted entities from a plot before conversion * Add option `floatFormat` to allow for custom specification of the format of float numbers * Bugfixes: - linewidth for patches - ... 2013-04-13 Nico Schlömer * Version 0.3.3. * Support for: - pictures in LaTeX subfloats * Bugfixes: - axes labels - extra* options - logscaled axes - ... 2013-03-14 Nico Schlömer * Version 0.3.2. * Support for: - waterfall plots * Bugfixes: - axis locations - color handling - stacked bars - ... 2013-02-15 Nico Schlömer * Version 0.3.1. * Use table{} for plots for cleaner output files. * Support for: - hg transformations - pcolor plots * Removed command line options: - minimumPointsDistance * Bugfixes: - legend positioning and alignment - tick labels - a bunch of fixed for Octave - line width for markers - axis labels for color bars - image trimming - subplots with bars - ... 2012-11-19 Nico Schlömer * Version 0.3.0. * Support for: - area plots - legend position - inner color bars - log-scaled color bars * New command line options: - standalone (create compilable TeX file) - checkForUpdates * mlint cleanups. * Removed deprecated options. * Bugfixes: - colorbar-axis association - option parsing - automatic updater - unit 'px' - ... 2012-09-01 Nico Schlömer * Version 0.2.3. * Multiline text for all entities. * Support for logical images. * Support for multiple legends (legends in subplots). * Fixed version check bug. * Fix minumumPointsDistance. 2012-07-19 Nico Schlömer * Version 0.2.2. * Support for multiline titles and axis labels. * Respect log-scaled axes for minimumPointsDistance. * Add support for automatic graph labels via new option. * About 5 bugfixes. 2012-05-04 Nico Schlömer * Version 0.2.1. * Support for color maps. * Support for native color bars. * Partial support for hist3 plots. * Support for spectrogram plots. * Support for rotated text. * Native handling of Infs/NaNs. * Better info text. * matlab2tikz version checking. * Line plotting code cleanup. * About 10 bugfixes. 2012-03-17 Nico Schlömer * Version 0.2.0. * Greatly overhauled text handling. (Burkhart Lingner) * Added option 'tikzFileComment'. * Added option 'parseStrings'. * Added option 'extraTikzpictureSettings'. * Added proper documetion (for 'help matlab2tikz'). * Improved legend positioning, orientation. * Support for horizontal bar plots. * Get bar widths right. * Doubles are plottet with 15-digit precision now. * Support for rectangle objects. * Better color handling. * Testing framework improvements. * Several bugfixes: - ticks handled more concisely - line splitting bugs - ... 2011-11-22 Nico Schlömer * Version 0.1.4. * Support for scatter 3D plots. * Support for 3D parameter curves. * Support for 3D patches. * Support for minor ticks. * Add option interpretTickLabelsAsTex (default false). * Several bugfixes: - %-sign in annotations - fixed \omega and friends in annotations - proper legend for bar plots - don't override PNG files if there is more than one image plot - don't always close patch paths 2011-08-22 Nico Schlömer * Version 0.1.3. * Greatly overhauled text handling. * Better Octave compatibility. * Several bugfixes: - subplot order - environment detection 2011-06-02 Nico Schlömer * Version 0.1.2. * Support for logscaled color bar. * Support for truecolor images. * Initial support for text handles. * Speed up processing for line plots. * Several bugfixes: - axis labels, tick labels, etc. for z-axis - marker handling for scatter plots - fix for unicolor scatter plots 2011-04-06 Nico Schlömer * Version 0.1.1. * Improved Octave compatibility. * Several bugfixes: - input parser 2011-01-31 Nico Schlömer * Version 0.1.0. * Basic Octave compatibility. * Several bugfixes: - bar plots fix (thanks to Christoph Rüdiger) - fix legends with split graphs 2010-09-10 Nico Schlömer * Version 0.0.7. * Compatibility fixes for older MATLAB installations. * Several bugfixes: - line plots with only one point - certain surface plots - orientation of triangle markers ("<" vs. ">") - display of the color "purple" 2010-05-06 Nico Schlömer * Version 0.0.6. * Support for scatter plots. * Preliminary support for surface plots; thanks to Pooya. * Large changes in the codebase: - next to matlab2tikz.m, the file pgfplotsEnvironment.m is now needed as well; it provides a much better structured approach to storing and writing environments when parsing the MATLAB(R) figure * proper MATLAB(R) version check * lots of small fixes 2009-12-21 Nico Schlömer * Version 0.0.5. * Improvements in axis handling: - colored axes - allow different left and right ordinates * Improvements for line plots: * Version 0.0.5. * Improvements in axis handling: - colored axes - allow different left and right ordinates * Improvements for line plots: - far outliers are moved toward the plot, avoiding 'Dimension too large'-type errors in LaTeX - optional point reduction by new option 'minimumPointsDistance' * Improvements for image handling: - creation of a PNG file, added by '\addplot graphics' - fixed axis orientation bug * Bugfixes for: - multiple axes - CMYK colors - legend text alignment (thanks Dragen Mitrevski) - transparent patches (thanks Carlos Russo) * Added support for: - background color - Bode plots - zplane plots - freqz plots 2009-06-09 Nico Schlömer * Version 0.0.4. * Added support for: - error bars (thanks Robert Whittlesey for the suggestion) * Improvents in: - legends (thanks Theo Markettos for the patch), - images, - quiver plots (thanks Robert for spotting this). * Improved options handling. * Allow for custom file encoding (thanks Donghua Wang for the suggestion). * Numerous bugfixes (thanks Andreas Gäb). 2009-03-08 Nico Schlömer * Version 0.0.3. * Added support for: - subplots - reverse axes * Completed support for: - images 2009-01-08 Nico Schlömer * Version 0.0.2. * Added support for: - quiver (arrow) plots - bar plots - stem plots - stairs plots * Added preliminary support for: - images - rose plots - compass plots - polar plots * Moreover, large code improvement have been introduced, notably: - aspect ratio handling - color handling - plot options handling 2008-11-07 Nico Schlömer * Initial version 0.0.1. matlab2tikz-0.4.4/Makefile000066400000000000000000000007661226131721500154140ustar00rootroot00000000000000# This makefile creates a release tarball. MATLAB2TIKZ_DIR=. VERSION=0.4.4 default: release release: # The license is automatically added by # MathWorks after the upload. @zip -r matlab2tikz_${VERSION}.zip \ ${MATLAB2TIKZ_DIR}/AUTHORS \ ${MATLAB2TIKZ_DIR}/ChangeLog \ ${MATLAB2TIKZ_DIR}/README.md \ ${MATLAB2TIKZ_DIR}/THANKS \ ${MATLAB2TIKZ_DIR}/version-${VERSION} \ ${MATLAB2TIKZ_DIR}/tools/ \ ${MATLAB2TIKZ_DIR}/src/ clean: rm -f matlab2tikz_${VERSION}.zip matlab2tikz-0.4.4/README.md000066400000000000000000000047021226131721500152250ustar00rootroot00000000000000=============================== Logo contest! ------------- On http://tex.stackexchange.com/questions/132985/matlab2tikz-logo you can submit your own suggestion for a new matlab2tikz logo. Chime in if you have something nice and iconic in mind! =============================== This is matlab2tikz, a MATLAB(R) script for converting MATLAB(R) figures into native TikZ/Pgfplots figures. To download and rate matlab2tikz, go to its page on MathWorks http://www.mathworks.com/matlabcentral/fileexchange/22022. matlab2tikz supports the conversion of most MATLAB figures, including 2D and 3D plots. For plots constructed with third- party packages, your mileage may vary. The workflow is as follows. 0. a. Place the matlab2tikz scripts (contents of src/ folder) in a directory where MATLAB can find it (the current directory, for example). b. Make sure that your LaTeX installation includes the packages * TikZ (aka PGF, >=2.00) and * Pgfplots (>=1.3). 1. Generate your plot in MATLAB. 2. Invoke matlab2tikz by ```matlab >> matlab2tikz(); ``` or ```matlab >> matlab2tikz('myfile.tex'); ``` The script accepts numerous options; check them out by invoking the help, ```matlab >> help matlab2tikz ``` Sometimes, MATLAB makes it hard to create matching LaTeX plots by keeping invisible objects around or stretches the plots too far beyond the bounding box. Use ```matlab >> cleanfigure; >> matlab2tikz('myfile.tex'); ``` to first clean the figure of unwanted entities, and then convert it to TeX. 3. Add the contents of `myfile.tex` into your LaTeX source code; a convenient way of doing so is to use `\input{/path/to/myfile.tex}`. Also make sure that at the header of your document the Pgfplots package is included: ```latex \documentclass{article} \usepackage{pgfplots} % and optionally (as of Pgfplots 1.3): \pgfplotsset{compat=newest} \pgfplotsset{plot coordinates/math parser=false} \newlength\figureheight \newlength\figurewidth \begin{document} \input{myfile.tex} \end{document} ``` There are reported incompatibilities with the following LaTeX packages: * signalflowdiagram (Check out .) If you experience bugs, have nice examples of what matlab2tikz can do, or if you are just looking for more information, please visit the web page of matlab2tikz . matlab2tikz-0.4.4/THANKS000066400000000000000000000016131226131721500146570ustar00rootroot00000000000000matlab2tikz has once greatly profited from its ancestor, Matfig2PGF, http://www.mathworks.com/matlabcentral/fileexchange/12962 Matfig2PGF is written by Paul Wagenaars. Also, the author would like to thank Christian Feuersänger package Pgfplots without which the structure of matlab2tikz would hardly be possible. Thanks for patches, suggestions, and other contributions to Katherine Elkington Andreas Gäb Roman Gesenhues David Haberthür Patrick Häcker Mykel Kochenderfer Henk Kortier Theo Markettos Dragan Mitrevski Carlos Russo Robert Whittlesey Pooya Ziraksaz Johannes Schmitz Christoph Rüdiger Ben Abbott Johannes Mueller-Roemer Julien Ridoux Burkart Lingner Francesco Montorsi Ricardo Santiago Mozos Eike Blechschmidt Michael Schoeberl Patrick Häcker Egon Geerardyn ... and MathWorks' very own Martijn Aben Bastiaan Zuurendonk Michael Glasser and many more! matlab2tikz-0.4.4/gallery/000077500000000000000000000000001226131721500154025ustar00rootroot00000000000000matlab2tikz-0.4.4/gallery/matlab2tikz-snapshot.png000066400000000000000000001024001226131721500221660ustar00rootroot00000000000000PNG  IHDR-!7 pHYs7o IDATx{@Te?yLS/IR)AMԕ(ru1L30[jM}k#RqSu ՊBL #x# 2(*9s\53s ND~رcwW_}vG["6m8pwhC{{yec;?Ӂ-oGxbǚ7nkyݪU/-rItÇ; yZhXl;~޽cǎ/ ׯ߳>X%ԩSN8p Q~~@{l'77cǎuo;vgڣOoBS܉ŋ~gtҭ[7O>F)lOyGb?N<цٳg-qZlyYڣOoDSxSv:tP7ϯm۶w}M`"t}G77c֍3a„f͜HYǕ+W{/՟fs0dr=vq48UZZjͰ{=.\P( $w}w?qssNiJb״P]]g͜9pww{[]]@{Ԧc4P /(5{k4>ڣ^HNN$~x`޽O>W_9СåKv9U~///Gۢ nN,m۶-Xv)NTѪU|ǎvؑhŢ"B-222.]t d28pwQ0`ӧޞolknprIfh~557XԘWT+v 5 ߯a3ne?khp;lP܁~n掫68IÖH n+6hT547φ&!j6!UT?oؐf[o'6lVˮlk&Ҳkɵzz-3$~ZZb- NՃo L2?#~l^>-?Z=Iw-?ټZ6fV',7zk9m]X=Ig-' ,H|/ohFK+ޥm}$TlCokhO-UVR -]-ϜPX7}2EC r!9~@B?@ [o':{DG`Hj\|HMU7W+Eq~!9~@B?@ @ @ A@  C r!9~@B?@ @ @ A@  C rp~o&؃74fMW46y^x_m=?i|Mk4Y4憦5*5@ pE~@B?@ @ @ FyԘV *!U@ 4nJ r!9~@B?@ ?|G}d0[nu?]zuQQ]wuرo۷@ pЏ?O-ZBCC===={Z 8xĉk;[,g՛o-###[jayp#FX^[N@ 8 G``^˖׹;w޽{6Q NH+Wֽ.++;vذa,oϞ=kkYhٲٳg6Q NHQs_ҥld25xa'YRVj}geEfSaTa2pZۄaRqZ-]jn̆ >teuo|̀:T@ PhСC͚5a.]Th4kRK̬N|Yb)0L*08m08ar'†<<<ٜn<00ԩS555'O߿e@40 ֭k۶m~~~MM~aˏ^|Źs ޽{ؽ{w+;vw}Wbˋ;*((O`@ c۶m7 ::Z5c@2@ +%_~@B?@ @ @ A@  C r!9(1a2s"ɋ]ff~&Pzv=TБ|Rx!Q4* FWg9\nl)g?nht/[{頼%&3' Nsˤ3%䝢O';A5{hw;mx\yc5K. D.ww=hI ig G[| U?r4T%M+֚~Bv +?f=k DBm4Ѵ_}9y͇0%gA?NL 6Y3awG[fwU/f!Ւ=ա)SEC09Tƶ"s C֋~rv"{Mh@&B?.bٛ>M0V(IMBK!pI,~UӃf؄zZ>BK@eNm8Nm ;9Zr\%!C|w"z?:{%6 E_μRu$EOfvC *$\ C|XRoë :ڠЗq̪7ھtþgo+9~]!9:C1nn%u|?ZBb" 6^D]1HA9K&(\`2#{IM죌~[4^pE ?{r7NJnPtzuD TKHeD.`H7 0bIQD)9mVba%}7[Վ! @]xRfPAIFW7(_'$C{2'RĔRYI ,B?Q8G Jf2e>Rw7{WE#'T|$Iy1V YpgB?ʠƶC_F|4g2Y٩D j$19lQLfkz*;KӋ";e!˶ckqm; LK%q-ߐ_9DIߔpbsZ!;ݻ*i1^w8lG"&31{pg B?6a0go<ʋ<6䭬A !9qJ} 莱my`hDnxޮ#`m:eD$ȏ+ןbE:ɩĆ;Ҧ:Y1Qi<&ΎM],=J{/(3-JprmlÆ>??ȡ .mM&N&{7Wq0Q׽ |)_k_y㏼{XN_ncz?%|YN|R9'pV:gMfÒͤIrb!tlFԯHMcC<{ۺ)1XKXUع%(,!f!6MPrNxdP6pV:)pƌ$9O薧͹$һ'd$Ťo"-Rc1zM:)bf%SGuz~EO*|H%(L'OlB/)1I-߰eBЃ.2G$>O122;HsD>/%%df|"{0UZ"RA_NgHTfB~Dr9w.~-%!2(zbNM胒dbǬ2s {G̨8XuF~wiV&wSw\\f|iky`xV)gxmllISDs;K^2!>$DHF* C@2 'sd0/ |9OFWy'(2W̞OIo>2Դ'1eh&s+VC^$e=qI$M":Tf&OvۖUCa92 A@ HeFu/i+lSYdcɧxy1%BMM_Ǖ}11i͒7FZY1 *dl2DQ!C 5D T ln27E9d[B#^6m;,~sקq= IF& QaYasRCB?E!Nlh5'Gw2ecԇCnX+&ٙTYyKdd2|9^Bf:vx$Ӆ]8JP/K[4I'7 .bԧ&p b0oG ]˶#i&n,-Y*8d"'Ե|ofQ2Y*PN?ѿՅ(y+(6t($>c1/va$m $K[d#kR"yF?F@~A2zc2/'3&T/

H乳t˚פym":TU7B8%5#a\_FjiJ-}kPNX,sNxu3!'1ٶy 9X@f {/;k'NʉQ`p{K6TٓEF+%̶ΣS߼}kF[z{KV<, !e97<= ɦ"0f}@%X}p'UVH6&&&'B?;RsmħvHķ:=枭زSʤB7bɋhڰ"&Nb ЏŤĥ: g$$G'a|D=&m/%n흒/lE:-lhAL(m{M Dؚ?@o RV.W ?Y e!*rkCb Џ& lA۝]{Җ8! 5>ҥz\U~VDUf6} mt`vi 5mMدCߴ7,(;nD@W4m8؄Y(+ĨGFd魇Y 4{N6%bD6ھȺkOʼL%-Y,36c JVUg݋"]R՜(UJKtԨX_EY "M?ԠiAPԠ֧vu,QKH]"B}YW~D ี'Bw\xW^+u's%vܲc{%ϣ-Ia(4pww6lXEEŌ3ƍ"/ ʇx(tьQ߹ΖDYO:ug k `I;(lt!?ㆡ\~t"_nÝGQs+ փA~,XW^w{?77GHϬN4SLj>qꮊl\C}1As'A]:Һ9͝k?ԕ)FBڵ ɴHl^7S>{Wz߽Dj ي>O:X#UP=lCb%?"Y<[e IDATS*%}IRX?%O+.@\g p݇Vp?:uzD;ZkO40C*bjb{fऑ"#^?G^a܁uhJ싮)ym vd1IC6βunL" FukGV~ƾFDYu%1=>ݬhd[I^JD$tlŬH%5\Z{$ <[JoIЛ3k|[Gur~5W^u~=s'Nl`^GVSƿ KT #@A9MLv)[Nһ#S䔱Dz]" ?χ?1!O&ĽOL`=Klfl"y qsL&a)50Q &AvꋉM!ޒ/7'b1Qif sg *Q{wߕZII;K֤ };!eS &3Տ!~`8G::ôt2ک#;}(~Ɠ#!^ӚMDhÁu77k]A)L#'C=vHYDy=Dnj(#%Ixd2w"e6 IgPbKXMp?⑵=ox;ڦng b[cǎW:踬=zt>y׎}9 s6o%Нc[ i?Qz1֝~e2xET>CдgVyBLf!y=k#-O3Ak/wwrLR`h0ahl4Llʌ˜$U{ >b{)ȩ=f'R*Dm_͘1lٲe!!!AAAi$77絋~X#Er ϲ?u~K@GBNwIV]eӬM5\`2"cDN.KDlZxo{? y<<1N$MRKlQU~r\el8yMDOP1xl-"m訡iڍE'g/w1֗lNI)@'/be`vFZ$V%|t˲ `ULѨ[UiBaBR9,r}٥,?sD寖Kw+xQ>"᪌%l#cz$"c% IH~ }1ٻn/]oB;vJpdiwԯ$V]C~R7lYա3SR&+3[hQIuCzhF)2H9R^i"f%4g ޳$EL&ȶm`!Qb8C{;9xAG~ПbE:ɩD5`Ejo/hQFwzP[` ,"navx&Z ?q둪. Jx0)J$~"5&m#ˈLGBv"oL0;{?lB6?Eq;7nDF.3'a;QFYE]EШ&C_B+hO,dpi}X~`J ^w-+jOH h$ڂC9'K):MN[s)=оh{1@5!u0zY-iJH24З3B<\-h_ОUĔuwG˘-yc¬}6^x 9İu/'[ ? 3H;@#ǭ?CA1?p0~8={_woP +> YI{'< FV/ `Cqrk#}摦ʙ1USk$Wj0[ہ1HV! H`7JDz.?=%NT٠XD~u=0eah?4 zn=6^܄:(-'f09lGH"~̌ZAbo!N$DC][+,Le")>ʄ 8MfN}{k#9_O] @We^}ͯ\]O-7 |%@ 1؆T I\HM~Xcҽ"1U$3rKAk;d73¥=ؚȔU1S.p$EgI]zEh5@7 wUN. P'^w0I^.&*$ gq%i_MB5Lsȿ뿓*ba.[ƣL "v;s9\Kߓw3=]@YM&og4b\R?fml\t&VaN#e̤ P. [}Np#.BUߚLa ED6#$D6 '-#E3]F/gEomfcL$pDwir~3=߃֏vk\$! uzp`SrNm U/ksjZ7Bm!!p1*"q#Gh$29A6J/(Zu(2S8\B)J/27z6^v2 +*վ9Ru!vw^c NQMz΢:% &3 ’X9ZS8+:#$beK9Ӕ^fh{"N-Xα[Oz(=VlLr)cO"k>Qa2(2C%% 4^-Ҏhۡir}8V/,?}1>JJ٣y>΀+qvaOJO!m l_(p"AeNZeSFKȚXe#ƍőha0¦߫TcT̈́o?K="eL,.b 2#Ze0[4^D2[4zLf_{]MJPI5$"ډ2eG`Wǫ߳OIh{L4Oet'zOk(Ⱥ9ή}9B\5@inbhSnu IkkPPIm@_Nv19Hѻ ^f7Vq܀$9k AWEsǯCk'A LFX$d2#p90Zu\S5s/͂YrۚDg'6KPe 3}Ӭ-7 `X/bE``<r/Aw kXQflfX% ֏VM0iM}Woe% ">1U3j!)&!u4ΐvg ddo:2Tp EgkwGB?q=+|FD>21|9)yuE.f4Y7kϲ~Z_Ceΐ~UHD_=jb}?]Ȫ\| D9WGT_p^]CFsr q,|=oh0d]SD/4 dcEMn7 )1b\r'dWD9j-ΫG=,N0UMA!]HZN3? {S׭k .sLE p*bˊϦY _SEq.rJbI?S`ঘ쟸۹3Uba;1aII܀xn HaSwtL*ьi]!Dk94mX?|{C*B1ʝ0؏!!0^Q}F7UBTgT !͙G~%Ԧg Xr41UJLc[lRp'C;IXOU *:~'#)Aynr.OLO7fV, U Ǭd4Gf1hڐ!SV^ُߩDcBEħ驄T]s&%1+U$ zr41 USM66dΦ,u%ijQdzuj:֝3ڱ^2.K {\{2}译yȦ@D_eOcQ2Sو kf.!ӇM*GD<$aWǒ;EB%As ˏ4J}yٖf!4faRЧ0՚1C F;cn&{6S;y0v7 L:!\S5S1K '_ɦw- cKPE ;dk*G@½1r^$.=Qsyt.%M-M {%ՈY_);%3؏~*J?w9FEhĒwgb\{,QB9 -m>[ʋ`[ hfs!֓$!*{;?2ycBEhRŃJG͹^hlPw@Y UBCba IP0h= OҳU ͇شu*gX$$q 7Cg@ +*%}E}uljfBc㒗 + gSYb4ld+?aFдb RԏFC7OU 6*rp>KbK!%?_;g_omuh{>țb0[/HB2A ['s0}W]9s#{H|d0{֌gdf$%F*9 >8,MW[Z`'4ev@uhZP<:@8D_Eȟx$c!A<2-IQlzE1Е8ƦqTiOOiEPЮ䞷rX?Z3r*$oӢfc*_d0>BIP\)Mke^.2(0h н5kuEf$dzO1"Z0Tg+Y+j֬ -MHw%:HViȴ.eG[ kUHy{xwb ~$[FiLƚX7iD!a48ʈd`_yJÝh߁Q4mzWϞU!g7:J5-3KL;@8D 0j!ބ[T+8;:Eg+A:9. 55ЏFbŊ;wͿ={/³>;qD; #;UhƦ`ڷa#x0`dGDz1Ƞs&nB͍iSN/^֮]{͏.\8b޽{tn\9[^9|Z۩&$$Knz \x5xMk Ku-}l-1lW/ Ҵ577s竾U//{*m Il!=;CXXʞB E#AKKtxXдfY~z3n#29ڀ48{lW-[!DvZ}}I7ژJc"ȋԖ 8,%'-24Z)ADi KgV'^Q@~tҥKuoFcv7'1 \fLFa9}pFOވj`Y27Ѵp3n;P*f2 IDAT_c36M,>"`_BezF(gd0v.y LV_QrNgf|/RWN:hjjjN<ٿ eލѬ4WKNsnazx*75VYۈIyAxСwD;kb%=VZY^TN<m, !Wڄٟjjjjj~S/~M޽{ؽ{]by)aD܇ڈĂf#yc**!l#MUӰHq^Ls :ZgW9 PE!͉}mÝ̿0"sw2\`BU NXܮQ 3f(++[lYHHHPP3<`QJJǽ |:4<P宁LZ'xZqa*%ʪmȴo6揗c 'jU2^x "w%] %~zZ2"?d N/'&MqΓ#M*`@*a N{ѠܜvºP>qlLl400yږVX4r!wR|6l",4T0-34mn69!䃶r2k|[8cQaE$DK9>Xc jU-v&gͪ3̡nGrg4 "!+/vsd=?ۋX gxPgUyVr"W1f n&3{˦(B urs:QLNLf_pOYEl.U￱=|)Dm:9U%Q?> .9{Y;Kvo972!FxK6S5q9YYswΐP/#2!}IdDه9ּr5@)9&e)ɌN',n:Q $RQZd^IxT }I]J[f rhIb[8VFLfFE(|0Қ&4CEOJ;픯#=O~;Y¹>9}`8xO@R$ƙ3tx~w|:4?K iS\Y63?WfC)8NF2"!>ꊇLjn[V?(mj#p<f2CS59癢˓&ϪpUay>8y<[4U*$HK&|:0)ynlBe<) nu①rUC` ;r :'2yM:R[ƑΦ U`9z{4a2t=J]KIy~aÝy 68]SY2SiZI83{0o#s4&GDO Ϋky"*3:G^;BS$ dž4:5Ge C%?!Oiâ)K]ҳIQ١Yr H 9r iXOLVC=PAglK㜨? _#\C%ћ<}㽭0"u>/Rge"Kֳ lLfGɽ@"sX*>Lh V}?_G؂oA/T8cU,W.h5V / TnIycU _m EUO'1Cdž\R&YXy Tk}a= +0x*؄>p+9C|IAE `xd0  _V,] |^rd#-O\UA~X^Lu[FSFw߉W$ Dftig\"Map cmE{l h' wVYxh+X6>eÐ _rN7Nd/{$ͨ $e)0 t[Ϋo𰛖~Aol\i&&gC:W~ah$haGe/P{/223mߖj(:3opձ0k\l\Rb^AROr_RҡaX]Ħ DNq#`FEK5Lc vZ<(Bȼd]EY]QCo`>z`#L+Lx9$s@s ϓ\ll?FZ=?U$x{XitçdU;i<$*ڙވbj+IC{Q'c-7A$Mʃ$=`oGP< . 9ޓ+Ht\au6PjyvLJo.Ba#"~]s>k 8?N]p?ML<$YDjH+$,#Old-$Z~!D `LoFÑԲV8Ipo;![%~]Mk:Do`٧%eȒ?e)c[H D{5;1kh:?~Md~_Khw:S뭭k-J8rRVNlN\&Mp?1-zKo|'/%-!, k0˼̴!Cliv yRsyp8.NekcCo ,}w3L$g1輋,H9 Bz8n, :KÈŀ W<4Wpv}W!D c@gvq?8?7fWJ $YaMs|j ]6S/IÙΤ! ~k+H*JZͮBU/bD%LEDo&aD7 75GGH>JL,6\&;)ytbmäB'7bvwc@'zϫU>Ւ|ݘ91~iR&9{S%ΗVHnG ؟ԡ? D--EyuQ'9Gw۝bhJ<>JI穢G4 o|,NULKTVVLvW\iiqx"),Lh7ȭtqˇ;^P0}|=Klu4y*ʤ&W먛'/M5laoFEtz-5R*'z 0ޯY} x#B]fm!nrm1*\A,VϬM5elį MՑa#~(PDour &&jl<linQSqAC$6E^,^#/[TZkX, jMKl%Vf~*,)w[JJ٥eyfhcԯrұװjq03Oy]y\VRS$};[T("1SDWvWP dR\ǚ{`rKq4G\燅eRֻv**,#m-OdH w'jסTJ'p8|_׎k/N =`$*j/W;&we~ӟY!QC9bGbK79=6ݍ$\[3įHw޹ i*#t-' gpO"n\]еslZD5'6Pqܜ@Z)ՑSr}B` ›t _{<LˬuR)6Do1kΕղ<,!-,pwc@_DfCC*;4\QPɮsdQ\@"УSZ:Oeyl,b<^>At{ԹS2>+VV*Q_ffoΞe&l/ff]:E7Ct}j--Ee&x:4-٥7"Gk43s+[̑d]@'x{.p+5)!AY-)0qꇟ '/qLÑɺ O WB37Y<96 NtW½aW9/_frOӖOj-`ݽ inI*]dٗ|gǫE#qo/Mr&27>jh9v]- +KfK;q٣F/A5OXu3oPVF>2bxYbc],Q-6nYŖRˈ@l-z#Nq)vqꇤn:!ɏi}"7FVvGwfQ-t8@rEי:v%| ([NWBN#-P ^#~t '(^,e]x;Qobo9Pld[ke3KMCCձ.>Tv'ф"@/o&7{}*D kt嗯w۝z)B{! ݡId^H&`\o} y53yFvl h0Y @9u$^!jve'9TFO쳞d_cO]WW#!gpRZJ+I;dQDXBz+čmK84!M-,eKpoĆK} M ir=+)2`ʌ l/"gR|C:KE wl}:58V\biFaY*ěŁM485wsFf;KI,a'HPO:78m!Xgd]%U$_[0,n0{C,eaBz!II~6al,FT@Ӈ3Ḵ?kcCo":ɥ$_#ڋs`GDz*kG|Oj%" %2˙{!vkE,'Be其ICbÚtu=/`rOiޟNO%֞Q:Uۑ)Y_Er52-1:Oi/ufil ~X71םl9K%V3uQD@ B댼U˕dʇƂBօsBJS̯Y8gkX eVs-$?-6, &ĵ48Bڳ؇ȻزJ\Fz1#δpg3Oj (d&/j^εLÛh )eKCzTQAl荤_&8źJ֟aq?7vb|;kcCoGxD4VfX9g*hRPq&_K|z/]#؜4Q ^#WCωcKx$g 9-兀xmX<q8aJ@[w"ZⳭ +)cOwkU%U*h3Zd( O <~ɗ'}Hًq8,vL S?fo;)%ֆGjo+ *ɞS:% Ҕw{p1x1ҫ tZWl̶wSd^VW%!ld>+F^j YֆǓ|U8ݘRJtiV tσ*eO؉o)~2_Tp* gnKShL #ӿ`b{N[i;nֆFτwVw0e՞ U#z$7@m)`,Ʀ9@Z'߈,F\Cg wvU&\!v _aޜ,;-Y&64zC )ΏO>ѣfrsk+vՑA{{^"|lUAbM<]nqV8]'ju;u$Ma<ܙZ/d؉bZ2;7!52$EPz?+**QPݧynŴ$adLRp y,:A0BgHqqw0¦.t_w+ww"D 5f8 mw;Ɛsr5" (;uQQQ1eʔ˗Ϛ5kĉL |ώ,0p `]=k})D˲Жs|Uo-k#X`j OCnǓTh1Π8X˂XqWgNe#YEM':Dbĕ Ft^3f̱cǼ_ EcM$ wỶhʘwbҋe8 @RV$ZtYU챺)U9 &L*Z* C[Q0&y.PhG Sd)f]zd+p˝VP0޽}{FݖDwin~˧ʎX_[NI/aZns@ ɰzhY];]&z1x쾌] <,)⶙$+[̚2CQǫk׮xzz^zզ꛾u-KTldoObd >L2GSrc4%!Xܝ#><"&?f\ JgA'پVvNL?/+N\TTtڻ$M ^:MeCXvQ\9EFR| JnwQH5~Wf{gGnx1p)ȏ?={5|pT%+# Wz{.XY>FΌq CN{2Xr*˾a cb/b+/r3YQ.(LNN.,,AAA֭s\eA:} 6GIfvU NW_`+'CbtXhbCx63t!7D%O8ɏ6AW˴S fbi`1k4HBLhodv;"Ԏ՞PЈvװu}8HđZLC=:=kI{rS qp}zܧZW+X9&i1k$Z#t](ѳߎGXv05rvdӽL}㱲" NsT8ϙؓoO YXh# Z\۝@OʈORGj)Z#3\ /d6Y4GrY1J:k"{]Ʀq[pp8Zj-ZLao=Coc$MæP &dj4$?\VǂpSt{XndS+.5k bS[LK艹F=,onk_[xNn':Sjwqc8r _]sp㊰}ysС>,bw󖅈 ^a5eb5a,dT N$:#IU*aa%4HP.T'> ZxS ]YR8W[Egwd݈f5$X@lOP45DvMWFf9Ywok]z &|L.ՋnAWate_^B4k;z#{Y~ ?w W[3q uTd5+퍯vz͞6̃*Ld)5Gkb5ap/w ؐ+`Ө.k7$'IʧFů v)v%!h*v8d[A}s$?-tzҮSZGG͔Dk53rU#uh!:fww":ѣNv&Yl.ϋgގr}ʻY2>tr1)J~F8~z#ods6)mr/6v,!.;lQ)Sv'U l˃ɝmOx'# O2yFvf &mfuy(&'D!>[o;Ӄ""C Du T2%i>Ȟ<$| Cb1m_? hh ajzsG6IL=ʨI*ES-g&Pc6f?s>ss1I}xS޹t+ߴ$Ũ]Nӝ%#τVf@GJd"{x{m :z2q69/#3@7;=oΆRi:@[kC6Ntw"z@`'FoKV*kQw"!Z.aY}IҘ%nۡz7u3:=Z\aWi`Mi Q=pH+9$9n罳pE87U~=G^"l?F){{O궤’A*NOJ$GF6OdpnN awjaW}\ gѵ*T(")Ix{Yx.Ź%Lo 52wQFX-Y؟I=5Օ荤_eQ&~ď%)pF[E?HWqlԮaU|];g8x>Dft{.鍜R*'v8󆷎%TÃfg..rzRv)ۑ1SWٙϢl3ӏ(n722YDF`3ԾRXpi>M3mdEld7Ȍ@x? k2rJIAzًQk6J4K+Kcm@Cܙ#6=e%~;D2YNp=:% IjvN56JnʌDnp;@C4Io`l")AG,gw1=mƊy?Jͳ~فDJfؓO86?IPC4-u81MEtT`Wa$Wɸ X4ȹ^BA-Ep׋pb) L,aw ]Ѵvu屼g9Rv3Gޚ4iu7û13twB{CS?64hv)?Q8[^j3E_obI>vBASHx؍G~S!ZVj>f hs<=X7>C[pz#N#ńtS?e9KR])|^dU5c(̧Ywt t@Ir86._o'|,mBVa;Y|?I"ńů{ 'ծFf3*mOUX=JhFgMnKZ AdQvv5B(aNH{hT 7] "Ցpw)"wMƻ5%#?vPƹ^aIfn8NݝY ÉkS0M 2 yp9"T窅J~ }aNN?欅ĵRC<0.@LX#c:֑zgC36EF ZĨd|DVO`ɽD c>4A~*{E7D!؝hRfYFdwL-2X *#!bN 8VCv$EYVVr'W2m]fGmyĢ],<H'_"˕fJٮaݷe/NVގ'6>Q wE !hY6dC!k!Ba !Ba !pK}3g\x?IԮf> !??7ѣGAAA~~߫]@NN֭[{uѸjժU[h`0޽ʕ+ӷ~&&fNRd||gرǨ/ܹ0TQQqС+Vdee5W_}G555Vի:wܻ[ZZЩS'?ƿݺu=<Y9rٳU+YMMԩS'Mv!7>}z֬Y&iǎ<L&SUUUDDDUUf\\ܟ' O~r}Zׯ_{uVUU? S}_xg̙soZ Sw_ؾ}{߾}zmUe4y߿o|I˿_~Æ 7lk5A͏gyf˖->ETV7n\vSǃ>hj:C ݻw?d2f͚uaz֭ͳܜ7o֭[[ s}!11vvuF s}ԩSG/\`˫9w\@@fQQpé8p`tMoojɾ}ƏߥK !//̙3C 裏RRRjkkծ^~rssΝ{5 %%eܹjՈcǎr*c!RN/QQQO>9sKwҥ)Yooo(--={ٲ&Zq~7sL&QQQdqŋ/?^B~믿7ƍ7z_NlڴiǎFZrI3?JJJ:t`URRb=/(uK.3}AAAbbbt׮]?#5_~n{yyY͏>㰰{LB ÿ~ZBnV^^OgoE{g}Y5k䘜rfUQ/XÙ{7!!a„ ZZZZUU*e_}֭`,M~[A~;wѣ[lio|뼽ufٷo}[ł y䑴E%$$;jWƪF'-K+9oj4{]t*eիGei[?;#G]Y+zrsssss=|ۆ Ԯ6_07.//﫯6mZ7lvQ񩬬t=zPȾ`=UV-Y?mTnft:SGuuF3gV3w*2~1 0!5f̘ׯ[nt!CXŕ+Wvj裏8ƍwE .}*Ӑ 8\r0Re_5jÁt(ݻY.\߿Ϟ=)g!s+ܥKTnfsԮ^ǎ}ѣGw}ѣG. `eeeAAA͛vQ|v?뫪:vXYYeg(I;Un}i'UL{;v8pEKiye4۷qF?-^O>:t({jrk{UV%$$41 ˗/Oy_cƌQ(zK/QUUҒCk֬ 4hЯ~+ٲeKfffRRR׮]gΜy[F7}7۷o>|xvvܹs[qT8{{ϟ??((Y{;h6mڔgϞ9s7..|ԮXbE׮]۵kWWW??rʰa4hPnnoK/ud2nyC!3s!NKC!-$?BBC!-$?BQ?d}!VR:ׁ/|O^oJf#oFp7V?xl5qRy~ŰN6FB"N7CW}"k+ \_q`m/W΀.5EPdFzGmэGPrx2~Up;}"؃}#(GPaEpF79;=W,ۈw5VWf:D`z#5__25OԮȁjkkccc.!._\YY|r[xu53:Q~<}0`@``ovQg0=jr.\EB`04Fvss*\kT }Pms üufٷo}@yvyOZuy湻;Qr[iQ[[kܹ%0FCze>Fz>bk6p@Oxxx\vaEYhhɺ(_y 4oے%KS=Y6͌F{/1ǧrSCzʕ>Fz>:Q3떛:nȐ!* 999 .oz)1裏>Rf;vK,7/\pwXCר6:D?:v裏=z=vQe]޽^mW߿رcO81f?ϊ+.!\k >:?zK/QUU2g+r|O?4??g/i>*L2= ,زeZŕ+WV^=|𢢢A%?qT+?BN!Ba !Ba !Ba !Ba !Ba !Ba !Ba !BaD8=ֺX IENDB`matlab2tikz-0.4.4/src/000077500000000000000000000000001226131721500145325ustar00rootroot00000000000000matlab2tikz-0.4.4/src/matlab2tikz.m000066400000000000000000006316731226131721500171540ustar00rootroot00000000000000function matlab2tikz(varargin) %MATLAB2TIKZ Save figure in native LaTeX (TikZ/Pgfplots). % MATLAB2TIKZ() saves the current figure as LaTeX file. % MATLAB2TIKZ comes with several options that can be combined at will. % % MATLAB2TIKZ(FILENAME,...) or MATLAB2TIKZ('filename',FILENAME,...) % stores the LaTeX code in FILENAME. % % MATLAB2TIKZ('filehandle',FILEHANDLE,...) stores the LaTeX code in the file % referenced by FILEHANDLE. (default: []) % % MATLAB2TIKZ('figurehandle',FIGUREHANDLE,...) explicitly specifies the % handle of the figure that is to be stored. (default: gcf) % % MATLAB2TIKZ('colormap',DOUBLE,...) explicitly specifies the colormap to be % used. (default: current color map) % % MATLAB2TIKZ('strict',BOOL,...) tells MATLAB2TIKZ to adhere to MATLAB(R) % conventions wherever there is room for relaxation. (default: false) % % MATLAB2TIKZ('showInfo',BOOL,...) turns informational output on or off. % (default: true) % % MATLAB2TIKZ('showWarning',BOOL,...) turns warnings on or off. % (default: true) % % MATLAB2TIKZ('imagesAsPng',BOOL,...) stores MATLAB(R) images as (lossless) % PNG files. This is more efficient than storing the image color data as TikZ % matrix. (default: true) % % MATLAB2TIKZ('relativePngPath',CHAR, ...) tells MATLAB2TIKZ to use the given % path to follow the PNG file. If LaTeX source and PNG file will reside in % the same directory, this can be set to '.'. (default: []) % % MATLAB2TIKZ('height',CHAR,...) sets the height of the image. This can be any % LaTeX-compatible length, e.g., '3in' or '5cm' or '0.5\textwidth'. % If unspecified, MATLAB2TIKZ tries to make a reasonable guess. % % MATLAB2TIKZ('width',CHAR,...) sets the width of the image. % If unspecified, MATLAB2TIKZ tries to make a reasonable guess. % % MATLAB2TIKZ('extraCode',CHAR or CELLCHAR,...) % explicitly adds extra code at the beginning of the output file. % (default: []) % % MATLAB2TIKZ('extraAxisOptions',CHAR or CELLCHAR,...) explicitly adds extra % options to the Pgfplots axis environment. (default: []) % % MATLAB2TIKZ('extraTikzpictureOptions',CHAR or CELLCHAR,...) % explicitly adds extra options to the tikzpicture environment. (default: []) % % MATLAB2TIKZ('encoding',CHAR,...) sets the encoding of the output file. % % MATLAB2TIKZ('floatFormat',CHAR,...) sets the format used for float values. % You can use this to decrease the file size. (default: '%.15g') % % MATLAB2TIKZ('maxChunkLength',INT,...) sets maximum number of data points % per \addplot for line plots (default: 4000). % % MATLAB2TIKZ('parseStrings',BOOL,...) determines whether title, axes labels % and the like are parsed into LaTeX by MATLAB2TIKZ's parser. % If you want greater flexibility, set this to false and use straight LaTeX % for your labels. (default: true) % % MATLAB2TIKZ('parseStringsAsMath',BOOL,...) determines whether to use TeX's % math mode for more characters (such as operators and figures). % (default: false) % % MATLAB2TIKZ('showHiddenStrings',BOOL,...) determines whether to show strings % whose were deliberately hidden. This is usually unnecessary, but can come % in handy for unusual plot types (e.g., polar plots). % (default: false) % % MATLAB2TIKZ('interpretTickLabelsAsTex',BOOL,...) determines whether to % interpret tick labels as TeX. MATLAB(R) doesn't do that by default. % (default: false) % % MATLAB2TIKZ('tikzFileComment',CHAR,...) adds a custom comment to the header % of the output file. % % MATLAB2TIKZ('automaticLabels',BOOL,...) determines whether to automatically % add labels to plots (where applicable) which make it possible to refer % to them using \ref{...} (e.g., in the caption of a figure). % (default: false) % % MATLAB2TIKZ('standalone',BOOL,...) determines whether to produce % a standalone compilable LaTeX file. Setting this to true may be useful for % taking a peek at what the figure will look like. % (default: false) % % MATLAB2TIKZ('checkForUpdates',BOOL,...) determines whether to automatically % check for updates of matlab2tikz. % (default: true) % % Example % x = -pi:pi/10:pi; % y = tan(sin(x)) - sin(tan(x)); % plot(x,y,'--rs'); % matlab2tikz('myfile.tex'); % % Copyright (c) 2008--2013, Nico Schlömer % All rights reserved. % % Redistribution and use in source and binary forms, with or without % modification, are permitted provided that the following conditions are % met: % % * Redistributions of source code must retain the above copyright % notice, this list of conditions and the following disclaimer. % * Redistributions in binary form must reproduce the above copyright % notice, this list of conditions and the following disclaimer in % the documentation and/or other materials provided with the distribution % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % Note: % This program is originally based on Paul Wagenaars' Matfig2PGF which itself % uses pure PGF as output format , see % % http://www.mathworks.com/matlabcentral/fileexchange/12962 % % In an attempt to simplify and extend things, the idea for matlab2tikz has % emerged. The goal is to provide the user with a clean interface between the % very handy figure creation in MATLAB and the powerful means that TikZ with % Pgfplots has to offer. % % ========================================================================= % Check if we are in MATLAB or Octave. [m2t.env, m2t.envVersion] = getEnvironment(); minimalVersion = struct('MATLAB', struct('name','2008b', 'num',[7 7]), ... 'Octave', struct('name','3.4.0', 'num',[3 4 0])); checkDeprecatedEnvironment(m2t, minimalVersion); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - m2t.cmdOpts = []; m2t.currentHandles = []; % For hgtransform groups. m2t.transform = []; m2t.name = 'matlab2tikz'; m2t.version = '0.4.4'; m2t.author = 'Nico Schlömer'; m2t.authorEmail = 'nico.schloemer@gmail.com'; m2t.years = '2008--2013'; m2t.website = 'http://www.mathworks.com/matlabcentral/fileexchange/22022-matlab2tikz'; VCID = VersionControlIdentifier(); m2t.versionFull = strtrim(sprintf('v%s %s', m2t.version, VCID)); m2t.tol = 1.0e-15; % global round-off tolerance; % used, for example, in equality test for doubles m2t.relativePngPath = []; % The following color RGB-values which will need to be defined. % 'extraRgbColorNames' contains their designated names, 'extraRgbColorSpecs' % their specifications. m2t.extraRgbColorSpecs = cell(0); m2t.extraRgbColorNames = cell(0); % the actual contents of the TikZ file go here m2t.content = struct('name', [], ... 'comment', [], ... 'options', {cell(0,2)}, ... 'content', {cell(0)}, ... 'children', {cell(0)} ... ); m2t.preamble = sprintf(['\\usepackage{pgfplots}\n', ... '\\pgfplotsset{compat=newest}\n', ... '\\usetikzlibrary{plotmarks}\n', ... '\\usepackage{amsmath}\n']); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % scan the options ipp = matlab2tikzInputParser; ipp = ipp.addOptional(ipp, 'filename', [], @(x) filenameValidation(x,ipp)); ipp = ipp.addOptional(ipp, 'filehandle', [], @filehandleValidation); ipp = ipp.addParamValue(ipp, 'figurehandle', get(0,'CurrentFigure'), @ishandle); ipp = ipp.addParamValue(ipp, 'colormap', [], @isnumeric); ipp = ipp.addParamValue(ipp, 'strict', false, @islogical); ipp = ipp.addParamValue(ipp, 'showInfo', true, @islogical); ipp = ipp.addParamValue(ipp, 'showWarnings', true, @islogical); ipp = ipp.addParamValue(ipp, 'checkForUpdates', true, @islogical); ipp = ipp.addParamValue(ipp, 'encoding' , '', @ischar); ipp = ipp.addParamValue(ipp, 'standalone', false, @islogical); ipp = ipp.addParamValue(ipp, 'tikzFileComment', '', @ischar); ipp = ipp.addParamValue(ipp, 'extraCode', {}, @isCellOrChar); ipp = ipp.addParamValue(ipp, 'extraAxisOptions', {}, @isCellOrChar); ipp = ipp.addParamValue(ipp, 'extraTikzpictureOptions', {}, @isCellOrChar); ipp = ipp.addParamValue(ipp, 'floatFormat', '%.15g', @ischar); ipp = ipp.addParamValue(ipp, 'automaticLabels', false, @islogical); ipp = ipp.addParamValue(ipp, 'showHiddenStrings', false, @islogical); ipp = ipp.addParamValue(ipp, 'height', [], @ischar); ipp = ipp.addParamValue(ipp, 'width' , [], @ischar); % Whether to save images in PNG format or to natively draw filled squares % using TikZ itself. ipp = ipp.addParamValue(ipp, 'imagesAsPng', true, @islogical); ipp = ipp.addParamValue(ipp, 'relativePngPath', [], @ischar); % Maximum chunk length. % TeX parses files line by line with a buffer of size buf_size. If the % plot has too many data points, pdfTeX's buffer size may be exceeded. % As a work-around, the plot is split into several smaller plots, and this % function does the job. % % What is a "large" array? % TeX parser buffer is buf_size=200000 char on Mac TeXLive, let's say % 100000 to be on the safe side. % 1 point is represented by 25 characters (estimation): 2 coordinates (10 % char), 2 brackets, commma and white space, + 1 extra char. % That gives a magic arbitrary number of 4000 data points per array. ipp = ipp.addParamValue(ipp, 'maxChunkLength', 4000, @isnumeric); % By default strings like axis labels are parsed to match the appearance of % strings as closely as possible to that generated by MATLAB. % If the user wants to have particular strings in the matlab2tikz output that % can't be generated in MATLAB, they can disable string parsing. In that case % all strings are piped literally to the LaTeX output. ipp = ipp.addParamValue(ipp, 'parseStrings', true, @islogical); % In addition to regular string parsing, an additional stage can be enabled % which uses TeX's math mode for more characters like figures and operators. ipp = ipp.addParamValue(ipp, 'parseStringsAsMath', false, @islogical); % As opposed to titles, axis labels and such, MATLAB(R) does not interpret tick % labels as TeX. matlab2tikz retains this behavior, but if it is desired to % interpret the tick labels as TeX, set this option to true. ipp = ipp.addParamValue(ipp, 'interpretTickLabelsAsTex', false, @islogical); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % deprecated parameters (will auto-generate warnings upon parse) %ipp.deprecateParam(ipp,'mathmode',{'parseStrings','parseStringsAsMath'}); % Finally parse all the elements. ipp = ipp.parse(ipp, varargin{:}); m2t.cmdOpts = ipp; % store the input parser back into the m2t data struct % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % inform users of potentially dangerous options if m2t.cmdOpts.Results.parseStringsAsMath userInfo(m2t, ['\n==========================================================================\n', ... 'You are using the parameter ''parseStringsAsMath''.\n', ... 'This may produce undesirable string output. For full control over output\n', ... 'strings please set the parameter ''parseStrings'' to false.\n', ... '==========================================================================']); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % shortcut m2t.ff = m2t.cmdOpts.Results.floatFormat; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % add global elements if isempty(m2t.cmdOpts.Results.figurehandle) error('matlab2tikz:figureNotFound','MATLAB figure not found.'); end m2t.currentHandles.gcf = m2t.cmdOpts.Results.figurehandle; if m2t.cmdOpts.Results.colormap m2t.currentHandles.colormap = m2t.cmdOpts.Results.colormap; else m2t.currentHandles.colormap = get(m2t.currentHandles.gcf, 'colormap'); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % handle output file handle/file name if ~isempty(m2t.cmdOpts.Results.filehandle) fid = m2t.cmdOpts.Results.filehandle; fileWasOpen = true; if ~isempty(m2t.cmdOpts.Results.filename) userWarning(m2t, ... 'File handle AND file name for output given. File handle used, file name discarded.') end else fileWasOpen = false; % set filename if ~isempty(m2t.cmdOpts.Results.filename) filename = m2t.cmdOpts.Results.filename; else filename = uiputfile({'*.tex'; '*.*'}, ... 'Save File'); end % open the file for writing switch m2t.env case 'MATLAB' fid = fopen(filename, ... 'w', ... 'native', ... m2t.cmdOpts.Results.encoding ... ); case 'Octave' fid = fopen(filename, 'w'); otherwise errorUnknownEnvironment(); end if fid == -1 error('matlab2tikz:fileOpenError', ... 'Unable to open file ''%s'' for writing.', ... filename); end end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - m2t.tikzFileName = fopen(fid); if m2t.cmdOpts.Results.automaticLabels m2t.automaticLabelIndex = 0; end % By default, reference the PNG (if required) from the TikZ file % as the file path of the TikZ file itself. This works if the MATLAB script % is executed in the same folder where the TeX file sits. if isempty(m2t.cmdOpts.Results.relativePngPath) m2t.relativePngPath = fileparts(m2t.tikzFileName); else m2t.relativePngPath = m2t.cmdOpts.Results.relativePngPath; end userInfo(m2t, ['(To disable info messages, pass [''showInfo'', false] to matlab2tikz.)\n', ... '(For all other options, type ''help matlab2tikz''.)\n']); userInfo(m2t, '\nThis is %s %s.\n', m2t.name, m2t.versionFull) % Conditionally check for a new matlab2tikz version outside version control if m2t.cmdOpts.Results.checkForUpdates && isempty(VCID) updater(m2t.name, ... m2t.website, ... m2t.version, ... m2t.cmdOpts.Results.showInfo, ... m2t.env) end % print some version info to the screen versionInfo = ['The latest updates can be retrieved from\n' ,... ' %s\n' ,... 'where you can also make suggestions and rate %s.\n' ,... 'For usage instructions, bug reports, the latest ' ,... 'development versions and more, see\n' ,... ' https://github.com/nschloe/matlab2tikz,\n' ,... ' https://github.com/nschloe/matlab2tikz/wiki,\n' ,... ' https://github.com/nschloe/matlab2tikz/issues.\n' ]; userInfo(m2t, versionInfo, m2t.website, m2t.name); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Save the figure as pgf to file -- here's where the work happens saveToFile(m2t, fid, fileWasOpen); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % ========================================================================= function l = filenameValidation(x, p) % is the filename argument NOT another keyword? l = ischar(x) && ~any(strcmp(x,p.Parameters)); end % ========================================================================= function l = filehandleValidation(x) % is the filehandle the handle to an opened file? l = isnumeric(x) && any(x==fopen('all')); end % ========================================================================= function l = isCellOrChar(x) l = iscell(x) || ischar(x); end % ========================================================================= function m2t = saveToFile(m2t, fid, fileWasOpen) % Save the figure as TikZ to a file. % All other routines are called from here. % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % enter plot recursion -- % It is important to turn hidden handles on, as visible lines (such as the % axes in polar plots, for example), are otherwise hidden from their % parental handles (and can hence not be discovered by matlab2tikz). % With ShowHiddenHandles 'on', there is no escape. :) set(0, 'ShowHiddenHandles', 'on'); % get all axes handles fh = m2t.currentHandles.gcf; axesHandles = findobj(fh, 'type', 'axes'); tagKeyword = switchMatOct(m2t, 'Tag', 'tag'); if ~isempty(axesHandles) % Find all legend handles. This is MATLAB-only. legendHandleIdx = strcmp(get(axesHandles, tagKeyword), 'legend'); m2t.legendHandles = axesHandles(legendHandleIdx); % Remove all legend handles as they are treated separately. axesHandles = axesHandles(~legendHandleIdx); end colorbarKeyword = switchMatOct(m2t, 'Colorbar', 'colorbar'); if ~isempty(axesHandles) % Find all colorbar handles. This is MATLAB-only. cbarHandleIdx = strcmp(get(axesHandles, tagKeyword), colorbarKeyword); m2t.cbarHandles = axesHandles(cbarHandleIdx); % Remove all legend handles as they are treated separately. axesHandles = axesHandles(~cbarHandleIdx); else m2t.cbarHandles = []; end % Turn around the handles vector to make sure that plots that appeared % first also appear first in the vector. This has effects on the alignment % and the order in which the plots appear in the final TikZ file. % In fact, this is not really important but makes things more 'natural'. axesHandles = axesHandles(end:-1:1); % find alignments [relevantAxesHandles, alignmentOptions, IX] = alignSubPlots(m2t, axesHandles); m2t.axesContainers = {}; for ix = IX(:)' m2t = drawAxes(m2t, relevantAxesHandles(ix), alignmentOptions(ix)); end % Handle color bars. for cbar = m2t.cbarHandles(:)' m2t = handleColorbar(m2t, cbar); end % Add all axes containers to the file contents. for axesContainer = m2t.axesContainers m2t.content = addChildren(m2t.content, axesContainer); end set(0, 'ShowHiddenHandles', 'off'); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % actually print the stuff environment = sprintf('%s %s',m2t.env, m2t.envVersion); m2t.content.comment = sprintf(['This file was created by %s %s running on %s.\n', ... 'Copyright (c) %s, %s <%s>\n', ... 'All rights reserved.\n'], ... m2t.name, m2t.versionFull, environment, ... m2t.years, m2t.author, m2t.authorEmail); if m2t.cmdOpts.Results.showInfo % disable this info if showInfo=false m2t.content.comment = [m2t.content.comment, ... sprintf(['\n',... 'The latest updates can be retrieved from\n', ... ' %s\n', ... 'where you can also make suggestions and rate %s.\n'], ... m2t.website, m2t.name ) ... ]; end % Add custom comment. if ~isempty(m2t.cmdOpts.Results.tikzFileComment) m2t.content.comment = [m2t.content.comment, ... sprintf('\n%s\n', m2t.cmdOpts.Results.tikzFileComment) ]; end m2t.content.name = 'tikzpicture'; % Add custom TikZ options if any given. if ~isempty(m2t.cmdOpts.Results.extraTikzpictureOptions) if ischar(m2t.cmdOpts.Results.extraTikzpictureOptions) m2t.cmdOpts.Results.extraTikzpictureOptions = ... {m2t.cmdOpts.Results.extraTikzpictureOptions}; end for k = 1:length(m2t.cmdOpts.Results.extraTikzpictureOptions) m2t.content.options = ... addToOptions(m2t.content.options, ... m2t.cmdOpts.Results.extraTikzpictureOptions{k}, []); end end % Don't forget to define the colors. if ~isempty(m2t.extraRgbColorNames) m2t.content.colors = sprintf('%%\n%% defining custom colors\n'); for k = 1:length(m2t.extraRgbColorNames) % make sure to append with '%' to avoid spacing woes m2t.content.colors = [m2t.content.colors, ... sprintf(['\\definecolor{%s}{rgb}{', m2t.ff, ',', m2t.ff, ',', m2t.ff,'}%%\n'], ... m2t.extraRgbColorNames{k}', m2t.extraRgbColorSpecs{k})]; end m2t.content.colors = [m2t.content.colors sprintf('%%\n')]; end % Finally print it to the file, if ~isempty(m2t.content.comment) fprintf(fid, '%% %s\n', ... strrep(m2t.content.comment, sprintf('\n'), sprintf('\n%% '))); end if m2t.cmdOpts.Results.standalone fprintf(fid, '\\documentclass[tikz]{standalone}\n%s\n', m2t.preamble); end % Add custom code. if ~isempty(m2t.cmdOpts.Results.extraCode) if ischar(m2t.cmdOpts.Results.extraCode) fprintf(fid, '%s\n', m2t.cmdOpts.Results.extraCode); elseif iscellstr(m2t.cmdOpts.Results.extraCode) for str = m2t.cmdOpts.Results.extraCode(:)' fprintf(fid, '%s\n', str{1}); end else error('matlab2tikz:saveToFile', 'Need str or cellstr.'); end end if m2t.cmdOpts.Results.standalone fprintf(fid, '\\begin{document}\n'); end % printAll() handles the actual figure plotting. printAll(m2t, m2t.content, fid); if m2t.cmdOpts.Results.standalone fprintf(fid, '\n\\end{document}'); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % close the file if necessary if ~fileWasOpen fclose(fid); end end % ========================================================================= function [m2t, pgfEnvironments] = handleAllChildren(m2t, handle) % Draw all children of a graphics object (if they need to be drawn). children = get(handle, 'Children'); % prepare cell array of pgfEnvironments pgfEnvironments = cell(0); % It's important that we go from back to front here, as this is % how MATLAB does it, too. Significant for patch (contour) plots, % and the order of plotting the colored patches. for child = children(end:-1:1)' % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % First of all, check if 'child' is referenced in a legend. % If yes, some plot types may want to add stuff (e.g. 'forget plot'). % Add '\addlegendentry{...}' then after the plot. legendString = []; m2t.currentHandleHasLegend = false; % Check if current handle is referenced in a legend. switch m2t.env case 'MATLAB' if ~isempty(m2t.legendHandles) % Make sure that m2t.legendHandles is a row vector. for legendHandle = m2t.legendHandles(:)' ud = get(legendHandle, 'UserData'); % In Octave, the field name is 'handle'. Well, whatever. % fieldName = switchMatOct(m2t, 'handles', 'handle'); k = find(child == ud.handles); if isempty(k) % Lines of error bar plots are not referenced % directly in legends as an error bars plot contains % two "lines": the data and the deviations. Here, the % legends refer to the specgraph.errorbarseries % handle which is 'Parent' to the line handle. k = find(get(child,'Parent') == ud.handles); end if ~isempty(k) % Legend entry found. Add it to the plot. m2t.currentHandleHasLegend = true; interpreter = get(legendHandle, 'Interpreter'); legendString = ud.lstrings(k); end end end case 'Octave' % Octave associates legends with axes, not with (line) plot. % The variable m2t.gcaHasLegend is set in drawAxes(). m2t.currentHandleHasLegend = ~isempty(m2t.gcaAssociatedLegend); interpreter = get(m2t.gcaAssociatedLegend, 'interpreter'); if isfield(get(child), 'displayname') legendString = get(child, 'displayname'); end otherwise errorUnknownEnvironment(); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - switch get(child, 'Type') % 'axes' environments are treated separately. case 'line' [m2t, str] = drawLine(m2t, child); case 'patch' [m2t, str] = drawPatch(m2t, child); case 'image' [m2t, str] = drawImage(m2t, child); case 'hggroup' [m2t, str] = drawHggroup(m2t, child); case 'hgtransform' % From http://www.mathworks.de/de/help/matlab/ref/hgtransformproperties.html: % Matrix: 4-by-4 matrix % Transformation matrix applied to hgtransform object and its % children. The hgtransform object applies the transformation % matrix to all its children. % More information at http://www.mathworks.de/de/help/matlab/creating_plots/group-objects.html. m2t.transform = get(child, 'Matrix'); [m2t, str] = handleAllChildren(m2t, child); m2t.transform = []; case 'surface' [m2t, str] = drawSurface(m2t, child); case 'text' [m2t, str] = drawText(m2t, child); case 'rectangle' [m2t, str] = drawRectangle(m2t, child); case {'uitoolbar', 'uimenu', 'uicontextmenu', 'uitoggletool',... 'uitogglesplittool', 'uipushtool', 'hgjavacomponent'} % don't to anything for these handles and its children str = []; otherwise error('matlab2tikz:handleAllChildren', ... 'I don''t know how to handle this object: %s\n', ... get(child, 'Type')); end % Add legend after the plot data. % The test for ischar(str) && ~isempty(str) is a workaround for hggroups; % the output might not necessarily be a string, but a cellstr. if ischar(str) && ~isempty(str) ... && m2t.currentHandleHasLegend && ~isempty(legendString) c = prettyPrint(m2t, legendString, interpreter); % We also need a legend alignment option to make multiline % legend entries work. This is added by default in getLegendOpts(). str = [str, ... sprintf('\\addlegendentry{%s};\n\n', join(m2t, c, '\\'))]; %#ok end % append the environment pgfEnvironments{end+1} = str; end end % ========================================================================= function data = applyHgTransform(m2t, data) if ~isempty(m2t.transform) R = m2t.transform(1:3,1:3); t = m2t.transform(1:3,4); n = size(data, 1); data = data * R' ... + kron(ones(n,1), t'); end end % ========================================================================= function m2t = drawAxes(m2t, handle, alignmentOptions) % Input arguments: % handle.................The axes environment handle. % alignmentOptions.......The alignment options as defined in the % function 'alignSubPlots()'. % This argument is optional. % Handle special cases. % MATLAB(R) uses 'Tag', Octave 'tag' for their tags. :/ tagKeyword = switchMatOct(m2t, 'Tag', 'tag'); colorbarKeyword = switchMatOct(m2t, 'Colorbar', 'colorbar'); switch get(handle, tagKeyword) case colorbarKeyword % Handle a colorbar separately. m2t = handleColorbar(m2t, handle); return case 'legend' % Don't handle the legend here, but further below in the 'axis' % environment. % In MATLAB, an axes environment and its corresponding legend are % children of the same figure (siblings), while in Pgfplots, the % \legend (or \addlegendentry) command must appear within the axis % environment. return otherwise % continue as usual end % Initialize empty enviroment. % Use a struct instead of a custom subclass of hgsetget (which would % facilitate writing clean code) as structs are more portable (old MATLAB(R) % versions, GNU Octave). m2t.axesContainers{end+1} = struct('handle', handle, ... 'name', [], ... 'comment', [], ... 'options', {cell(0,2)}, ... 'content', {cell(0)}, ... 'children', {cell(0)}, ... 'stackedBarsPresent', false, ... 'nonbarPlotsPresent', false ... ); % update gca m2t.currentHandles.gca = handle; % This is an ugly workaround for bar plots. % Bar plots need to have several values counted on a per-axes basis, e.g., % the number of bars. Setting m2t.barplotId to [] here makes sure those % values are recomputed in drawBarseries(). m2t.barplotId = []; % Octave: % Check if this axis environment is referenced by a legend. m2t.gcaAssociatedLegend = []; switch m2t.env case 'Octave' if ~isempty(m2t.legendHandles) % Make sure that m2t.legendHandles is a row vector. for lhandle = m2t.legendHandles(:)' ud = get(lhandle, 'UserData'); if any(handle == ud.handle) m2t.gcaAssociatedLegend = lhandle; break; end end end case 'MATLAB' % no action needed otherwise errorUnknownEnvironment(); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % get the axes dimensions dim = getAxesDimensions(handle, ... m2t.cmdOpts.Results.width, ... m2t.cmdOpts.Results.height); % set the width if dim.x.unit(1)=='\' && dim.x.value==1.0 % only return \figurewidth instead of 1.0\figurewidth m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, 'width', dim.x.unit); else if strcmp(dim.x.unit, 'px') % TikZ doesn't know pixels. -- Convert to inches. dpi = get(0, 'ScreenPixelsPerInch'); dim.x.value = dim.x.value / dpi; dim.x.unit = 'in'; end m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, 'width', ... sprintf([m2t.ff, '%s'], dim.x.value, dim.x.unit)); end if dim.y.unit(1)=='\' && dim.y.value==1.0 % only return \figureheight instead of 1.0\figureheight m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, 'height', dim.y.unit); else if strcmp(dim.y.unit, 'px') % TikZ doesn't know pixels. -- Convert to inches. dpi = get(0, 'ScreenPixelsPerInch'); dim.y.value = dim.y.value / dpi; dim.y.unit = 'in'; end m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, 'height', ... sprintf([m2t.ff, '%s'], dim.y.value, dim.y.unit)); end % Add the physical dimension of one unit of length in the coordinate system. % This is used later on to translate lenghts to physical units where % necessary (e.g., in bar plots). m2t.unitlength.x.unit = dim.x.unit; xLim = get(m2t.currentHandles.gca, 'XLim'); m2t.unitlength.x.value = dim.x.value / (xLim(2)-xLim(1)); m2t.unitlength.y.unit = dim.y.unit; yLim = get(m2t.currentHandles.gca, 'YLim'); m2t.unitlength.y.value = dim.y.value / (yLim(2)-yLim(1)); for axis = 'xyz' m2t.([axis 'AxisReversed']) = ... strcmp(get(handle,[upper(axis),'Dir']), 'reverse'); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % In MATLAB, all plots are treated as 3D plots; it's just the view that % makes 2D plots appear like 2D. % Recurse into the children of this environment. Do this here to give the % contained plots the chance to set m2t.currentAxesContain3dData to true. m2t.currentAxesContain3dData = false; [m2t, childrenEnvs] = handleAllChildren(m2t, handle); m2t.axesContainers{end} = addChildren(m2t.axesContainers{end}, childrenEnvs); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if m2t.axesContainers{end}.stackedBarsPresent ... && m2t.axesContainers{end}.nonbarPlotsPresent userWarning(m2t, ['Pgfplots can''t deal with stacked bar plots', ... ' and non-bar plots in one axis environment.', ... ' The LaTeX file will probably not compile.']); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % The rest of this is handling axes options. % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Set view for 3D plots. if m2t.currentAxesContain3dData m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'view', sprintf(['{', m2t.ff, '}{', m2t.ff, '}'], get(handle, 'View'))); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % the following is general MATLAB behavior m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'scale only axis', []); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Get other axis options (ticks, axis color, label,...). % This is set here such that the axis orientation indicator in m2t is set % before -- if ~isVisible(handle) -- the handle's children are called. m2t.axesContainers{end}.options = merge(m2t.axesContainers{end}.options, ... getAxisOptions(m2t, handle, 'x') ... ); m2t.axesContainers{end}.options = merge(m2t.axesContainers{end}.options, ... getAxisOptions(m2t, handle, 'y') ... ); %[m2t, hasXGrid] = getAxisOptions(m2t, handle, 'x'); %[m2t, hasYGrid] = getAxisOptions(m2t, handle, 'y'); if m2t.currentAxesContain3dData %[m2t, hasZGrid] = getAxisOptions(m2t, handle, 'z'); m2t.axesContainers{end}.options = ... merge(m2t.axesContainers{end}.options, ... getAxisOptions(m2t, handle, 'z') ... ); end hasXGrid = false; hasYGrid = false; hasZGrid = false; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if ~isVisible(handle) % Setting hide{x,y} axis also hides the axis labels in Pgfplots whereas % in MATLAB, they may still be visible. Well. m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'hide axis', []); end %if ~isVisible(handle) % % An invisible axes container *can* have visible children, so don't % % immediately bail out here. % children = get(handle, 'Children'); % for child = children(:)' % if isVisible(child) % % If the axes contain something that's visible, add an invisible % % axes pair. % m2t.axesContainers{end}.name = 'axis'; % m2t.axesContainers{end}.options = {m2t.axesContainers{end}.options{:}, ... % 'hide x axis', 'hide y axis'}; % m2t.axesContainers{end}.comment = getTag(handle); % break; % end % end % % recurse into the children of this environment % [m2t, childrenEnvs] = handleAllChildren(m2t, handle); % m2t.axesContainers{end} = addChildren(m2t.axesContainers{end}, childrenEnvs); % return %end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % This used to discriminate between semilog{x,y}axis, loglog, and axis. % Now, the log-scale is handled by the {x,y,z}mode argument, so just go for % axis. m2t.axesContainers{end}.name = 'axis'; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % set alignment options if ~isempty(alignmentOptions.opts) m2t.axesContainers{end}.options = cat(1,m2t.axesContainers{end}.options,... alignmentOptions.opts); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % background color backgroundColor = get(handle, 'Color'); if ~strcmp(backgroundColor, 'none') [m2t, col] = getColor(m2t, handle, backgroundColor, 'patch'); if ~strcmp(col, 'white') m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'axis background/.style', sprintf('{fill=%s}', col)); end end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % title title = get(get(handle, 'Title'), 'String'); if ~isempty(title) titleInterpreter = get(get(handle, 'Title'), 'Interpreter'); title = prettyPrint(m2t, title, titleInterpreter); if length(title) > 1 m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'title style', '{align=center}'); end title = join(m2t, title, '\\[1ex]'); m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'title', sprintf('{%s}', title)); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % axes locations boxOn = strcmp(get(handle, 'box'), 'on'); xloc = get(handle, 'XAxisLocation'); if boxOn if strcmp(xloc, 'bottom') % default; nothing added elseif strcmp(xloc, 'top') m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'axis x line*', 'top'); else error('matlab2tikz:drawAxes', ... 'Illegal axis location ''%s''.', xloc); end else % box off m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'axis x line*', xloc); end yloc = get(handle, 'YAxisLocation'); if boxOn if strcmp(yloc, 'left') % default; nothing added elseif strcmp(yloc, 'right') m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'axis y line*', 'right'); else error('matlab2tikz:drawAxes', ... 'Illegal axis location ''%s''.', yloc); end else % box off m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'axis y line*', yloc); end if m2t.currentAxesContain3dData % There's no such attribute as 'ZAxisLocation'. % Instead, the default seems to be 'left'. if ~boxOn m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'axis z line*', 'left'); end end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % grid line style if hasXGrid || hasYGrid || (exist('hasZGrid','var') && hasZGrid) matlabGridLineStyle = get(handle, 'GridLineStyle'); % Take over the grid line style in any case when in strict mode. % If not, don't add anything in case of default line grid line style % and effectively take Pgfplots' default. defaultMatlabGridLineStyle = ':'; if m2t.cmdOpts.Results.strict ... || ~strcmp(matlabGridLineStyle,defaultMatlabGridLineStyle) gls = translateLineStyle(matlabGridLineStyle); axisGridOpts = {'grid style', sprintf('{%s}', gls)}; m2t.axesContainers{end}.options = cat(1, ... m2t.axesContainers{end}.options,... axisGridOpts); end else % When specifying 'axis on top', the axes stay above all graphs (which is % default MATLAB behavior), but so do the grids (which is not default % behavior). % To date (Dec 12, 2009) Pgfplots is not able to handle those things % separately. % See also http://sourceforge.net/tracker/index.php?func=detail&aid=3510455&group_id=224188&atid=1060657 % As a prelimary compromise, only pull this option if no grid is in use. if m2t.cmdOpts.Results.strict m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'axis on top', []); end end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % See if there are any legends that need to be plotted. % Since the legends are at the same level as axes in the hierarchy, % we can't work out which relates to which using the tree % so we have to do it by looking for a plot inside which the legend sits. % This could be done better with a heuristic of finding % the nearest legend to a plot, which would cope with legends outside % plot boundaries. switch m2t.env case 'MATLAB' legendHandle = legend(handle); if ~isempty(legendHandle) [m2t, key, legendOpts] = getLegendOpts(m2t, legendHandle); m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... key, ... ['{', legendOpts, '}']); end case 'Octave' % TODO: How to uniquely connect a legend with a pair of axes in Octave? axisDims = pos2dims(get(handle,'Position')); %#ok % siblings of this handle: siblings = get(get(handle,'Parent'), 'Children'); % "siblings" always(?) is a column vector. Iterating over the column % with the for statement below wouldn't return the individual vector % elements but the same column vector, resulting in no legends exported. % So let's make sure "siblings" is a row vector by reshaping it: siblings = reshape(siblings, 1, []); for sibling = siblings if sibling && strcmp(get(sibling,'Type'), 'axes') && strcmp(get(sibling,'Tag'), 'legend') legDims = pos2dims(get(sibling, 'Position')); %#ok % TODO The following logic does not work for 3D plots. % => Commented out. % This creates problems though for stacked plots with legends. % if ( legDims.left > axisDims.left ... % && legDims.bottom > axisDims.bottom ... % && legDims.left + legDims.width < axisDims.left + axisDims.width ... % && legDims.bottom + legDims.height < axisDims.bottom + axisDims.height) [m2t, key, legendOpts] = getLegendOpts(m2t, sibling); m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... key, ... ['{', legendOpts, '}']); % end end end otherwise errorUnknownEnvironment(); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % add manually given extra axis options if ~isempty(m2t.cmdOpts.Results.extraAxisOptions) if ischar(m2t.cmdOpts.Results.extraAxisOptions) m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... m2t.cmdOpts.Results.extraAxisOptions, []); elseif iscellstr(m2t.cmdOpts.Results.extraAxisOptions) for k = 1:length(m2t.cmdOpts.Results.extraAxisOptions) m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... m2t.cmdOpts.Results.extraAxisOptions{k}, []); end else error('matlab2tikz:illegalExtraAxisOptions',... 'Illegal extraAxisOptions (need string or cell string).') end end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % ========================================================================= function m2t = handleColorbar(m2t, handle) if isempty(handle) return; end % Find the axes environment that this colorbar belongs to. parentAxesHandle = double(get(handle,'axes')); parentFound = false; for k = 1:length(m2t.axesContainers) if m2t.axesContainers{k}.handle == parentAxesHandle k0 = k; parentFound = true; break; end end if parentFound m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... matlab2pgfplotsColormap(m2t, m2t.currentHandles.colormap), []); % Append cell string. m2t.axesContainers{k0}.options = cat(1,... m2t.axesContainers{k0}.options, ... getColorbarOptions(m2t, handle)); else warning('matlab2tikz:parentAxesOfColorBarNotFound',... 'Could not find parent axes for color bar. Skipping.'); end end % ========================================================================= function tag = getTag(handle) % if a tag is given, use it as comment tag = get(handle, 'tag'); if ~isempty(tag) tag = sprintf('Axis "%s"', tag); else tag = sprintf('Axis at [%.2g %.2f %.2g %.2g]', get(handle, 'position')); end end % ========================================================================= function options = getAxisOptions(m2t, handle, axis) % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if ~strcmpi(axis,'x') && ~strcmpi(axis,'y') && ~strcmpi(axis,'z') error('matlab2tikz:illegalAxisSpecifier',... 'Illegal axis specifier ''%s''.', axis); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - options = {}; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % axis colors color = get(handle, [upper(axis),'Color']); if (any(color)) % color not black [0,0,0] [m2t, col] = getColor(m2t, handle, color, 'patch'); if strcmp(get(handle, 'box'), 'on') % If the axes are arranged as a box, make sure that the individual % axes are drawn as four separate paths. This makes the alignment % at the box corners somewhat less nice, but allows for different % axis styles (e.g., colors). options = addToOptions(options, 'separate axis lines', []); end options = ... addToOptions(options, ... ['every outer ', axis, ' axis line/.append style'], ... ['{', col, '}']); options = ... addToOptions(options, ... ['every ',axis,' tick label/.append style'], ... ['{font=\color{',col,'}}']); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % handle the orientation isAxisReversed = strcmp(get(handle,[upper(axis),'Dir']), 'reverse'); m2t.([axis 'AxisReversed']) = isAxisReversed; if isAxisReversed options = addToOptions(options, ... [axis, ' dir'], 'reverse'); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - isAxisLog = strcmp(get(handle,[upper(axis),'Scale']), 'log'); if isAxisLog options = addToOptions(options, ... [axis,'mode'], 'log'); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % get axis limits limits = get(handle, [upper(axis),'Lim']); options = addToOptions(options, ... [axis,'min'], sprintf(m2t.ff, limits(1))); options = addToOptions(options, ... [axis,'max'], sprintf(m2t.ff, limits(2))); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % get ticks along with the labels [ticks, tickLabels, hasMinorTicks] = getAxisTicks(m2t, handle, axis); % According to http://www.mathworks.com/help/techdoc/ref/axes_props.html, % the number of minor ticks is automatically determined by MATLAB(R) to % fit the size of the axis. Until we know how to extract this number, use % a reasonable default. matlabDefaultNumMinorTicks = 3; if ~isempty(ticks) options = addToOptions(options, ... [axis,'tick'], sprintf('{%s}', ticks)); end if ~isempty(tickLabels) options = addToOptions(options, ... [axis,'ticklabels'], sprintf('{%s}', tickLabels)); end if hasMinorTicks options = addToOptions(options, ... [axis,'minorticks'], 'true'); if m2t.cmdOpts.Results.strict options = ... addToOptions(options, ... sprintf('minor %s tick num', axis), ... sprintf('{%d}', matlabDefaultNumMinorTicks)); end end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % get axis label axisLabel = get(get(handle, [upper(axis),'Label']), 'String'); if ~isempty(axisLabel) axisLabelInterpreter = ... get(get(handle, [upper(axis),'Label']), 'Interpreter'); label = prettyPrint(m2t, axisLabel, axisLabelInterpreter); if length(label) > 1 % If there's more than one cell item, the list % is displayed multi-row in MATLAB(R). % To replicate the same in Pgfplots, one can % use xlabel={first\\second\\third} only if the % alignment or the width of the "label box" % is defined. This is a restriction that comes with % TikZ nodes. options = addToOptions(options, ... [axis, 'label style'], '{align=center}'); end label = join(m2t, label,'\\[1ex]'); %if isVisible(handle) options = addToOptions(options, ... [axis, 'label'], sprintf('{%s}', label)); %else % m2t.axesContainers{end}.options{end+1} = ... % sprintf(['extra description/.code={\n', ... % '\\node[/pgfplots/every axis label,/pgfplots/every axis %s label]{%s};\n', ... % '}'], axis, label); %end end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % get grids hasGrid = false; if strcmp(get(handle, [upper(axis),'Grid']), 'on'); options = addToOptions(options, ... [axis, 'majorgrids'], []); hasGrid = true; end if strcmp(get(handle, [upper(axis),'MinorGrid']), 'on'); options = addToOptions(options, ... [axis, 'minorgrids'], []); hasGrid = true; end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % ========================================================================= function bool = axisIsVisible(axisHandle) if ~isVisible(axisHandle) % An invisible axes container *can* have visible children, so don't % immediately bail out here. children = get(axisHandle, 'Children'); bool = false; for child = children(:)' if isVisible(child) bool = true; return; end end else bool = true; end end % ========================================================================= function [m2t, str] = drawLine(m2t, handle, yDeviation) % Returns the code for drawing a regular line. % This is an extremely common operation and takes place in most of the % not too fancy plots. % % This function handles error bars, too. str = []; if ~isVisible(handle) return end % Don't allow lines is there's already stacked bars. % This could be somewhat controversial: Why not remove the stacked bars then? % Anyways, with stacked bar plots, lines are typically base lines and such, % so nothing of great interest. Throw those out for now. if m2t.axesContainers{end}.stackedBarsPresent return end % This is for a quirky workaround for stacked bar plots. m2t.axesContainers{end}.nonbarPlotsPresent = true; lineStyle = get(handle, 'LineStyle'); lineWidth = get(handle, 'LineWidth'); marker = get(handle, 'Marker'); % Get draw options. color = get(handle, 'Color'); [m2t, xcolor] = getColor(m2t, handle, color, 'patch'); lineOptions = getLineOptions(m2t, lineStyle, lineWidth); [m2t, markerOptions] = getMarkerOptions(m2t, handle); drawOptions = [{sprintf('color=%s', xcolor)}, ... % color lineOptions, ... markerOptions]; % Check for "special" lines, e.g.: if strcmp(get(handle, 'Tag'), 'zplane_unitcircle') % Draw unit circle and axes. % TODO Don't hardcode "10". opts = join(m2t, drawOptions, ','); str = [sprintf('\\draw[%s] (axis cs:0,0) circle[radius=1];\n', opts),... sprintf('\\draw[%s] (axis cs:-10,0)--(axis cs:10,0);\n', opts), ... sprintf('\\draw[%s] (axis cs:0,-10)--(axis cs:0,10);\n', opts)]; return end hasLines = ~strcmp(lineStyle,'none') && lineWidth>0.0; hasMarkers = ~strcmp(marker,'none'); if ~hasLines && ~hasMarkers return end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Plot the actual line data. % First put them all together in one multiarray. % This also implicitly makes sure that the lengths match. xData = get(handle, 'XData'); yData = get(handle, 'YData'); zData = get(handle, 'ZData'); % We would like to do % data = [xData(:), yData(:), zData(:)], % but Octave fails. Hence this isempty() construction. if isempty(zData) data = [xData(:), yData(:)]; else data = applyHgTransform(m2t, [xData(:), yData(:), zData(:)]); end % check if the *optional* argument 'yDeviation' was given hasDeviations = false; if nargin > 2 data = [data, yDeviation(:,1:2)]; hasDeviations = true; end % Check if any value is infinite/NaN. In that case, add appropriate option. if any(~isfinite(data(:))) m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, 'unbounded coords', 'jump'); end if ~isempty(zData) % Don't try to be smart in parametric 3d plots: Just plot all the data. str = [str, ... sprintf(['\\addplot3 [\n', join(m2t, drawOptions, ',\n'), ']\n']), ... sprintf('table[row sep=crcr] {\n'), ... sprintf([m2t.ff, ' ', m2t.ff, ' ', m2t.ff, '\\\\\n'], data'), ... sprintf('};\n')]; m2t.currentAxesContain3dData = true; else xLim = get(m2t.currentHandles.gca, 'XLim'); yLim = get(m2t.currentHandles.gca, 'YLim'); % split the data into logical chunks dataCell = splitLine(m2t, hasLines, hasMarkers, hasDeviations, data, xLim, yLim); % plot them for k = 1:length(dataCell) % If the line has a legend string, make sure to only include a legend % entry for the *last* occurence of the plot series. % Hence the condition k m2t.tol) lineOpts{end+1} = sprintf('%s', translateLineStyle(lineStyle)); end % Take over the line width in any case when in strict mode. If not, don't add % anything in case of default line width and effectively take Pgfplots' % default. % Also apply the line width if no actual line is there; the markers make use % of this, too. matlabDefaultLineWidth = 0.5; if m2t.cmdOpts.Results.strict ... || ~abs(lineWidth-matlabDefaultLineWidth) <= m2t.tol lineOpts{end+1} = sprintf('line width=%.1fpt', lineWidth); end end % ========================================================================= function [m2t, drawOptions] = getMarkerOptions(m2t, h) % Handles the marker properties of a line (or any other) plot. drawOptions = cell(0); marker = get(h, 'Marker'); if ~strcmp(marker, 'none') markerSize = get(h, 'MarkerSize'); lineStyle = get(h, 'LineStyle'); lineWidth = get(h, 'LineWidth'); [tikzMarkerSize, isDefault] = ... translateMarkerSize(m2t, marker, markerSize); % take over the marker size in any case when in strict mode; % if not, don't add anything in case of default marker size % and effectively take Pgfplots' default. if m2t.cmdOpts.Results.strict || ~isDefault drawOptions{end+1} = sprintf('mark size=%.1fpt', tikzMarkerSize); end markOptions = cell(0); % make sure that the markers get painted in solid (and not dashed) % if the 'lineStyle' is not solid (otherwise there is no problem) if ~strcmp(lineStyle, 'solid') markOptions{end+1} = 'solid'; end % print no lines if strcmp(lineStyle,'none') || lineWidth==0 drawOptions{end+1} = 'only marks'; end % get the marker color right markerFaceColor = get(h, 'markerfaceColor'); markerEdgeColor = get(h, 'markeredgeColor'); [tikzMarker, markOptions] = translateMarker(m2t, marker, ... markOptions, ~strcmp(markerFaceColor,'none')); if ~strcmp(markerFaceColor,'none') [m2t, xcolor] = getColor(m2t, h, markerFaceColor, 'patch'); markOptions{end+1} = sprintf('fill=%s', xcolor); end if ~strcmp(markerEdgeColor,'none') && ~strcmp(markerEdgeColor,'auto') [m2t, xcolor] = getColor(m2t, h, markerEdgeColor, 'patch'); markOptions{end+1} = sprintf('draw=%s', xcolor); end % add it all to drawOptions drawOptions{end+1} = sprintf('mark=%s', tikzMarker); if ~isempty(markOptions) mo = join(m2t, markOptions, ','); drawOptions{end+1} = ['mark options={', mo, '}']; end end end % ========================================================================= function [tikzMarkerSize, isDefault] = ... translateMarkerSize(m2t, matlabMarker, matlabMarkerSize) % The markersizes of Matlab and TikZ are related, but not equal. This % is because % % 1.) MATLAB uses the MarkerSize property to describe something like % the diameter of the mark, while TikZ refers to the 'radius', % 2.) MATLAB and TikZ take different measures (, e.g., the % edgelength of a square vs. the diagonal length of it). if(~ischar(matlabMarker)) error('matlab2tikz:translateMarkerSize', ... 'Variable matlabMarker is not a string.'); end if(~isnumeric(matlabMarkerSize)) error('matlab2tikz:translateMarkerSize', ... 'Variable matlabMarkerSize is not a numeral.'); end % 6pt is the default MATLAB marker size for all markers defaultMatlabMarkerSize = 6; isDefault = abs(matlabMarkerSize-defaultMatlabMarkerSize)'} % for triangles, matlab takes the height % and tikz the circumcircle radius; % the triangles are always equiangular tikzMarkerSize = matlabMarkerSize / 2 * (2/3); otherwise error('matlab2tikz:translateMarkerSize', ... 'Unknown matlabMarker ''%s''.', matlabMarker); end end % ========================================================================= function [tikzMarker, markOptions] = ... translateMarker(m2t, matlabMarker, markOptions, faceColorToggle) % This function is used for getMarkerOptions() as well as drawScatterPlot(). if(~ischar(matlabMarker)) error('matlab2tikz:translateMarker:MarkerNotAString',... 'Variable matlabMarker is not a string.'); end switch (matlabMarker) case 'none' tikzMarker = ''; case '+' tikzMarker = '+'; case 'o' if faceColorToggle tikzMarker = '*'; else tikzMarker = 'o'; end case '.' tikzMarker = '*'; case 'x' tikzMarker = 'x'; otherwise % the following markers are only available with PGF's % plotmarks library userInfo(m2t, '\nMake sure to load \\usetikzlibrary{plotmarks} in the preamble.\n'); hasFilledVariant = true; switch (matlabMarker) case '*' tikzMarker = 'asterisk'; hasFilledVariant = false; case {'s','square'} tikzMarker = 'square'; case {'d','diamond'} tikzMarker = 'diamond'; case '^' tikzMarker = 'triangle'; case 'v' tikzMarker = 'triangle'; markOptions = [markOptions, ',rotate=180']; case '<' tikzMarker = 'triangle'; markOptions = [markOptions, ',rotate=90']; case '>' tikzMarker = 'triangle'; markOptions = [markOptions, ',rotate=270']; case {'p','pentagram'} tikzMarker = 'star'; case {'h','hexagram'} userWarning(m2t, 'MATLAB''s marker ''hexagram'' not available in TikZ. Replacing by ''star''.'); tikzMarker = 'star'; otherwise error('matlab2tikz:translateMarker:unknownMatlabMarker',... 'Unknown matlabMarker ''%s''.',matlabMarker); end if faceColorToggle && hasFilledVariant tikzMarker = [tikzMarker '*']; end end end % ========================================================================= function [m2t, str] = drawPatch(m2t, handle) % Draws a 'patch' graphics object (as found in contourf plots, for % example). % str = []; if ~isVisible(handle) return end % This is for a quirky workaround for stacked bar plots. m2t.axesContainers{end}.nonbarPlotsPresent = true; % MATLAB's patch elements are matrices in which each column represents a % a distinct graphical object. Usually there is only one column, but % there may be more (-->hist plots, although they are now handled % within the barplot framework). xData = get(handle, 'XData'); yData = get(handle, 'YData'); zData = get(handle, 'ZData'); if isempty(zData) columnNames = {'x', 'y'}; data = [xData(:), yData(:)]; plotType = 'addplot'; else columnNames = {'x', 'y', 'z'}; data = applyHgTransform(m2t, [xData(:), yData(:), zData(:)]); plotType = 'addplot3'; m2t.currentAxesContain3dData = true; end % ----------------------------------------------------------------------- % gather the draw options % Make sure that legends are shown in area mode. drawOptions = {'area legend'}; % see if individual color values are present cData = get(handle, 'CData'); % Use the '\\' as a row separator to make sure that the generated figures % work in subplot environments. tableOptions = {'row sep=crcr'}; % Add the proper color map even if the map data isn't directly used in the % plot to make sure that we get correct color bars. if length(cData) == length(xData) % Add the color map. m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... matlab2pgfplotsColormap(m2t, m2t.currentHandles.colormap), []); end % If full color data is provided, we can use point meta color data. % For some reason, this only works for filled contours in Pgfplots, so fall % back to explicit color specifications for line plots. if length(cData) == length(xData) ... && ~strcmp(get(handle, 'FaceColor'), 'none') data = [data, cData(:)]; drawOptions{end+1} = 'patch'; columnNames{end+1} = 'c'; tableOptions{end+1} = 'point meta=\\thisrow{c}'; else % Probably one color only, so things we're probably only dealing with % one patch here. % line width lineStyle = get(handle, 'LineStyle'); lineWidth = get(handle, 'LineWidth'); lineOptions = getLineOptions(m2t, lineStyle, lineWidth); drawOptions = [drawOptions, lineOptions]; % Find out color values. % fill color faceColor = get(handle, 'FaceColor'); if ~strcmp(faceColor, 'none') [m2t, xFaceColor] = getColor(m2t, handle, faceColor, 'patch'); drawOptions{end+1} = sprintf('fill=%s', xFaceColor); xFaceAlpha = get(handle, 'FaceAlpha'); if abs(xFaceAlpha-1.0) > m2t.tol drawOptions{end+1} = sprintf('opacity=%s', xFaceAlpha); end end % draw color edgeColor = get(handle, 'EdgeColor'); lineStyle = get(handle, 'LineStyle'); if strcmp(lineStyle, 'none') || strcmp(edgeColor, 'none') drawOptions{end+1} = 'draw=none'; else [m2t, xEdgeColor] = getColor(m2t, handle, edgeColor, 'patch'); if isempty(xEdgeColor) % getColor() wasn't able to return a color. This is because cdata % was an actual vector with different values in it, meaning that % the color changes along the edge. This is the case, for % example, with waterfall() plots. % An actual color maps is needed here. % drawOptions{end+1} = 'mesh'; % or surf m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... matlab2pgfplotsColormap(m2t, m2t.currentHandles.colormap), []); % Append upper and lower limit of the color mapping. clim = caxis; m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'point meta min', sprintf(m2t.ff, clim(1))); m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'point meta max', sprintf(m2t.ff, clim(2))); % Note: % Pgfplots can't currently use FaceColor and colormapped edge % color in one go. The option 'surf' makes sure that colormapped % edge colors are used. Face colors are not displayed. else % getColor() returned a reasonable color value. drawOptions{end+1} = sprintf('draw=%s', xEdgeColor); end end end if ~m2t.currentHandleHasLegend % No legend entry found. Don't include plot in legend. drawOptions{end+1} = 'forget plot'; end drawOpts = join(m2t, drawOptions, ','); % ----------------------------------------------------------------------- if any(~isfinite(xData(:))) ... || any(~isfinite(yData(:))) ... || any(~isfinite(zData(:))) m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'unbounded coords', 'jump'); end % Plot the actual data. str = [str, ... sprintf(['\n\\', plotType, '[',drawOpts,']\n']), ... sprintf(['table[', join(m2t, tableOptions, ', '), ']{\n']), ... sprintf([join(m2t, columnNames, ' '), '\\\\\n']), ... sprintf([repmat([m2t.ff, ' '], 1, size(data, 2)), '\\\\\n'], ... data'), ... sprintf('};\n')]; str = [str, sprintf('\n')]; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % ========================================================================= function [m2t, str] = drawImage(m2t, handle) str = []; if ~isVisible(handle) return end % read x-, y-, and color-data xData = get(handle, 'XData'); yData = get(handle, 'YData'); cdata = get(handle, 'CData'); m = size(cdata, 1); n = size(cdata, 2); if ~strcmp(get(m2t.currentHandles.gca,'Visible'), 'off') % Flip the image over as the PNG gets written starting at (0,0) that is, % the top left corner. % MATLAB quirk: In case the axes are invisible, don't do this. cdata = cdata(m:-1:1,:,:); end if (m2t.cmdOpts.Results.imagesAsPng) if ~isfield(m2t, 'imageAsPngNo') m2t.imageAsPngNo = 1; else m2t.imageAsPngNo = m2t.imageAsPngNo + 1; end % ------------------------------------------------------------------------ % draw a png image % Take the TikZ file base name and change the extension .png. [pathstr, name] = fileparts(m2t.tikzFileName); pngFileName = fullfile(pathstr, [name '-' num2str(m2t.imageAsPngNo) '.png']); pngReferencePath = fullfile(m2t.relativePngPath, [name '-' num2str(m2t.imageAsPngNo) '.png']); if strcmp(filesep, '\') % We're on a Windows system with the directory separator % character "\". It has to be changed into "/" for the TeX output pngReferencePath = strrep(pngReferencePath, filesep, '/'); end % Get color indices for indexed color images and truecolor values % otherwise. Don't use ismatrix(), c.f. % . if ndims(cdata) == 2 [m2t, colorData] = cdata2colorindex(m2t, cdata, handle); else colorData = cdata; end % flip the image if reverse if m2t.xAxisReversed colorData = colorData(:, n:-1:1, :); end if m2t.yAxisReversed colorData = colorData(m:-1:1, :, :); end % write the image imwriteWrapperPNG(colorData, m2t.currentHandles.colormap, pngFileName); % ------------------------------------------------------------------------ % dimensions of a pixel in axes units if n==1 xLim = get(m2t.currentHandles.gca, 'XLim'); xw = xLim(2) - xLim(1); else xw = (xData(end)-xData(1)) / (n-1); end if m==1 yLim = get(m2t.currentHandles.gca, 'YLim'); yw = yLim(2) - yLim(1); else yw = (yData(end)-yData(1)) / (m-1); end opts = {sprintf(['xmin=', m2t.ff], xData(1) - xw/2), ... sprintf(['xmax=', m2t.ff], xData(end) + xw/2), ... sprintf(['ymin=', m2t.ff], yData(1) - yw/2), ... sprintf(['ymax=', m2t.ff], yData(end) + yw/2)}; str = [str, ... sprintf('\\addplot graphics [%s] {%s};\n', ... join(m2t, opts, ','), pngReferencePath)]; userInfo(m2t, ... ['\nA PNG file is stored at ''%s'' for which\n', ... 'the TikZ file contains a reference to ''%s''.\n', ... 'You may need to adapt this, depending on the relative\n', ... 'locations of the master TeX file and the included TikZ file.\n'], ... pngFileName, pngReferencePath); else % ------------------------------------------------------------------------ % draw the thing userWarning(m2t, ['It is highly recommended to use PNG data to store images.\n', ... 'Make sure to set ''imagesAsPng'' to true.']); % Generate uniformly distributed X, Y, although xData and yData may be non-uniform. % This is MATLAB(R) behaviour. switch length(xData) case 2 % only the limits given; common for generic image plots hX = 1; case m % specific x-data is given hX = (xData(end)-xData(1)) / (length(xData)-1); otherwise error('drawImage:arrayLengthMismatch', ... 'Array lengths not matching (%d = size(cdata,1) ~= length(xData) = %d).', m, length(xData)); end X = xData(1):hX:xData(end); switch length(yData) case 2 % only the limits given; common for generic image plots hY = 1; case n % specific y-data is given hY = (yData(end)-yData(1)) / (length(yData)-1); otherwise error('drawImage:arrayLengthMismatch', ... 'Array lengths not matching (%d = size(cdata,2) ~= length(yData) = %d).', n, length(yData)); end Y = yData(1):hY:yData(end); m = length(X); n = length(Y); [m2t, xcolor] = getColor(m2t, handle, cdata, 'image'); % The following section takes pretty long to execute, although in % principle it is discouraged to use TikZ for those; LaTeX will take % forever to compile. % Still, a bug has been filed on MathWorks to allow for one-line % sprintf'ing with (string+num) cells (Request ID: 1-9WHK4W); % . for i = 1:m for j = 1:n str = strcat(str, ... sprintf(['\\fill [%s] (axis cs:', m2t.ff,',', m2t.ff,') rectangle (axis cs:',m2t.ff,',',m2t.ff,');\n'], ... xcolor{m-i+1,j}, Y(j)-hY/2, X(i)-hX/2, Y(j)+hY/2, X(i)+hX/2 )); end end % ------------------------------------------------------------------------ end % Make sure that the axes are still visible above the image. m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'axis on top', []); end % ========================================================================= function [m2t, str] = drawHggroup(m2t, h) % Octave doesn't have the handle() function, so there's no way to % determine the nature of the plot anymore at this point. % Set to 'unknown' to force fallback handling. This produces something % for bar plots, for example. try cl = class(handle(h)); catch %#ok cl = 'unknown'; end switch(cl) case 'specgraph.barseries' % hist plots and friends [m2t, str] = drawBarseries(m2t, h); case 'specgraph.stemseries' % stem plots [m2t, str] = drawStemSeries(m2t, h); case 'specgraph.stairseries' % stair plots [m2t, str] = drawStairSeries(m2t, h); case {'specgraph.areaseries'} % scatter plots [m2t,str] = drawAreaSeries(m2t, h); case {'specgraph.quivergroup'} % quiver arrows [m2t, str] = drawQuiverGroup(m2t, h); case {'specgraph.errorbarseries'} % error bars [m2t,str] = drawErrorBars(m2t, h); case {'specgraph.scattergroup'} % scatter plots [m2t,str] = drawScatterPlot(m2t, h); case {'specgraph.contourgroup', 'hggroup'} % handle all those the usual way [m2t, str] = handleAllChildren(m2t, h); case 'unknown' % Weird spurious class from Octave. [m2t, str] = handleAllChildren(m2t, h); otherwise userWarning(m2t, 'Don''t know class ''%s''. Default handling.', cl); try m2tBackup = m2t; [m2t, str] = handleAllChildren(m2t, h); catch ME userWarning(m2t, 'Default handling for ''%s'' failed. Continuing as if it did not occur. \n Original Message:\n %s', cl, getReport(ME)); [m2t, str] = deal(m2tBackup, ''); % roll-back end end end % ========================================================================= function [m2t,env] = drawSurface(m2t, handle) str = []; [m2t, opts, plotType] = surfaceOpts(m2t, handle); dx = get(handle, 'XData'); dy = get(handle, 'YData'); dz = get(handle, 'ZData'); if any(~isfinite(dx(:))) || any(~isfinite(dy(:))) || any(~isfinite(dz(:))) m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'unbounded coords', 'jump'); end [numcols, numrows] = size(dz); % If dx or dy are given as vectors, convert them to the (wasteful) matrix % representation first. This makes sure we can treat the data with one % single sprintf() command below. if isvector(dx) dx = ones(numcols,1) * dx(:)'; end if isvector(dy) dy = dy(:) * ones(1,numrows); end % Add 'z buffer=sort' to the options to make sphere plot and the like not % overlap. There are different options here some of which may be more % advantagous in other situations; check out Pgfplots' manual here. % Since 'z buffer=sort' is computationally more expensive for LaTeX, try % to avoid it for the most default situations, e.g., when dx and dy are % rank-1-matrices. if any(~isnan(dx(1,:)) & dx(1,:) ~= dx(2,:)) ... || any(~isnan(dy(:,1)) & dy(:,1) ~= dy(:,2)) opts{end+1} = 'z buffer=sort'; end % There are several possibilities of how colors are specified for surface % plots: % * explicitly by RGB-values, % * implicitly through a color map with a point-meta coordinate, % * implicitly through a color map with a given coordinate (e.g., z). % % Check if we need extra CData. colors = get(handle, 'CData'); if length(size(colors)) == 3 && size(colors, 3) == 3 % Explicit RGB-coded colors. opts{end+1} = 'mesh/color input=explicit'; formatType = 'table[row sep=crcr,header=false,meta index=3]'; formatString = [m2t.ff, ' ', m2t.ff, ' ', m2t.ff, ' ', ... m2t.ff, ',', m2t.ff, ',', m2t.ff, ... '\\\\\n']; r = colors(:, :, 1); g = colors(:, :, 2); b = colors(:, :, 3); data = [applyHgTransform(m2t, [dx(:), dy(:), dz(:)]), ... r(:), g(:), b(:)]; %formatType = 'table[row sep=crcr,header=false]'; %formatString = [m2t.ff, ' ', m2t.ff, ' ', m2t.ff, '\\\\\n']; %data = applyHgTransform(m2t, [dx(:), dy(:), dz(:)]); %elseif length(size(colors)) > 2 || any(isnan(colors(:))) % needsPointmeta = false; else opts{end+1} = matlab2pgfplotsColormap(m2t, ... m2t.currentHandles.colormap); % If NaNs are present in the color specifications, don't use them for % Pgfplots; they may be interpreted as strings there. The option % 'header=false' will be explicitly added. % Note: % Pgfplots actually does a better job than MATLAB in determining what % colors to use for the patches. The circular test case on % http://www.mathworks.de/de/help/matlab/ref/pcolor.html, for example % yields a symmetric setup in Pgfplots (and doesn't in MATLAB). needsPointmeta = any(xor(isnan(dz), isnan(colors)) ... | (abs(colors - dz) > 1.0e-10)); if needsPointmeta % Get color map. %formatType = 'coordinates'; %formatString = '(%.15g, %.15g, %.15g) [%.15g]\n'; formatType = 'table[row sep=crcr,header=false,meta index=3]'; opts{end+1} = 'point meta=explicit'; formatString = [m2t.ff, ' ', m2t.ff, ' ', m2t.ff, ' ', ... m2t.ff, '\\\\\n']; data = [applyHgTransform(m2t, [dx(:), dy(:), dz(:)]), colors(:)]; else %formatType = 'coordinates'; %formatString = '(%.15g, %.15g, %.15g)\n'; formatType = 'table[row sep=crcr,header=false]'; formatString = [m2t.ff, ' ', m2t.ff, ' ', m2t.ff, '\\\\\n']; data = applyHgTransform(m2t, [dx(:), dy(:), dz(:)]); end end % Add mesh/rows= for specifying the row data instead of empty % lines in the data list below. This makes it possible to reduce the % data writing to one single sprintf() call. opts{end+1} = sprintf('mesh/rows=%d', numrows); opts = join(m2t, opts, ',\n'); str = [str, sprintf(['\n\\addplot3[%%\n%s,\n', opts ,']'], plotType)]; % TODO Check if surf plot is 'spectrogram' or 'surf' and run corresponding % algorithm. % Spectrograms need to have the grid removed, % m2t.axesContainers{end}.options{end+1} = 'grid=none'; % Here is where everything is put together. str = [str, ... sprintf('\n%s {\n', formatType), ... sprintf(formatString, data'), ... sprintf('};\n')]; env = str; % TODO: % - remove grids in spectrogram by either removing grid command % or adding: 'grid=none' from/in axis options % - handling of huge data amounts in LaTeX. if m2t.cmdOpts.Results.automaticLabels [m2t, label] = addLabel(m2t); str = [str, label]; %#ok end m2t.currentAxesContain3dData = true; end % ========================================================================= function [m2t, str] = drawText(m2t, handle) % Adding text node anywhere in the axex environment. % Not that, in Pgfplots, long texts get cut off at the axes. This is % Different from the default MATLAB behavior. To fix this, one could % use /pgfplots/after end axis/.code. str = []; % There may be some text objects floating around a MATLAB figure which % are handled by other subfunctions (labels etc.) or don't need to be % handled at all. % The HandleVisibility says something about whether the text handle is % visible as a data structure or not. Typically, a handle is hidden % if the graphics aren't supposed to be altered, e.g., axis labels. % Most of those entities are captured by matlab2tikz one way or % another, but sometimes they are not. This is the case, for % example, with polar plots and the axis descriptions therein. % Also, Matlab treats text objects with a NaN in the position as % invisible. if any(isnan(get(handle, 'Position')) | isnan(get(handle, 'Rotation'))) ... || strcmp(get(handle, 'Visible'), 'off') ... || (strcmp(get(handle, 'HandleVisibility'), 'off') && ~m2t.cmdOpts.Results.showHiddenStrings) return; end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % get required properties color = get(handle, 'Color'); [m2t, tcolor] = getColor(m2t, handle, color, 'patch'); bgColor = get(handle,'BackgroundColor'); EdgeColor = get(handle, 'EdgeColor'); HorizontalAlignment = get(handle, 'HorizontalAlignment'); String = get(handle, 'String'); Interpreter = get(handle, 'Interpreter'); String = prettyPrint(m2t, String, Interpreter); % For now, don't handle multiline strings. % Sometimes, the cells are nested; take care of this, too. while iscell(String) String = String{1}; end VerticalAlignment = get(handle, 'VerticalAlignment'); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % translate them to pgf style style = cell(0); if ~strcmpi(bgColor,'none') [m2t, bcolor] = getColor(m2t, handle, bgColor, 'patch'); style{end+1} = ['fill=' bcolor]; end switch VerticalAlignment case {'top', 'cap'} style{end+1} = 'below'; case {'baseline', 'bottom'} style{end+1} = 'above'; end switch HorizontalAlignment case 'left' style{end+1} = 'right'; case 'right' style{end+1} = 'left'; end % remove invisible border around \node to make the text align precisely style{end+1} = 'inner sep=0mm'; % Add rotation. rot = get(handle, 'Rotation'); if rot ~= 0.0 style{end+1} = sprintf(['rotate=', m2t.ff], rot); end % Don't try and mess around with the font sizes: MATLAB and LaTeX have % a very different approach for the two. % While MATLAB determines the font sizes in points (pt), the font size % in LaTeX is determined globally by the font in use and the environment % specs (What you mean is what you get). % MATLAB's default font size is 10pt which is way to small for usual % plots, but fits quite okay for annoated contours, for example. % It's a mess. % switch get(handle, 'FontSize') % case 10 % % This setting comes out quite okay for contour annotations. % style{end+1} = sprintf('font=\\tiny'); % case 12 % style{end+1} = sprintf('font=\\footnotesize'); % end style{end+1} = ['text=' tcolor]; if ~strcmp(EdgeColor, 'none') [m2t, ecolor] = getColor(m2t, handle, EdgeColor, 'patch'); style{end+1} = ['draw=', ecolor]; end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % plot the thing pos = get(handle, 'Position'); units = get(handle, 'Units'); if length(pos) == 2 if strcmp(units, 'normalized') posString = sprintf(['(rel axis cs:', m2t.ff, ',', m2t.ff, ')'], pos); else posString = sprintf(['(axis cs:', m2t.ff, ',', m2t.ff, ')'], pos); end xlim = get(m2t.currentHandles.gca,'XLim'); ylim = get(m2t.currentHandles.gca,'YLim'); if pos(1) < xlim(1) || pos(1) > xlim(2) ... || pos(2) < ylim(1) || pos(2) > ylim(2) m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'clip', 'false'); end elseif length(pos) == 3 pos = applyHgTransform(m2t, pos); if strcmp(units, 'normalized') posString = sprintf(['(rel axis cs:',m2t.ff,',',m2t.ff,',',m2t.ff,')'], pos); else posString = sprintf(['(axis cs:',m2t.ff,',',m2t.ff,',',m2t.ff,')'], pos); end xlim = get(m2t.currentHandles.gca, 'XLim'); ylim = get(m2t.currentHandles.gca, 'YLim'); zlim = get(m2t.currentHandles.gca, 'ZLim'); if pos(1) < xlim(1) || pos(1) > xlim(2) ... || pos(2) < ylim(1) || pos(2) > ylim(2) ... || pos(3) < zlim(1) || pos(3) > zlim(2) m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'clip', 'false'); end else error('matlab2tikz:drawText', ... 'Illegal text position specification.'); end str = sprintf('\\node[%s]\nat %s {%s};\n', ... join(m2t, style,', '), posString, String); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % ========================================================================= function [m2t, str] = drawRectangle(m2t, handle) str = []; % there may be some text objects floating around a Matlab figure which % are handled by other subfunctions (labels etc.) or don't need to be % handled at all if strcmp(get(handle, 'Visible'), 'off') ... || strcmp(get(handle, 'HandleVisibility'), 'off') return; end % TODO handle Curvature = [0.8 0.4] % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - lineStyle = get(handle, 'LineStyle'); lineWidth = get(handle, 'LineWidth'); if (strcmp(lineStyle,'none') || lineWidth==0) return end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Get draw options. lineOptions = getLineOptions(m2t, lineStyle, lineWidth); colorOptions = cell(0); % fill color faceColor = get(handle, 'FaceColor'); if ~strcmp(faceColor, 'none') [m2t, xFaceColor] = getColor(m2t, handle, faceColor, 'patch'); colorOptions{end+1} = sprintf('fill=%s', xFaceColor); end % draw color edgeColor = get(handle, 'EdgeColor'); lineStyle = get(handle, 'LineStyle'); if strcmp(lineStyle, 'none') || strcmp(edgeColor, 'none') colorOptions{end+1} = 'draw=none'; else [m2t, xEdgeColor] = getColor(m2t, handle, edgeColor, 'patch'); colorOptions{end+1} = sprintf('draw=%s', xEdgeColor); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - pos = pos2dims(get(handle, 'Position')); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - drawOptions = [lineOptions, colorOptions]; % plot the thing str = sprintf(['\\draw[%s] (axis cs:',m2t.ff,',',m2t.ff,') rectangle (axis cs:',m2t.ff,',',m2t.ff,');\n'], ... join(m2t, drawOptions,', '), pos.left, pos.bottom, pos.right, pos.top ... ); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % ========================================================================= function [m2t,surfOptions,plotType] = surfaceOpts(m2t, handle) faceColor = get(handle, 'FaceColor'); edgeColor = get(handle, 'EdgeColor'); % Check for surf or mesh plot. Second argument in if-check corresponds to % default values for mesh plot in MATLAB. if strcmpi(faceColor, 'none') || ... (strcmpi(edgeColor, 'flat') && isequal(faceColor, [1 1 1])) plotType = 'mesh'; else plotType = 'surf'; end surfOptions = cell(0); % Set opacity if FaceAlpha < 1 in MATLAB faceAlpha = get(handle, 'FaceAlpha'); if isnumeric(faceAlpha) && faceAlpha ~= 1.0 surfOptions{end+1} = sprintf(['opacity=', m2t.ff], faceAlpha); end % TODO Revisit this selection and create a bunch of test plots. if strcmpi(plotType, 'surf') % Set shader for surface plot. if strcmpi(edgeColor, 'none') && strcmpi(faceColor, 'flat') surfOptions{end+1} = 'shader=flat'; elseif isnumeric(edgeColor) && strcmpi(faceColor, 'flat') [m2t, xEdgeColor] = getColor(m2t, handle, edgeColor, 'patch'); % same as shader=flat,draw=\pgfkeysvalueof{/pgfplots/faceted color} surfOptions{end+1} = 'shader=faceted'; surfOptions{end+1} = sprintf('draw=%s', xEdgeColor); elseif strcmpi(edgeColor, 'none') && strcmpi(faceColor, 'interp') surfOptions{end+1} = 'shader=interp'; else surfOptions{end+1} = 'shader=faceted interp'; end elseif strcmpi(plotType, 'mesh') surfOptions{end+1} = 'shader=flat'; else error('matlab2tikz:surfaceOpts', ... 'Illegal plot type ''%s''.', plotType); end end % ========================================================================= function [m2t, str] = drawScatterPlot(m2t, h) str = []; xData = get(h, 'XData'); yData = get(h, 'YData'); zData = get(h, 'ZData'); cData = get(h, 'CData'); matlabMarker = get(h, 'Marker'); markerFaceColor = get(h, 'MarkerFaceColor'); hasFaceColor = ~strcmp(markerFaceColor,'none'); [tikzMarker, markOptions] = translateMarker(m2t, matlabMarker, [], hasFaceColor); if length(cData) == 3 % No special treatment for the colors or markers are needed. % All markers have the same color. [m2t, xcolor] = getColor(m2t, h, cData, 'patch'); drawOptions = { 'only marks', ... ['mark=' tikzMarker], ... ['color=' xcolor] }; elseif size(cData,2) == 3 drawOptions = { 'only marks' ... % TODO Get this in order as soon as Pgfplots can do "scatter rgb". % 'scatter rgb' ... }; else markerOptions = { ['mark=', tikzMarker], ... sprintf('draw=mapped color') }; if hasFaceColor markerOptions{end+1} = 'fill=mapped color'; end drawOptions = { 'scatter', ... 'only marks', ... 'scatter src=explicit', ... ['scatter/use mapped color={', join(m2t, markerOptions,','), '}'] }; % Add color map. m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... matlab2pgfplotsColormap(m2t, m2t.currentHandles.colormap), []); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % plot the thing drawOpts = join(m2t, drawOptions, ','); if isempty(zData) env = 'addplot'; format = ['(', m2t.ff, ',', m2t.ff, ')']; data = [xData(:), yData(:)]; else env = 'addplot3'; m2t.currentAxesContain3dData = true; format = ['(', m2t.ff, ',', m2t.ff, ',', m2t.ff, ')']; data = applyHgTransform(m2t, [xData(:),yData(:),zData(:)]); end if length(cData) == 3 % If size(cData,1)==1, then all the colors are the same and have % already been accounted for above. format = [format, '\n']; elseif size(cData,2) == 3 % Hm, can't deal with this? %[m2t, col] = rgb2colorliteral(m2t, cData(k,:)); %str = strcat(str, sprintf(' [%s]\n', col)); else format = [format, ' [%d]\n']; data = [data, cData(:)]; end % The actual printing. str = [str, ... sprintf('\\%s[%s] plot coordinates{\n', env, drawOpts), ... sprintf(format, data'), ... sprintf('};\n\n')]; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % ========================================================================= function [m2t, str] = drawBarseries(m2t, h) % Takes care of plots like the ones produced by MATLAB's hist. % The main pillar is Pgfplots's '{x,y}bar' plot. % % TODO Get rid of code duplication with 'drawAxes'. % m2t.barplotId is set to [] in drawAxes(), so all of the values are computed % anew for subplots. if ~isfield(m2t, 'barplotId') || isempty(m2t.barplotId) % 'barplotId' provides a consecutively numbered ID for each % barseries plot. This allows for a proper handling of multiple bars. m2t.barplotId = []; m2t.barplotTotalNumber = []; m2t.barShifts = []; m2t.addedAxisOption = false; end str = []; % ----------------------------------------------------------------------- % The bar plot implementation in Pgfplots lacks certain functionalities; % for example, it can't plot bar plots and non-bar plots in the same % axis (while MATLAB can). % The following checks if this is the case and cowardly bails out if so. % On top of that, the number of bar plots is counted. if isempty(m2t.barplotTotalNumber) m2t.barplotTotalNumber = 0; siblings = get(get(h, 'Parent'), 'Children'); for s = siblings(:)' % skip invisible objects if ~isVisible(s) continue; end if strcmpi(get(s, 'Type'), 'hggroup') cl = class(handle(s)); switch cl case 'specgraph.barseries' m2t.barplotTotalNumber = m2t.barplotTotalNumber + 1; case 'specgraph.errorbarseries' % TODO % Unfortunately, MATLAB(R) treats error bars and % corresponding bar plots as siblings of a common axes % object. For error bars to work with bar plots -- which % is trivially possible in Pgfplots -- one has to match % errorbar and bar objects (probably by their values). userWarning(m2t, 'Error bars discarded (to be implemented).'); otherwise error('matlab2tikz:drawBarseries', ... 'Unknown class''%s''.', cl); end end end end % ----------------------------------------------------------------------- xData = get(h, 'XData'); yData = get(h, 'YData'); % init drawOptions drawOptions = cell(0); barlayout = get(h, 'BarLayout'); isHoriz = strcmp(get(h, 'Horizontal'), 'on'); if (isHoriz) barType = 'xbar'; else barType = 'ybar'; end numBars = m2t.barplotTotalNumber; switch barlayout case 'grouped' % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % grouped plots % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % set ID if isempty(m2t.barplotId) m2t.barplotId = 1; else m2t.barplotId = m2t.barplotId + 1; end % % From /toolbox/matlab/specgraph/makebars.m % % plottype==0 means 'grouped' % if m==1 || plottype~=0, % groupWidth = 1.0; % else % groupWidth = min(groupWidth, m/(m+1.5)); % end % xx(:,3:4) = 1; % if plottype==0, % xx = (xx-0.5)*barwidth*groupwidth/m; % else % xx = (xx-0.5)*barwidth*groupwidth; % end % Maximum group with relative to the minumum distance between to % x-values. maxGroupWidth = 0.8; if numBars == 1 groupWidth = 1.0; else groupWidth = min(maxGroupWidth, numBars/(numBars+1.5)); end % --------------------------------------------------------------- % Calculate the width of each bar and the center point shift. % The following is taken from MATLAB (see makebars.m) without % the special handling for hist plots or other fancy options. % --------------------------------------------------------------- if isempty(m2t.barShifts) % Get the shifts of the bar centers. % In case of numBars==1, this returns 0, % In case of numBars==2, this returns [-1/4, 1/4], % In case of numBars==3, this returns [-1/3, 0, 1/3], % and so forth. % The bar width is assumed to be groupWidth/numBars. m2t.barShifts = ((1:numBars) - 0.5) * groupWidth / numBars ... - 0.5* groupWidth; end % --------------------------------------------------------------- % From http://www.mathworks.com/help/techdoc/ref/bar.html: % bar(...,width) sets the relative bar width and controls the % separation of bars within a group. The default width is 0.8, so if % you do not specify X, the bars within a group have a slight % separation. If width is 1, the bars within a group touch one % another. The value of width must be a scalar. barWidth = get(h, 'BarWidth') * groupWidth / numBars; % The minimum distance between two x-values. This is the scaling % factor for all other lengths about the bars. dx = min(diff(xData)); % MATLAB treats shift and width in normalized coordinate units, % whereas Pgfplots requires physical units (pt,cm,...); hence % have the units converted. if (isHoriz) physicalBarWidth = dx * barWidth * m2t.unitlength.y.value; physicalBarShift = dx * m2t.barShifts(m2t.barplotId) * m2t.unitlength.y.value; phyicalBarUnit = m2t.unitlength.y.unit; else physicalBarWidth = dx * barWidth * m2t.unitlength.x.value; physicalBarShift = dx * m2t.barShifts(m2t.barplotId) * m2t.unitlength.x.value; phyicalBarUnit = m2t.unitlength.x.unit; end drawOptions = {drawOptions{:}, ... barType, ... sprintf(['bar width=',m2t.ff,'%s'], physicalBarWidth, phyicalBarUnit)}; if physicalBarShift ~= 0.0 drawOptions{end+1} = ... sprintf(['bar shift=',m2t.ff,'%s'], physicalBarShift, phyicalBarUnit); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % end grouped plots % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case 'stacked' % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Stacked plots -- % Add option 'ybar stacked' to the options of the surrounding % axis environment (and disallow anything else but stacked % plots). % Make sure this happens exactly *once*. if isempty(m2t.addedAxisOption) || ~m2t.addedAxisOption m2t.axesContainers{end}.stackedBarsPresent = true; bWFactor = get(h, 'BarWidth'); % Add 'ybar stacked' to the containing axes environment. m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... [barType,' stacked'], []); m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'bar width', ... sprintf([m2t.ff,'%s'], m2t.unitlength.x.value*bWFactor, m2t.unitlength.x.unit)); m2t.addedAxisOption = true; end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - otherwise error('matlab2tikz:drawBarseries', ... 'Don''t know how to handle BarLayout ''%s''.', barlayout); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % define edge color edgeColor = get(h, 'EdgeColor'); lineStyle = get(h, 'LineStyle'); if strcmp(lineStyle, 'none') || strcmp(edgeColor, 'none') drawOptions{end+1} = 'draw=none'; else [m2t, xEdgeColor] = getColor(m2t, h, edgeColor, 'patch'); drawOptions{end+1} = sprintf('draw=%s', xEdgeColor); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % define face color; % quite oddly, this value is not coded in the handle itself, but in its % child patch. child = get(h, 'Children'); faceColor = get(child, 'FaceColor'); if ~strcmp(faceColor, 'none') [m2t, xFaceColor] = getColor(m2t, h, faceColor, 'patch'); drawOptions{end+1} = sprintf('fill=%s', xFaceColor); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Add 'area legend' to the options as otherwise the legend indicators % will just highlight the edges. m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, 'area legend', []); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % plot the thing drawOpts = join(m2t, drawOptions, ','); str = [str, ... sprintf('\\addplot[%s] plot coordinates{\n', drawOpts)]; if isHoriz % If the bars are horizontal, the values x and y are exchanged. str = strcat(str, ... sprintf(['(',m2t.ff,',',m2t.ff,')\n'], [yData(:), xData(:)]')); else str = strcat(str, ... sprintf(['(',m2t.ff,',',m2t.ff,')\n'], [xData(:), yData(:)]')); end str = [str, sprintf('};\n\n')]; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % ========================================================================= function [m2t, str] = drawStemSeries(m2t, h) [m2t, str] = drawStemOrStairSeries_(m2t, h, 'ycomb'); end function [m2t, str] = drawStairSeries(m2t, h) [m2t, str] = drawStemOrStairSeries_(m2t, h, 'const plot'); end function [m2t, str] = drawStemOrStairSeries_(m2t, h, plotType) str = []; lineStyle = get(h, 'LineStyle'); lineWidth = get(h, 'LineWidth'); marker = get(h, 'Marker'); if ((strcmp(lineStyle,'none') || lineWidth==0) && strcmp(marker,'none')) return % nothing to plot! end %% deal with draw options color = get(h, 'Color'); [m2t, plotColor] = getColor(m2t, h, color, 'patch'); lineOptions = getLineOptions(m2t, lineStyle, lineWidth); [m2t, markerOptions] = getMarkerOptions(m2t, h); drawOptions = [plotType, ... sprintf('color=%s', plotColor),... lineOptions, ... markerOptions]; %% insert draw options drawOpts = join(m2t, drawOptions, ','); %% plot the thing xData = get(h, 'XData'); yData = get(h, 'YData'); str = [str, ... sprintf('\\addplot[%s] plot coordinates{\n', drawOpts), ... sprintf(['(',m2t.ff,',',m2t.ff,')\n'], [xData(:), yData(:)]'), ... sprintf('};\n\n')]; end % ========================================================================= function [m2t, str] = drawAreaSeries(m2t, h) % Takes care of MATLAB's stem plots. % % TODO Get rid of code duplication with 'drawAxes'. str = []; if ~isfield(m2t, 'addedAreaOption') || isempty(m2t.addedAreaOption) || ~m2t.addedAreaOption % Add 'area style' to axes options. m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, 'area style', []); m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, 'stack plots', 'y'); m2t.addedAreaOption = true; end % Handle draw options. % define edge color drawOptions = {}; edgeColor = get(h, 'EdgeColor'); [m2t, xEdgeColor] = getColor(m2t, h, edgeColor, 'patch'); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % define face color; % quite oddly, this value is not coded in the handle itself, but in its % child patch. child = get(h, 'Children'); faceColor = get(child, 'FaceColor'); [m2t, xFaceColor] = getColor(m2t, h, faceColor, 'patch'); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % gather the draw options lineStyle = get(h, 'LineStyle'); drawOptions{end+1} = sprintf('fill=%s', xFaceColor); if strcmp(lineStyle, 'none') drawOptions{end+1} = 'draw=none'; else drawOptions{end+1} = sprintf('draw=%s', xEdgeColor); end drawOpts = join(m2t, drawOptions, ','); % plot the thing xData = get(h, 'XData'); yData = get(h, 'YData'); str = [str, ... sprintf('\\addplot[%s] plot coordinates{\n', drawOpts), ... sprintf(['(',m2t.ff,',',m2t.ff,')\n'], [xData(:), yData(:)]'), ... sprintf('}\n\\closedcycle;\n')]; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % ========================================================================= function [m2t, str] = drawQuiverGroup(m2t, h) % Takes care of MATLAB's quiver plots. if ~isfield(m2t, 'quiverId') % used for arrow styles, in case there are more than one quiver fields m2t.quiverId = 0; else m2t.quiverId = m2t.quiverId + 1; end str = []; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % One could get(h,'{X,Y,U,V}Data') in which the intended arrow lengths % are stored. MATLAB(R) however applies some quite sophisticated scaling % here to avoid overlap of arrows. % The actual length of the arrows is stored in c(1) of % % c = get(h, 'Children'); % % 'XData' and 'YData' of c(1) will be of the form % % [arrow1point1, arrow1point2, NaN, arrow2point1, arrow2point2, NaN]. % c = get(h, 'Children'); xData = get(c(1), 'XData'); yData = get(c(1), 'YData'); zData = get(c(1), 'ZData'); step = 3; m = length(xData(1:step:end)); % number of arrows if(isempty(zData)) name = 'addplot'; format = [m2t.ff,',',m2t.ff]; data = zeros(4,m); data(1,:) = xData(1:step:end); data(2,:) = yData(1:step:end); data(3,:) = xData(2:step:end); data(4,:) = yData(2:step:end); else m2t.currentAxesContain3dData = true; name = 'addplot3'; format = [m2t.ff,',',m2t.ff,',',m2t.ff]; data = zeros(6,m); data(1,:) = xData(1:step:end); data(2,:) = yData(1:step:end); data(3,:) = zData(1:step:end); data(4,:) = xData(2:step:end); data(5,:) = yData(2:step:end); data(6,:) = zData(2:step:end); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % gather the arrow options showArrowHead = get(h, 'ShowArrowHead'); lineStyle = get(h, 'LineStyle'); lineWidth = get(h, 'LineWidth'); if (strcmp(lineStyle,'none') || lineWidth==0) && ~showArrowHead return end arrowOpts = cell(0); if showArrowHead arrowOpts = [arrowOpts, '->']; else arrowOpts = [arrowOpts, '-']; end color = get(h, 'Color'); [m2t, arrowcolor] = getColor(m2t, h, color, 'patch'); arrowOpts = [arrowOpts, ... sprintf('color=%s', arrowcolor), ... % color getLineOptions(m2t, lineStyle, lineWidth), ... % line options ]; % define arrow style arrowOptions = join(m2t, arrowOpts, ','); % Append the arrow style to the TikZ options themselves. % TODO: Look into replacing this by something more 'local', % (see \pgfplotset{}). arrowStyle = ['arrow',num2str(m2t.quiverId), '/.style={',arrowOptions,'}']; m2t.content.options = addToOptions(m2t.content.options,... sprintf('arrow%d/.style', m2t.quiverId), ... ['{', arrowOptions, '}']); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % return the vector field code str = [str, ... sprintf(['\\',name,' [arrow',num2str(m2t.quiverId), '] ', ... 'coordinates{(',format,') (',format,')};\n'],... data)]; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end % ========================================================================= function [m2t, str] = drawErrorBars(m2t, h) % Takes care of MATLAB's error bar plots. % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % 'errorseries' plots have two line-plot children, one of which contains % the information about the center points; 'XData' and 'YData' components % are both of length n. % The other contains the information about the deviations (errors), more % more precisely: the lines to be drawn. Those are % ___ % | % | % X <-- (x0,y0) % | % | % _|_ % % X: x0, x0, x0-eps, x0+eps, x0-eps, x0+eps; % Y: y0-dev, y0+dev, y0-dev, y0-dev, y0+dev, y0+dev. % % Hence, 'XData' and 'YData' are of length 6*n and contain redundant info. % Some versions of MATLAB(R) insert more columns with NaNs (to be able to % pass the entire X, Y arrays into plot()) such that the data is laid out as % % X: x0, x0, NaN, x0-eps, x0+eps, NaN, x0-eps, x0+eps; % Y: y0-dev, y0+dev, NaN, y0-dev, y0-dev, NaN, y0+dev, y0+dev, % % or with another columns of NaNs added at the end. % % This function accounts for all variants. % c = get(h, 'Children'); % Find out which contains the data and which the deviations. n1 = length(get(c(1),'XData')); n2 = length(get(c(2),'XData')); if n2 == 6*n1 % 1 contains centerpoint info dataIdx = 1; errorIdx = 2; numDevData = 6; elseif n1 == 6*n2 % 2 contains centerpoint info dataIdx = 2; errorIdx = 1; numDevData = 6; elseif n2 == 9*n1-1 || n2 == 9*n1 % 1 contains centerpoint info dataIdx = 1; errorIdx = 2; numDevData = 9; elseif n1 == 9*n2-1 || n1 == 9*n2 % 2 contains centerpoint info dataIdx = 2; errorIdx = 1; numDevData = 9; else error('drawErrorBars:errorMatch', ... 'Sizes of and error data not matching (6*%d ~= %d and 6*%d ~= %d, 9*%d-1 ~= %d, 9*%d-1 ~= %d).', ... n1, n2, n2, n1, n1, n2, n2, n1); end % prepare error array (that is, gather the y-deviations) yValues = get(c(dataIdx) , 'YData'); yErrors = get(c(errorIdx), 'YData'); n = length(yValues); yDeviations = zeros(n, 2); for k = 1:n % upper deviation kk = numDevData*(k-1) + 1; upDev = abs(yValues(k) - yErrors(kk)); % lower deviation kk = numDevData*(k-1) + 2; loDev = abs(yValues(k) - yErrors(kk)); yDeviations(k,:) = [upDev loDev]; end % Now, pull drawLine() with deviation information. [m2t, str] = drawLine(m2t, c(dataIdx), yDeviations); end % ============================================================================= function out = linearFunction(X, Y) % Return the linear function that goes through (X[1], Y[1]), (X[2], Y[2]). out = @(x) (Y(2,:)*(x-X(1)) + Y(1,:)*(X(2)-x)) / (X(2)-X(1)); end % ============================================================================= function matlabColormap = pgfplots2matlabColormap(points, rgb, numColors) % Translates a Pgfplots colormap to a MATLAB color map. matlabColormap = zeros(numColors, 3); % Point indices between which to interpolate. I = [1, 2]; f = linearFunction(points(I), rgb(I,:)); for k = 1:numColors x = (k-1)/(numColors-1) * points(end); if x > points(I(2)) I = I + 1; f = linearFunction(points(I), rgb(I,:)); end matlabColormap(k,:) = f(x); end end % ============================================================================= function pgfplotsColormap = matlab2pgfplotsColormap(m2t, matlabColormap) % Translates a MATLAB color map into a Pgfplots colormap. % First check if we could use a default Pgfplots color map. % Unfortunately, MATLAB and Pgfplots color maps will never exactly coincide % except to the most simple cases such as blackwhite. This is because of a % slight incompatibility of Pgfplots and MATLAB colormaps: % In MATLAB, indexing goes from 1 through 64, whereas in Pgfplots you can % specify any range, the default ones having something like % (0: red, 1: yellow, 2: blue). % To specify this exact color map in MATLAB, one would have to put 'red' at % 1, blue at 64, and yellow in the middle of the two, 32.5 that is. % Not really sure how MATLAB rounds here: 32, 33? Anyways, it will be % slightly off and hence not match the Pgfplots color map. % As a workaround, build the MATLAB-formatted colormaps of Pgfplots default % color maps, and check if matlabColormap is close to it. If yes, take it. % For now, comment out the color maps which haven't landed yet in Pgfplots. pgfmaps = { %struct('name', 'colormap/autumn', ... % 'points', [0,1], ... % 'values', [[1,0,0];[1,1,0]]), ... %struct('name', 'colormap/bled', ... % 'points', 0:6, ... % 'values', [[0,0,0];[43,43,0];[0,85,0];[0,128,128];[0,0,170];[213,0,213];[255,0,0]]/255), ... %struct('name', 'colormap/bright', ... % 'points', 0:7, ... % 'values', [[0,0,0];[78,3,100];[2,74,255];[255,21,181];[255,113,26];[147,213,114];[230,255,0];[255,255,255]]/255), ... %struct('name', 'colormap/bone', ... % 'points', [0,3,6,8], ... % 'values', [[0,0,0];[84,84,116];[167,199,199];[255,255,255]]/255), ... %struct('name', 'colormap/cold', ... % 'points', 0:3, ... % 'values', [[0,0,0];[0,0,1];[0,1,1];[1,1,1]]), ... %struct('name', 'colormap/copper', ... % 'points', [0,4,5], ... % 'values', [[0,0,0];[255,159,101];[255,199,127]]/255), ... %struct('name', 'colormap/copper2', ... % 'points', 0:4, ... % 'values', [[0,0,0];[68,62,63];[170,112,95];[207,194,138];[255,255,255]]/255), ... %struct('name', 'colormap/hsv', ... % 'points', 0:6, ... % 'values', [[1,0,0];[1,1,0];[0,1,0];[0,1,1];[0,0,1];[1,0,1];[1,0,0]]), ... struct('name', 'colormap/hot', ... 'points', 0:3, ... 'values', [[0,0,1];[1,1,0];[1,0.5,0];[1,0,0]]), ... % TODO check this struct('name', 'colormap/hot2', ... 'points', [0,3,6,8], ... 'values', [[0,0,0];[1,0,0];[1,1,0];[1,1,1]]), ... struct('name', 'colormap/jet', ... 'points', [0,1,3,5,7,8], ... 'values', [[0,0,128];[0,0,255];[0,255,255];[255,255,0];[255,0,0];[128,0,0]]/255), ... struct('name', 'colormap/blackwhite', ... 'points', [0,1], ... 'values', [[0,0,0];[1,1,1]]), ... struct('name', 'colormap/bluered', ... 'points', 0:5, ... 'values', [[0,0,180];[0,255,255];[100,255,0];[255,255,0];[255,0,0];[128,0,0]]/255), ... struct('name', 'colormap/cool', ... 'points', [0,1,2], ... 'values', [[255,255,255];[0,128,255];[255,0,255]]/255), ... struct('name', 'colormap/greenyellow', ... 'points', [0,1], ... 'values', [[0,128,0];[255,255,0]]/255), ... struct('name', 'colormap/redyellow', ... 'points', [0,1], ... 'values', [[255,0,0];[255,255,0]]/255), ... struct('name', 'colormap/violet', ... 'points', [0,1,2], ... 'values', [[25,25,122];[255,255,255];[238,140,238]]/255) ... }; % The tolerance is a subjective matter of course. % Some figures: % * The norm-distance between MATLAB's gray and bone is 6.8e-2. % * The norm-distance between MATLAB's jet and Pgfplots's jet is 2.8e-2. % * The norm-distance between MATLAB's hot and Pgfplots's hot2 is 2.1e-2. tol = 5.0e-2; for map = pgfmaps numColors = size(matlabColormap, 1); mmap = pgfplots2matlabColormap(map{1}.points, map{1}.values, numColors); alpha = norm(matlabColormap - mmap) / sqrt(numColors); if alpha < tol userInfo(m2t, 'Found %s to be a pretty good match for your color map (||diff||=%g).', ... map{1}.name, alpha); pgfplotsColormap = map{1}.name; return end end % Build a custom color map. % Loop over the data, stop at each spot where the linear % interpolation is interrupted, and set a color mark there. steps = [1, 2]; colors = [matlabColormap(1,:); matlabColormap(2,:)]; f = linearFunction(steps, colors); k = 3; m = size(matlabColormap, 1); while k <= m if norm(matlabColormap(k,:) - f(k)) > 1.0e-10 % Add the previous step to the color list steps(end) = k-1; colors(end,:) = matlabColormap(k-1,:); steps = [steps, k]; colors = [colors; matlabColormap(k,:)]; f = linearFunction(steps(end-1:end), colors(end-1:end,:)); end k = k+1; end steps(end) = m; colors(end,:) = matlabColormap(m,:); % Get it in Pgfplots-readable form. unit = 'pt'; colSpecs = {}; for k = 1:length(steps) x = steps(k)-1; sprintf('rgb(%d%s)=(%g, %g, %g)', x, unit, colors(k)); colSpecs{k} = sprintf('rgb(%d%s)=(%g,%g,%g)', x, unit, colors(k,:)); end pgfplotsColormap = sprintf('colormap={mymap}{[1%s] %s}', unit, join(m2t, colSpecs, '; ')); end % ========================================================================= function axisOptions = getColorbarOptions(m2t, handle) % begin collecting axes options axisOptions = cell(0, 2); cbarOptions = {}; cbarStyleOptions = {}; % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % set position, ticks etc. of the colorbar loc = get(handle, 'Location'); % MATLAB(R)'s keywords are camel cased (e.g., 'NorthOutside'), in Octave % small cased ('northoutside'). Hence, use lower() for uniformity. switch lower(loc) case 'north' cbarOptions{end+1} = 'horizontal'; cbarStyleOptions = {cbarStyleOptions{:},... 'at={(0.5,0.97)}',... 'anchor=north', ... 'xticklabel pos=lower', ... 'width=0.97*\pgfkeysvalueof{/pgfplots/parent axis width}'}; case 'south' cbarOptions{end+1} = 'horizontal'; cbarStyleOptions = {cbarStyleOptions{:},... 'at={(0.5,0.03)}',... 'anchor=south', ... 'xticklabel pos=upper', ... 'width=0.97*\pgfkeysvalueof{/pgfplots/parent axis width}'}; case 'east' cbarOptions{end+1} = 'right'; cbarStyleOptions = {cbarStyleOptions{:},... 'at={(0.97,0.5)}',... 'anchor=east', ... 'xticklabel pos=left', ... 'width=0.97*\pgfkeysvalueof{/pgfplots/parent axis width}'}; case 'west' cbarOptions{end+1} = 'left'; cbarStyleOptions = {cbarStyleOptions{:},... 'at={(0.03,0.5)}',... 'anchor=west', ... 'xticklabel pos=right', ... 'width=0.97*\pgfkeysvalueof{/pgfplots/parent axis width}'}; case 'eastoutside' %cbarOptions{end+1} = 'right'; case 'westoutside' cbarOptions{end+1} = 'left'; case 'northoutside' % TODO move to top cbarOptions{end+1} = 'horizontal'; cbarStyleOptions = {cbarStyleOptions{:},... 'at={(0.5,1.03)}',... 'anchor=south', ... 'xticklabel pos=upper'}; case 'southoutside' cbarOptions{end+1} = 'horizontal'; otherwise error('matlab2tikz:getColorOptions:unknownLocation',... 'getColorbarOptions: Unknown ''Location'' %s.', loc) end % TODO proper use of addToOptions() xo = getAxisOptions(m2t, handle, 'x'); for k = 1:size(xo, 1) if strcmp(xo{k,1}, 'xmin') ... || strcmp(xo{k,1}, 'xmax') ... || strcmp(xo{k,1}, 'xtick') % filter a bunch of keywords continue; end cbarStyleOptions{end+1} = [xo{k,1}, '=', xo{k,2}]; end yo = getAxisOptions(m2t, handle, 'y'); for k = 1:size(yo, 1) if strcmp(yo{k,1}, 'ymin') ... || strcmp(yo{k,1}, 'ymax') % filter a bunch of keywords continue; end cbarStyleOptions{end+1} = [yo{k,1}, '=', yo{k,2}]; end %if strcmp(get(handle, 'YScale'), 'log') % cbarStyleOptions{end+1} = 'ymode=log'; %end % %% Get axis labels. %for axis = 'xy' % axisLabel = get(get(handle, [upper(axis),'Label']), 'String'); % if ~isempty(axisLabel) % axisLabelInterpreter = ... % get(get(handle, [upper(axis),'Label']), 'Interpreter'); % label = prettyPrint(m2t, axisLabel, axisLabelInterpreter); % if length(label) > 1 % % If there's more than one cell item, the list % % is displayed multi-row in MATLAB(R). % % To replicate the same in Pgfplots, one can % % use xlabel={first\\second\\third} only if the % % alignment or the width of the "label box" % % is defined. This is a restriction that comes with % % TikZ nodes. % m2t.axesContainers{end}.options = ... % addToOptions(m2t.axesContainers{end}.options, ... % [axis, 'label style'], '{align=center}'); % end % label = join(m2t, label,'\\[1ex]'); % cbarStyleOptions{end+1} = sprintf([axis,'label={%s}'], label); % end %end % title title = get(get(handle, 'Title'), 'String'); if ~isempty(title) titleInterpreter = get(get(handle, 'Title'), 'Interpreter'); title = prettyPrint(m2t, title, titleInterpreter); if length(title) > 1 m2t.axesContainers{end}.options = ... addToOptions(m2t.axesContainers{end}.options, ... 'title style', '{align=center}'); end title = join(m2t, title, '\\[1ex]'); cbarStyleOptions{end+1} = sprintf('title={%s}', title); end if m2t.cmdOpts.Results.strict % Sampled colors. numColors = size(m2t.currentHandles.colormap, 1); cbarOptions{end+1} = 'sampled'; cbarStyleOptions{end+1} = sprintf('samples=%d', numColors+1); end % Merge them together in axisOptions. if isempty(cbarOptions) axisOptions = addToOptions(axisOptions, 'colorbar', []); else if length(cbarOptions) > 1 userWarning(m2t, ... 'Pgfplots cannot deal with more than one colorbar option yet.'); end axisOptions = addToOptions(axisOptions, ... ['colorbar ', cbarOptions{1}], []); end if ~isempty(cbarStyleOptions) axisOptions = addToOptions(axisOptions, ... 'colorbar style', ... ['{', join(m2t, cbarStyleOptions, ','), '}']); end % Append upper and lower limit of the colorbar. % TODO Use caxis not only for color bars. clim = caxis; axisOptions = addToOptions(axisOptions, 'point meta min', sprintf(m2t.ff, clim(1))); axisOptions = addToOptions(axisOptions, 'point meta max', sprintf(m2t.ff, clim(2))); % do _not_ handle colorbar's children end % ========================================================================= function [m2t, xcolor] = getColor(m2t, handle, color, mode) % Handles MATLAB colors and makes them available to TikZ. % This includes translation of the color value as well as explicit % definition of the color if it is not available in TikZ by default. % % The variable 'mode' essentially determines what format 'color' can % have. Possible values are (as strings) 'patch' and 'image'. % check if the color is straight given in rgb % -- notice that we need the extra NaN test with respect to the QUIRK % below if isreal(color) && length(color)==3 && ~any(isnan(color)) % everything alright: rgb color here [m2t, xcolor] = rgb2colorliteral(m2t, color); else % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - switch mode case 'patch' [m2t, xcolor] = patchcolor2xcolor(m2t, color, handle); case 'image' [m2t, colorindex] = cdata2colorindex(m2t, color, handle); m = size(colorindex, 1); n = size(colorindex, 2); xcolor = cell(m, n); for i = 1:m for j = 1:n [m2t, xc] = rgb2colorliteral(m2t, m2t.currentHandles.colormap(colorindex(i,j), :)); xcolor{i, j} = xc; end end otherwise error(['matlab2tikz:getColor', ... 'Argument ''mode'' has illegal value ''%s''.'], ... mode); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - end end % ========================================================================= function [m2t, xcolor] = patchcolor2xcolor(m2t, color, patchhandle) % Transforms a color of the edge or the face of a patch to an xcolor literal. if ~ischar(color) error('patchcolor2xcolor:illegalInput', ... 'Input argument ''color'' not a string.'); end switch color case 'flat' % look for CData at different places cdata = get(patchhandle, 'CData'); if isempty(cdata) || ~isnumeric(cdata) c = get(patchhandle, 'Children'); cdata = get(c, 'CData'); end col1 = cdata(1,1); if all(isnan(cdata) | abs(cdata-col1)<1.0e-10) [m2t, colorindex] = cdata2colorindex(m2t, col1, patchhandle); [m2t, xcolor] = rgb2colorliteral(m2t, m2t.currentHandles.colormap(colorindex, :)); else % Don't return anything meaningful and count on the caller to % make soemthing of it. xcolor = []; end case 'auto' color = get(patchhandle, 'Color'); [m2t, xcolor] = rgb2colorliteral(m2t, color); case 'none' error('matlab2tikz:anycolor2rgb:ColorModelNoneNotAllowed',... ['Color model ''none'' not allowed here. ',... 'Make sure this case gets intercepted before.']); otherwise error('matlab2tikz:anycolor2rgb:UnknownColorModel',... 'Don''t know how to handle the color model ''%s''.',color); end end % ========================================================================= function [m2t, colorindex] = cdata2colorindex(m2t, cdata, imagehandle) % Transforms a color in CData format to an index in the color map. % Only does something if CDataMapping is 'scaled', really. if ~isnumeric(cdata) && ~islogical(cdata) error('matlab2tikz:cdata2colorindex:unknownCDataType',... 'Don''t know how to handle CData ''%s''.',cdata); end axeshandle = m2t.currentHandles.gca; % ----------------------------------------------------------------------- % For the following, see, for example, the MATLAB help page for 'image', % section 'Image CDataMapping'. switch get(imagehandle, 'CDataMapping') case 'scaled' % need to scale within clim % see MATLAB's manual page for caxis for details clim = get(axeshandle, 'clim'); m = size(m2t.currentHandles.colormap, 1); colorindex = zeros(size(cdata)); idx1 = cdata <= clim(1); idx2 = cdata >= clim(2); idx3 = ~idx1 & ~idx2; colorindex(idx1) = 1; colorindex(idx2) = m; colorindex(idx3) = fix((cdata(idx3)-clim(1)) / (clim(2)-clim(1)) *m) ... + 1; case 'direct' % direct index colorindex = cdata; otherwise error('matlab2tikz:anycolor2rgb:unknownCDataMapping',... 'Unknown CDataMapping ''%s''.',cdatamapping); end % ----------------------------------------------------------------------- end % ========================================================================= function [m2t, key, lOpts] = getLegendOpts(m2t, handle) % Need to check that there's nothing inside visible before we % abandon this legend -- an invisible property of the parent just % means the legend has no box. children = get(handle, 'Children'); if ~isVisible(handle) && ~any(isVisible(children)) return end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % handle legend location loc = get(handle, 'Location'); dist = 0.03; % distance to to axes in normalized coordinated anchor = []; % MATLAB(R)'s keywords are camel cased (e.g., 'NorthOutside'), in Octave % small cased ('northoutside'). Hence, use lower() for uniformity. switch lower(loc) case 'northeast' % don't anything in this (default) case case 'northwest' position = [dist, 1-dist]; anchor = 'north west'; case 'southwest' position = [dist, dist]; anchor = 'south west'; case 'southeast' position = [1-dist, dist]; anchor = 'south east'; case 'north' position = [0.5, 1-dist]; anchor = 'north'; case 'east' position = [1-dist, 0.5]; anchor = 'east'; case 'south' position = [0.5, dist]; anchor = 'south'; case 'west' position = [dist, 0.5]; anchor = 'west'; case 'northoutside' position = [0.5, 1+dist]; anchor = 'south'; case 'southoutside' position = [0.5, -dist]; anchor = 'north'; case 'eastoutside' position = [1+dist, 0.5]; anchor = 'west'; case 'westoutside' position = [-dist, 0.5]; anchor = 'east'; case 'northeastoutside' position = [1+dist, 1]; anchor = 'north west'; case 'northwestoutside' position = [-dist, 1]; anchor = 'north east'; case 'southeastoutside' position = [1+dist, 0]; anchor = 'south west'; case 'southwestoutside' position = [-dist, 0]; anchor = 'south east'; case 'none' % TODO handle position with pixels legendPos = get(handle, 'Position'); unit = get(handle, 'Units'); switch unit case 'normalized' position = legendPos(1:2); case 'pixels' % Calculate where the legend is located w.r.t. the axes. axesPos = get(m2t.currentHandles.gca, 'Position'); % By default, the axes position is given w.r.t. to the figure, % and so is the legend. position = (legendPos(1:2)-axesPos(1:2)) ./ axesPos(3:4); otherwise position = pos(1:2); userWarning(m2t, [' Unknown legend length unit ''', unit, '''' ... '. Handling like ''normalized''.']); end anchor = 'south west'; case {'best','bestoutside'} % TODO: Implement these. % The position could be determined by means of 'Position' and/or % 'OuterPosition' of the legend handle; in fact, this could be made % a general principle for all legend placements. userWarning(m2t, [sprintf(' Option ''%s'' not yet implemented.',loc), ... ' Choosing default.']); otherwise userWarning(m2t, [' Unknown legend location ''',loc,'''' ... '. Choosing default.']); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % handle alignment of legend text and pictograms textalign = []; pictalign = []; switch m2t.env case 'Octave' % Octave allows to change the alignment of legend text and % pictograms using legend('left') and legend('right') textpos = get(handle, 'textposition'); switch lower(textpos) case 'left' % pictogram right of flush right text textalign = 'left'; pictalign = 'right'; case 'right' % pictogram left of flush left text (default) textalign = 'right'; pictalign = 'left'; otherwise userWarning(m2t, [' Unknown legend text position ''',textpos,'''' ... '. Choosing default.']); end case 'MATLAB' % does not specify text/pictogram alignment in legends otherwise errorUnknownEnvironment(); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - lStyle = cell(0); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % append to legend options if ~isempty(anchor) lStyle = {lStyle{:}, ... sprintf(['at={(',m2t.ff,',',m2t.ff,')}'], position), ... sprintf('anchor=%s', anchor)}; end % handle orientation ori = get(handle, 'Orientation'); switch lower(ori) case 'horizontal' numLegendEntries = length(get(handle, 'String')); lStyle{end+1} = sprintf('legend columns=%d', numLegendEntries); case 'vertical' % Use default. otherwise userWarning(m2t, [' Unknown legend orientation ''',ori,'''' ... '. Choosing default (vertical).']); end % If the plot has 'legend boxoff', we have the 'not visible' % property, so turn off line and background fill. if (~isVisible(handle)) lStyle = {lStyle{:}, 'fill=none', 'draw=none'}; else % handle colors edgeColor = get(handle, 'EdgeColor'); if all(edgeColor == [1,1,1]) lStyle = {lStyle{:}, 'draw=none'}; else [m2t, col] = getColor(m2t, handle, edgeColor, 'patch'); lStyle = {lStyle{:}, sprintf('draw=%s', col)}; end fillColor = get(handle, 'Color'); if ~all(edgeColor == [1,1,1]) [m2t, col] = getColor(m2t, handle, fillColor, 'patch'); lStyle = {lStyle{:}, sprintf('fill=%s', col)}; end end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % alignment of legend text and pictograms, if available if ~isempty(textalign) && ~isempty(pictalign) lStyle = {lStyle{:}, ... sprintf('nodes=%s', textalign), ... sprintf('legend plot pos=%s', pictalign)}; else % Make sure the entries are flush left (default MATLAB behavior). % This is also import for multiline legend entries: Without alignment % specification, the TeX document won't compile. %lStyle{end+1} = 'nodes=right'; lStyle{end+1} = 'legend cell align=left'; end if ~isempty(lStyle) key = 'legend style'; lOpts = join(m2t, lStyle,','); end end % ========================================================================= function [pgfTicks, pgfTickLabels, hasMinorTicks] = getAxisTicks(m2t, handle, axis) % Return axis tick marks Pgfplots style. Nice: Tick lengths and such % details are taken care of by Pgfplots. if ~strcmpi(axis,'x') && ~strcmpi(axis,'y') && ~strcmpi(axis,'z') error('matlab2tikz:illegalAxisSpecifier',... 'Illegal axis specifier ''%s''.', axis); end keywordTickMode = [upper(axis), 'TickMode']; tickMode = get(handle, keywordTickMode); keywordTick = [upper(axis), 'Tick']; ticks = get(handle, keywordTick); if isempty(ticks) % If no ticks are present, we need to enforce this in any case. pgfTicks = '\empty'; else if strcmp(tickMode, 'auto') && ~m2t.cmdOpts.Results.strict % If the ticks are set automatically, and strict conversion is % not required, then let Pgfplots take care of the ticks. % In most cases, this looks a lot better anyway. pgfTicks = []; else % strcmp(tickMode,'manual') || m2t.cmdOpts.Results.strict pgfTicks = join(m2t, cellstr(num2str(ticks(:))), ', '); end end keywordTickLabelMode = [upper(axis), 'TickLabelMode']; tickLabelMode = get(handle, keywordTickLabelMode); keywordTickLabel = [upper(axis), 'TickLabel']; tickLabels = cellstr(get(handle, keywordTickLabel)); if strcmp(tickLabelMode, 'auto') && ~m2t.cmdOpts.Results.strict pgfTickLabels = []; else % strcmp(tickLabelMode,'manual') || m2t.cmdOpts.Results.strict keywordScale = [upper(axis), 'Scale']; isAxisLog = strcmp(get(handle,keywordScale), 'log'); [pgfTicks, pgfTickLabels] = ... matlabTicks2pgfplotsTicks(m2t, ticks, tickLabels, isAxisLog); end keywordMinorTick = [upper(axis), 'MinorTick']; hasMinorTicks = strcmp(get(handle, keywordMinorTick), 'on'); end % ========================================================================= function [pTicks, pTickLabels] = ... matlabTicks2pgfplotsTicks(m2t, ticks, tickLabels, isLogAxis) % Converts MATLAB style ticks and tick labels to pgfplots style % ticks and tick labels (if at all necessary). if isempty(ticks) pTicks = '\empty'; pTickLabels = []; return end % set ticks + labels pTicks = join(m2t, num2cell(ticks), ','); % if there's no specific labels, return empty if isempty(tickLabels) || (length(tickLabels)==1 && isempty(tickLabels{1})) pTickLabels = '\empty'; return end % sometimes tickLabels are cells, sometimes plain arrays % -- unify this to cells if ischar(tickLabels) tickLabels = strtrim(mat2cell(tickLabels, ... ones(size(tickLabels,1), 1), ... size(tickLabels, 2) ... ) ... ); end % What MATLAB does when there the number of ticks and tick labels do not % coincide is somewhat unclear. To fix bug % https://github.com/nschloe/matlab2tikz/issues/161, % cut off the first entries in `ticks`. m = length(ticks); n = length(tickLabels); if n < m ticks = ticks(m-n+1:end); end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Check if tickLabels are really necessary (and not already covered by % the tick values themselves). plotLabelsNecessary = false; k = find(ticks ~= 0.0, 1); % get an index with non-zero tick value if isLogAxis || isempty(k) % only a 0-tick scalingFactor = 1; else % When plotting axis, MATLAB might scale the axes by a factor of ten, % say 10^n, and plot a 'x 10^k' next to the respective axis. This is % common practice when the tick marks are really large or small % numbers. % Unfortunately, MATLAB doesn't contain the information about the % scaling anywhere in the plot, and at the same time the {x,y}TickLabels % are given as t*10^k, thus no longer corresponding to the actual % value t. % Try to find the scaling factor here. This is then used to check % whether or not explicit {x,y}TickLabels are really necessary. s = str2double(tickLabels{k}); scalingFactor = ticks(k)/s; % check if the factor is indeed a power of 10 S = log10(scalingFactor); if abs(round(S)-S) > m2t.tol scalingFactor = 1.0; end end for k = 1:min(length(ticks),length(tickLabels)) % Don't use str2num here as then, literal strings as 'pi' get % legally transformed into 3.14... and the need for an explicit % label will not be recognized. str2double returns a NaN for 'pi'. if isLogAxis s = 10^(str2double(tickLabels{k})); else s = str2double(tickLabels{k}); end if isnan(s) || abs(ticks(k)-s*scalingFactor) > m2t.tol plotLabelsNecessary = true; break; end end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if plotLabelsNecessary % if the axis is logscaled, MATLAB does not store the labels, % but the exponents to 10 if isLogAxis for k = 1:length(tickLabels) if isnumeric(tickLabels{k}) str = num2str(tickLabels{k}); else str = tickLabels{k}; end tickLabels{k} = sprintf('$10^{%s}$', str); end end pTickLabels = join(m2t, tickLabels, ','); else pTickLabels = []; end end % ========================================================================= function tikzLineStyle = translateLineStyle(matlabLineStyle) if(~ischar(matlabLineStyle)) error('matlab2tikz:translateLineStyle:NotAString',... 'Variable matlabLineStyle is not a string.'); end switch (matlabLineStyle) case 'none' tikzLineStyle = ''; case '-' tikzLineStyle = 'solid'; case '--' tikzLineStyle = 'dashed'; case ':' tikzLineStyle = 'dotted'; case '-.' tikzLineStyle = 'dash pattern=on 1pt off 3pt on 3pt off 3pt'; otherwise error('matlab2tikz:translateLineStyle:UnknownLineStyle',... 'Unknown matlabLineStyle ''%s''.', matlabLineStyle); end end % ========================================================================= function [m2t, colorLiteral] = rgb2colorliteral(m2t, rgb) % Translates an rgb value to an xcolor literal -- if possible! % If not, it returns the empty string. % This allows for a cleaner output in cases where predefined colors are % being used. % % Take a look at xcolor.sty for the color definitions. % TODO Implement mixtures with colors other than 'black' such as red!50!green. xcolColorNames = {'red', 'green', 'blue', 'brown', ... 'lime', 'orange', 'pink', 'purple', ... 'teal', 'violet', 'black', 'darkgray', ... 'gray', 'lightgray', 'white'}; xcolColorSpecs = {[1,0,0], [0,1,0], [0,0,1], [0.75,0.5,0.25], ... [0.75,1,0], [1,0.5,0], [1,0.75,0.75], [0.75,0,0.25], ... [0,0.5,0.5], [0.5,0,0.5], [0,0,0], [0.25,0.25,0.25], ... [0.5,0.5,0.5], [0.75,0.75,0.75], [1,1,1]}; % The colors 'cyan', 'magenta', 'yellow', and 'olive' within xcolor.sty % are defined in the CMYK color space, with an approximation in RGB. % Unfortunately, the approximation is not very close (particularly for % cyan), so just redefine those colors. % 'cyan', 'magenta', 'yellow', 'olive' % [0,1,1], [1,0,1], [1,1,0], [0.5,0.5,0] % Check 'rgb' against all xcolor literals and the already defined colors. colorNames = [xcolColorNames, m2t.extraRgbColorNames]; colorSpecs = [xcolColorSpecs, m2t.extraRgbColorSpecs]; numCols = length(colorSpecs); % Check if RGB is a multiple of a predefined color. for k = 1:numCols if colorSpecs{k}(1) ~= 0.0 alpha = rgb(1) / colorSpecs{k}(1); elseif colorSpecs{k}(2) ~= 0.0 alpha = rgb(2) / colorSpecs{k}(2); elseif colorSpecs{k}(3) ~= 0.0 alpha = rgb(3) / colorSpecs{k}(3); else % colorSpecs{k} = [0,0,0] alpha = 0.0; end if isequal(rgb, alpha * colorSpecs{k}) if alpha == 1.0 colorLiteral = colorNames{k}; return elseif alpha == 0.0 colorLiteral = 'black'; return elseif 0.0 < alpha && alpha < 1.0 && round(alpha*100) == alpha*100 % Not sure if that last condition is necessary. colorLiteral = [colorNames{k}, sprintf('!%g!black', alpha*100)]; return end end end % Color was not found in the default set. Need to define it. colorLiteral = sprintf('mycolor%d', length(m2t.extraRgbColorNames)+1); m2t.extraRgbColorNames{end+1} = colorLiteral; m2t.extraRgbColorSpecs{end+1} = rgb; end % ========================================================================= function newstr = join(m2t, cellstr, delimiter) % This function joins a cell of strings to a single string (with a % given delimiter inbetween two strings, if desired). % % Example of usage: % join(m2t, cellstr, ',') if isempty(cellstr) newstr = []; return end % convert all values to strings first nElem = numel(cellstr); for k = 1:nElem if isnumeric(cellstr{k}) cellstr{k} = sprintf(m2t.ff, cellstr{k}); elseif iscell(cellstr{k}) cellstr{k} = join(m2t, cellstr{k}, delimiter); % this will fail for heavily nested cells elseif ~ischar(cellstr{k}) error('matlab2tikz:join:NotCellstrOrNumeric',... 'Expected cellstr or numeric.'); end end % inspired by strjoin of recent versions of MATLAB newstr = cell(2,nElem); newstr(1,:) = reshape(cellstr, 1, nElem); newstr(2,1:nElem-1) = {delimiter}; % put delimiters in-between the elements newstr = [newstr{:}]; end % ========================================================================= function dimension = getAxesDimensions(handle, ... widthString, heightString) % optional % Returns the physical dimension of the axes. [width, height, unit] = getNaturalAxesDimensions(handle); % get the natural width-height ration of the plot axesWidthHeightRatio = width / height; % check matlab2tikz arguments if ~isempty(widthString) width = extractValueUnit(widthString); end if ~isempty(heightString) height = extractValueUnit(heightString); end % prepare the output if ~isempty(widthString) && ~isempty(heightString) dimension.x.unit = width.unit; dimension.x.value = width.value; dimension.y.unit = height.unit; dimension.y.value = height.value; elseif ~isempty(widthString) dimension.x.unit = width.unit; dimension.x.value = width.value; dimension.y.unit = width.unit; dimension.y.value = width.value / axesWidthHeightRatio; elseif ~isempty(heightString) dimension.y.unit = height.unit; dimension.y.value = height.value; dimension.x.unit = height.unit; dimension.x.value = height.value * axesWidthHeightRatio; else % neither width nor height given dimension.x.unit = unit; dimension.x.value = width; dimension.y.unit = unit; dimension.y.value = height; end end % ========================================================================= function [width, height, unit] = getNaturalAxesDimensions(handle) daspectmode = get(handle, 'DataAspectRatioMode'); position = get(handle, 'Position'); units = get(handle, 'Units'); % Convert the MATLAB unit strings into TeX unit strings. switch units case 'pixels' units = 'px'; case 'centimeters' units = 'cm'; case 'inches' units = 'in'; case 'points' units = 'pt'; case 'characters' units = 'em'; end switch daspectmode case 'auto' % --------------------------------------------------------------------- % The plot will use the full size of the current figure., if strcmp(units, 'normalized') % The dpi is needed to associate the size on the screen (in pixels) % to the physical size of the plot. % Unfortunately, MATLAB doesn't seem to be able to always make a % good guess about the current DPI (a bug is filed for this on % mathworks.com). dpi = get(0, 'ScreenPixelsPerInch'); unit = 'in'; figuresize = get(gcf, 'Position'); % This assumes that figuresize is always in units of dots (pixels). % Apparently, this isn't always the case, so we're going to need to % fix things here. width = position(3) * figuresize(3) / dpi; height = position(4) * figuresize(4) / dpi; else % assume that TikZ knows the unit (in, cm,...) unit = units; width = position(3); height = position(4); end % --------------------------------------------------------------------- case 'manual' % --------------------------------------------------------------------- % When daspect was manually set, stick to it. % This is achieved here by explicitly determining the x-axis size % and adjusting the y-axis size based on this length. if strcmp(units, 'normalized') % The dpi is needed to associate the size on the screen (in pixels) % to the physical size of the plot (on a pdf, for example). % Unfortunately, MATLAB doesn't seem to be able to always make a % good guess about the current DPI (a bug is filed for this on % mathworks.com). dpi = get(0, 'ScreenPixelsPerInch'); unit = 'in'; figuresize = get(gcf, 'Position'); width = position(3) * figuresize(3) / dpi; else % assume that TikZ knows the unit unit = units; width = position(3); end % set y-axis length xLim = get (handle, 'XLim'); yLim = get (handle, 'YLim'); aspectRatio = get (handle, 'DataAspectRatio'); % = daspect % Actually, we'd have % % xlength = (xLim(2)-xLim(1)) / aspectRatio(1); % ylength = (yLim(2)-yLim(1)) / aspectRatio(2); % % but as xlength is scaled to a fixed 'dimension.x', 'dimension.y' % needs to be rescaled accordingly. height = width ... * aspectRatio(1) / aspectRatio(2) ... * (yLim(2)-yLim(1)) / (xLim(2)-xLim(1)); % --------------------------------------------------------------------- otherwise error('getAxesDimensions:illDaspectMode', ... 'Illegal DataAspectRatioMode ''%s''.', daspectmode); end end % ========================================================================= function out = extractValueUnit(str) % Decompose m2t.cmdOpts.Results.width into value and unit. % Regular expression to match '4.12cm', '\figurewidth', ... fp_regex = '[-+]?\d*\.?\d*(?:e[-+]?\d+)?'; pattern = strcat('(', fp_regex, ')?', '(\\?[a-z]+)'); [dummy,dummy,dummy,dummy,t,dummy] = regexp(str, pattern, 'match'); %#ok if length(t)~=1 error('getAxesDimensions:illegalLength', ... 'The width string ''%s'' could not be decomposed into value-unit pair.', str); end if length(t{1}) == 1 out.value = 1.0; % such as in '1.0\figurewidth' out.unit = strtrim(t{1}{1}); elseif length(t{1}) == 2 && isempty(t{1}{1}) % MATLAB(R) does this: % length(t{1})==2 always, but the first field may be empty. out.value = 1.0; out.unit = strtrim(t{1}{2}); elseif length(t{1}) == 2 out.value = str2double(t{1}{1}); out.unit = strtrim(t{1}{2}); else error('getAxesDimensions:illegalLength', ... 'The width string ''%s'' could not be decomposed into value-unit pair.', str); end end % ========================================================================= function newstr = escapeCharacters(str) % Replaces the single characters % and \ by their escaped versions % %% and \\, respectively. newstr = str; newstr = strrep(newstr, '%' , '%%'); newstr = strrep(newstr, '\' , '\\'); end % ========================================================================= function out = isVisible(handles) % Determines whether an object is actually visible or not. % out = strcmp(get(handles,'Visible'), 'on'); % There's another handle property, 'HandleVisibility', which may or may not % determine the visibility of the object. Empirically, it seems to be 'off' % whenever we're dealing with an object that's not user-created, such as % automatic axis ticks, baselines in bar plots, axis lines for polar plots % and so forth. % For now, don't check 'HandleVisibility'. %% Don't use short-circuit logical operators here to keep the function working %% for multiple handle inputs. %out = ~(strcmp(get(handles,'Visible'), 'off') ... % |strcmp(get(handles, 'HandleVisibility'), 'off')); end % ========================================================================= function [relevantAxesHandles, alignmentOptions, plotOrder] =... alignSubPlots(m2t, axesHandles) % Returns the alignment options for all the axes enviroments. % The question whether two plots are aligned on the left, right, top, or % bottom is answered by looking at the 'Position' property of the % axes object. % % The second output argument 'ix' is the order in which the axes % environments need to be created. This is to make sure that plots % which act as a reference are processed first. % % The output vector 'alignmentOptions' contains: % - whether or not it is a reference (.isRef) % - axes name (.name), only set if .isRef is true % - the actual Pgfplots options (.opts) % % The routine tries to be smart in the sense that it will detect that in % a setup such as % % [AXES1 AXES2] % [AXES3 ] % % 'AXES1' will serve as a reference for AXES2 and AXES3. % It does so by first computing a 'dependency' graph, then traversing % the graph starting from a node (AXES) with maximal connections. % % TODO: % - diagonal connections 'a la % [AXES1 ] % [ AXES2] % % TODO: fix this function % TODO: look for unique IDs of the axes enviroments % which could be returned along with its properties relevantAxesHandles = []; for axesHandle = axesHandles(:)' % Only handle visible non-colorbar handles. if axisIsVisible(axesHandle) && ~strcmp(get(axesHandle,'Tag'), 'Colorbar') relevantAxesHandles(end+1) = axesHandle; end end numRelevantHandles = length(relevantAxesHandles); % initialize alignmentOptions alignmentOptions = struct(); for k = 1:numRelevantHandles alignmentOptions(k).opts = cell(0); end % return immediately if nothing is to be aligned if numRelevantHandles <= 1 plotOrder = 1; return end % Connectivity matrix of the graph. % Contains 0's where the axes environments are not aligned, and % positive integers where they are. The integer encodes how the axes % are aligned (top right:bottom left, and so on). C = zeros(numRelevantHandles, numRelevantHandles); % 'isRef' tells whether the respective plot acts as a position reference % for another plot. % TODO: preallocate this % Also, gather all the positions. axesPos = zeros(numRelevantHandles, 4); for k = 1:numRelevantHandles % `axesPos(i,:)` contains % (indices 1,3): the x-value of the left and the right axis, and % (indices 2,4): the y-value of the bottom and top axis, % of plot `i`. axesPos(k,:) = get(relevantAxesHandles(k), 'Position'); axesPos(k,3) = axesPos(k,1) + axesPos(k,3); axesPos(k,4) = axesPos(k,2) + axesPos(k,4); end % Loop over all figures to see if axes are aligned. % Look for exactly *one* alignment, even if there might be more. % % Among all the {x,y}-alignments choose the one with the closest % {y,x}-distance. This is important, for example, in situations where % there are 3 plots on top of each other: % We want no. 2 to align below no. 1, and no. 3 below no. 2 % (and not no. 1 again). % % There are nine alignments this algorithm can deal with: % % 3| |4 % __ _____________ __ % -2 | | 2 % | | % | 5 | % | | % | | % -1_ |_____________| 1_ % % -3| |-4 % % They are coded in numbers -4 through 5. The matrix C will contain the % corresponding code at position (i,j), if plot number i and j are % aligned in such a way. % If two plots happen to coincide at both left and right axes, for % example, only one relation is stored. % for i = 1:numRelevantHandles for j = i+1:numRelevantHandles if max(abs(axesPos(i,:)-axesPos(j,:))) < m2t.tol % twins C(i,j) = 5; C(j,i) = -5; elseif abs(axesPos(i,1)-axesPos(j,1)) < m2t.tol; % Left axes align. % Check if the axes are on top of each other. if axesPos(i,2) > axesPos(j,4) C(i,j) = -3; C(j,i) = 3; elseif axesPos(j,2) > axesPos(i,4) C(i,j) = 3; C(j,i) = -3; end elseif abs(axesPos(i,1)-axesPos(j,3)) < m2t.tol % left axis of 'i' aligns with right axis of 'j' if axesPos(i,2) > axesPos(j,4) C(i,j) = -3; C(j,i) = 4; elseif axesPos(j,2) > axesPos(i,4) C(i,j) = 3; C(j,i) = -4; end elseif abs(axesPos(i,3)-axesPos(j,1)) < m2t.tol % right axis of 'i' aligns with left axis of 'j' if axesPos(i,2) > axesPos(j,4) C(i,j) = -4; C(j,i) = 3; elseif axesPos(j,2) > axesPos(i,4) C(i,j) = 4; C(j,i) = -3; end elseif abs(axesPos(i,3)-axesPos(j,1)) < m2t.tol % right axes of 'i' and 'j' align if axesPos(i,2) > axesPos(j,4) C(i,j) = -4; C(j,i) = 4; elseif axesPos(j,2) > axesPos(i,4) C(i,j) = 4; C(j,i) = -4; end elseif abs(axesPos(i,2)-axesPos(j,2)) < m2t.tol % lower axes of 'i' and 'j' align if axesPos(i,1) > axesPos(j,3) C(i,j) = -1; C(j,i) = 1; elseif axesPos(j,1) > axesPos(i,3) C(i,j) = 1; C(j,i) = -1; end elseif abs(axesPos(i,2)-axesPos(j,4)) < m2t.tol % lower axis of 'i' aligns with upper axis of 'j' if axesPos(i,1) > axesPos(j,3) C(i,j) = -1; C(j,i) = 2; elseif axesPos(j,1) > axesPos(i,3) C(i,j) = 1; C(j,i) = -2; end elseif abs(axesPos(i,4)-axesPos(j,2)) < m2t.tol % upper axis of 'i' aligns with lower axis of 'j' if axesPos(i,1) > axesPos(j,3) C(i,j) = -2; C(j,i) = 1; elseif axesPos(j,1) > axesPos(i,3) C(i,j) = 2; C(j,i) = -1; end elseif abs(axesPos(i,4)-axesPos(j,4)) < m2t.tol % upper axes of 'i' and 'j' align if axesPos(i,1) > axesPos(j,3) C(i,j) = -2; C(j,i) = 2; elseif axesPos(j,1) > axesPos(i,3) C(i,j) = 2; C(j,i) = -2; end end end end % Now, the matrix C contains all alignment information. % If, for any node, there is more than one plot that aligns with it in the % same way (e.g., upper left), then pick exactly *one* of them. % Take the one that is closest to the correspondig plot. for i = 1:numRelevantHandles for j = 1:numRelevantHandles if C(i,j)==0 || abs(C(i,j))==5 % don't check for double zeros (aka "no relation"'s) or triplets, quadruplets,... continue end % find doubles, and count C(i,j) in doub = find(C(i,j:numRelevantHandles)==C(i,j)) ... + j-1; % to get the actual index if length(doub)>1 % Uh-oh, found doubles: % Pick the one with the minimal distance, delete the other % relations. switch C(i,j) case {1,2} % all plots sit right of 'i' dist = axesPos(doub,1) - axesPos(i,3); case {-1,-2} % all plots sit left of 'i' dist = axesPos(i,1) - axesPos(doub,3); case {3,4} % all plots sit above 'i' dist = axesPos(doub,2) - axesPos(i,4); case {-3,-4} % all plots sit below 'i' dist = axesPos(i,2) - axesPos(doub,4); otherwise error('alignSubPlots:illCode', ... 'Illegal alignment code %d.', C(i,j)); end [dummy,idx] = min(dist); %#ok % 'idx' holds the index of the minimum. % If there is more than one, then % 'idx' has twins. min returns the one % with the lowest index. % delete the index from the 'remove list' doub(idx) = []; C(i,doub) = 0; C(doub,i) = 0; end end end % Alright. The matrix 'C' now contains exactly the alignment info that % we are looking for. %% Is each axes environment connected to at least one other? %noConn = find(~any(C,2)); %for nc = noConn(:)' % userWarning(m2t, ['The axes environment no. %d is not aligned with',... % ' any other axes environment and will be plotted',... % ' right in the middle.'], nc); %end % Now, actually go ahead and process the info to return Pgfplots alignment % options. % Sort the axes environments by the number of connections they have. % That means: start with the plot which has the most connections. [dummy, IX] = sort(sum(C~=0, 2), 'descend'); %#ok plotOrder = zeros(1,numRelevantHandles); plotNumber = 0; for ix = IX(:)' [plotOrder,plotNumber,alignmentOptions] = ... setOptionsRecursion(plotOrder, plotNumber, C, alignmentOptions, ix, []); end % Burkart, July 23, 2011: % Now let's rearrange the plot order. % Theoretically this should be harmful in that it would result in % subplots that refer to another named subplot to be drawn before the % named subplot itself is drawn. However, this reordering actually fixes % one such problem that only occurred in Octave with test case % subplot2x2b. Oddly enough the error only showed when certain other test % cases (including subplot2x2b itself) had been run beforehand and not if % subplot2x2b was the first / only test case to be run or if a harmless % test case like one_point preceded subplot2x2b. % The exact mechanism that led to this bug was not uncovered but a % differently ordered axesPos near the top of this function eventually % led to the wrong plotOrder and thus to a subplot referring to one that % came later in the TikZ output. % The reordering was tested against the test suite and didn't break any % of the test cases, neither on Octave nor on MATLAB. newPlotOrder = zeros(1,numRelevantHandles); for k = 1:numRelevantHandles newPlotOrder(plotOrder(k)) = k; end plotOrder = newPlotOrder; end % ----------------------------------------------------------------------- % sets the alignment options for a specific node % and passes on the its children % ----------------------------------------------------------------------- function [plotOrder, plotNumber, alignmentOptions] = setOptionsRecursion(plotOrder, plotNumber, C, alignmentOptions, k, parent) % return immediately if is has been processed before if plotOrder(k) return end plotNumber = plotNumber + 1; % TODO not looking at twins is probably not the right thing to do % find the non-zero elements in the k-th row unprocessedFriends = find(C(k,:)~=0 & ~plotOrder); unprocessedChildren = unprocessedFriends(abs(C(k,unprocessedFriends))~=5); unprocessedTwins = unprocessedFriends(abs(C(k,unprocessedFriends))==5); if ~isempty(unprocessedChildren) % Are there unprocessed children? % Give these axes a name. alignmentOptions(k).opts = ... addToOptions(alignmentOptions(k).opts, 'name', sprintf('plot%d', k)); end if ~isempty(parent) % if a parent is given if (abs(C(parent,k))==5) % don't apply "at=" for younger twins else % See were this node sits with respect to its parent, % and adapt the option accordingly. anchor = cornerCode2pgfplotOption(C(k,parent)); refPos = cornerCode2pgfplotOption(C(parent,k)); % add the option alignmentOptions(k).opts = ... addToOptions(alignmentOptions(k).opts, 'at', sprintf('(plot%d.%s)', parent, refPos)); alignmentOptions(k).opts = ... addToOptions(alignmentOptions(k).opts, 'anchor', anchor); end end plotOrder(k) = plotNumber; % Recursively loop over all dependent 'child' axes; % first the twins, though, to make sure they appear consecutively % in the TikZ file. for ii = unprocessedTwins [plotOrder,plotNumber,alignmentOptions] = setOptionsRecursion(plotOrder, plotNumber, C, alignmentOptions, ii, k); end for ii = unprocessedChildren [plotOrder,plotNumber,alignmentOptions] = setOptionsRecursion(plotOrder, plotNumber, C, alignmentOptions, ii, k); end end % ========================================================================= % translates the corner code in a real option to Pgfplots function pgfOpt = cornerCode2pgfplotOption(code) switch code case 1 pgfOpt = 'right of south east'; case 2 pgfOpt = 'right of north east'; case 3 pgfOpt = 'above north west'; case 4 pgfOpt = 'above north east'; case -1 pgfOpt = 'left of south west'; case -2 pgfOpt = 'left of north west'; case -3 pgfOpt = 'below south west'; case -4 pgfOpt = 'below south east'; otherwise error('cornerCode2pgfplotOption:unknRelCode',... 'Illegal alignment code %d.', code); end end % ========================================================================= function refAxesId = getReferenceAxes(loc, colBarPos, axesHandlesPos) % if there is only one axes reference handle, it must be the parent if size(axesHandlesPos,1) == 1 refAxesId = 1; return; end % MATLAB(R)'s keywords are camel cased (e.g., 'NorthOutside'), in Octave % small cased ('northoutside'). Hence, use lower() for uniformity. switch lower(loc) case { 'north', 'south', 'east', 'west' } userWarning(m2t, 'Don''t know how to deal with inner colorbars yet.'); return; case {'northoutside'} % scan in 'axesHandlesPos' for the handle number that lies % directly below colBarHandle [m,refAxesId] = min(colBarPos(2) ... - axesHandlesPos(axesHandlesPos(:,4)colBarPos(4),2)... - colBarPos(4)); %#ok case {'eastoutside'} % scan in 'axesHandlesPos' for the handle number that lies % directly left of colBarHandle [m,refAxesId] = min(colBarPos(1) ... - axesHandlesPos(axesHandlesPos(:,3)colBarPos(3),1) ... - colBarPos(3) ); %#ok otherwise error('getReferenceAxes:illLocation', ... 'Illegal ''Location'' ''%s''.', loc ); end end % ========================================================================= function userInfo(m2t, message, varargin) % Display usage information. if ~m2t.cmdOpts.Results.showInfo return end mess = sprintf(message, varargin{:}); % Replace '\n' by '\n *** ' and print. mess = strrep(mess, sprintf('\n'), sprintf('\n *** ')); fprintf(' *** %s\n', mess); end % ========================================================================= function userWarning(m2t, message, varargin) % Drop-in replacement for warning(). if ~m2t.cmdOpts.Results.showWarnings return end warning('matlab2tikz:userWarning', message, varargin{:}); end % ========================================================================= function parent = addChildren(parent, children) if isempty(children) return; end if iscell(children) for k = 1:length(children) parent = addChildren(parent, children{k}); end else if isempty(parent.children) parent.children = {children}; else parent.children = {parent.children{:} children}; end end end % ========================================================================= function printAll(m2t, env, fid) if isfield(env, 'colors') && ~isempty(env.colors) fprintf(fid, '%s', env.colors); end if isempty(env.options) fprintf(fid, '\\begin{%s}\n', env.name); else fprintf(fid, '\\begin{%s}[%%\n%s\n]\n', env.name, prettyprintOpts(m2t, env.options, sprintf(',\n'))); end for item = env.content fprintf(fid, '%s', char(item)); end for k = 1:length(env.children) if ischar(env.children{k}) fprintf(fid, escapeCharacters(env.children{k})); else fprintf(fid, '\n'); printAll(m2t, env.children{k}, fid); end end % End the tikzpicture environment with an empty comment and no newline % so no additional space is generated by the tikzpicture in TeX. % This is useful if something should immediately follow the picture, % e.g. another picture, with a separately defined spacing or without % any spacing at all between both pictures. if strcmp(env.name, 'tikzpicture') fprintf(fid, '\\end{%s}%%', env.name); else fprintf(fid, '\\end{%s}\n', env.name); end end % ========================================================================= function imwriteWrapperPNG(colorData, cmap, fileName) % Write an indexed or a truecolor image % Don't use ismatrix(), cf. . if (ndims(colorData) == 2) % According to imwrite's documentation there is support for 1-bit, % 2-bit, 4-bit and 8-bit (i.e., 256 colors) indexed images only. % When having more colors, a truecolor image must be generated and % used instead. if size(cmap, 1) <= 256 imwrite(colorData, cmap, fileName, 'png'); else imwrite(ind2rgb(colorData, cmap), fileName, 'png'); end else imwrite(colorData, fileName, 'png'); end end % ========================================================================= function c = prettyPrint(m2t, strings, interpreter) % Some resources on how MATLAB handles rich (TeX) markup: % http://www.mathworks.com/help/techdoc/ref/text_props.html#String % http://www.mathworks.com/help/techdoc/creating_plots/f0-4741.html#f0-28104 % http://www.mathworks.com/help/techdoc/ref/text_props.html#Interpreter % http://www.mathworks.com/help/techdoc/ref/text.html#f68-481120 % Multiline handling. % Make sure that the input string is really a cellstr that contains only % one-line strings. if ischar(strings) strings = cellstr(strings); elseif iscellstr(strings) cs = {}; for s = strings tmp = cellstr(s); cs = {cs{:}, tmp{:}}; end strings = cs; else error('matlab2tikz:prettyPrint', 'Data type not understood.'); end % Now loop over the strings and return them pretty-printed in c. c = {}; for s = strings % If the user set the matlab2tikz parameter 'parseStrings' to false, no % parsing of strings takes place, thus making the user 100% responsible. if ~m2t.cmdOpts.Results.parseStrings c = strings; return end % Make sure we have a valid interpreter set up if ~any(strcmpi(interpreter, {'latex', 'tex', 'none'})) userWarning(m2t, 'Don''t know interpreter ''%s''. Default handling.', interpreter); interpreter = 'tex'; end % The interpreter property of the text element defines how the string % is parsed switch lower(interpreter) case 'latex' % Basic subset of the LaTeX markup language % Replace $$...$$ with $...$ but otherwise leave untouched string = regexprep(s, '^\$\$(.*)\$\$$', '$$1$'); case 'tex' % Subset of plain TeX markup language % Deal with UTF8 characters. string = s; string = strrep(string, '°', '\circ'); string = strrep(string, '∞', '\infty'); % Parse string piece-wise in a separate function. string = parseTexString(m2t, string); case 'none' % Literal characters % Make special characters TeX compatible string = strrep(s, '\', '\textbackslash{}'); % Note: '{' and '}' can't be converted to '\{' and '\}', % respectively, via strrep(...) as this would lead to % backslashes converted to '\textbackslash\{\}' because % the backslash was converted to '\textbackslash{}' in % the previous step. Using regular expressions with % negative look-behind makes sure any braces in 'string' % were not introduced by escaped backslashes. % Also keep in mind that escaping braces before backslashes % would not remedy the issue -- in that case 'string' would % contain backslashes introduced by brace escaping that are % not supposed to be printable characters. repl = switchMatOct(m2t, '\\{', '\{'); string = regexprep(string, '(?= sCmd(i) & bracesPos <= eCmd(i)) = []; end % Exclude braces that are preceded by an odd number of backslashes which % means the brace is escaped and thus to be printed, not a grouping brace expr = '(? $ \text {(non-}) } $<-end % ...or when the parsed string is empty parsed = regexprep(parsed, '^\$\$$', ''); end % ========================================================================= function string = parseTexSubstring(m2t, string) % Keep a copy of the original input string for potential warning messages % referring to the string as it was originally used in MATLAB/Octave and % not the current value of the variable 'string' halfway into the m2t % conversion. origstr = string; % Font families (italic, bold, etc.) get a trailing '{}' because in % MATLAB they may be followed by a letter which would produce an error % in (La)TeX. for i = {'it', 'bf', 'rm', 'sl'} string = strrep(string, ['\' i{:}], ['\' i{:} '{}']); end % The same holds true for special characters like \alpha % The list of MATLAB-supported TeX characters was taken from % http://www.mathworks.com/help/techdoc/ref/text_props.html#String named = {'alpha', 'angle', 'ast', 'beta', 'gamma', 'delta', ... 'epsilon', 'zeta', 'eta', 'theta', 'vartheta', 'iota', ... 'kappa', 'lambda', 'mu', 'nu', 'xi', 'pi', 'rho', ... 'sigma', 'varsigma', 'tau', 'equiv', 'Im', 'otimes', ... 'cap', 'int', 'rfloor', 'lfloor', 'perp', 'wedge', ... 'rceil', 'vee', 'langle', 'upsilon', 'phi', 'chi', ... 'psi', 'omega', 'Gamma', 'Delta', 'Theta', 'Lambda', ... 'Xi', 'Pi', 'Sigma', 'Upsilon', 'Phi', 'Psi', 'Omega', ... 'forall', 'exists', 'ni', 'cong', 'approx', 'Re', ... 'oplus', 'cup', 'subseteq', 'lceil', 'cdot', 'neg', ... 'times', 'surd', 'varpi', 'rangle', 'sim', 'leq', ... 'infty', 'clubsuit', 'diamondsuit', 'heartsuit', ... 'spadesuit', 'leftrightarrow', 'leftarrow', ... 'Leftarrow', 'uparrow', 'rightarrow', 'Rightarrow', ... 'downarrow', 'circ', 'pm', 'geq', 'propto', 'partial', ... 'bullet', 'div', 'neq', 'aleph', 'wp', 'oslash', ... 'supseteq', 'nabla', 'ldots', 'prime', '0', 'mid', ... 'copyright' }; for i = named string = strrep(string, ['\' i{:}], ['\' i{:} '{}']); % FIXME: Only append '{}' if there's an odd number of backslashes % in front of the items from 'named'. If it's an even % number instead, that means there's an escaped (printable) % backslash and some text like "alpha" after that. end % Some special characters' names are subsets of others, e.g. '\o' is % a subset of '\omega'. This would produce undesired double-escapes. % For example if '\o' was converted to '\o{}' after '\omega' has been % converted to '\omega{}' this would result in '\o{}mega{}' instead of % '\omega{}'. Had '\o' been converted to '\o{}' _before_ '\omega' is % converted then the result would be '\o{}mega' and thus also wrong. % To circumvent the problem all those special character names that are % subsets of others are now converted using a regular expression that % uses negative lookahead. The special handling of the backslash is % required for MATLAB/Octave compatibility. string = regexprep(string, '(\\)o(?!mega|times|plus|slash)', '$1o{}'); string = regexprep(string, '(\\)in(?!t|fty)', '$1in{}'); string = regexprep(string, '(\\)subset(?!eq)', '$1subset{}'); string = regexprep(string, '(\\)supset(?!eq)', '$1supset{}'); % Convert '\0{}' (TeX text mode) to '\emptyset{}' (TeX math mode) string = strrep(string, '\0{}', '\emptyset{}'); % Add skip to \fontsize % This is required for a successful LaTeX run on the output as in contrast % to MATLAB/Octave it requires the skip parameter (even if it's zero) string = regexprep(string, '(\\fontsize\{[^}]*\})', '$1{0}'); % Put '\o{}' inside \text{...} as it is a text mode symbol that does not % exist in math mode (and LaTeX gives a warning if you use it in math mode) string = strrep(string, '\o{}', '\text{\o{}}'); % Put everything that isn't a TeX command inside \text{...} expr = '(\\[a-zA-Z]+(\[[^\]]*\])?(\{[^}]*\}){1,2})'; % |( \cmd )( [...]? )( {...}{1,2} )| % ( subset $1 ) repl = switchMatOct(m2t, '}$1\\text{', '}$1\text{'); string = regexprep(string, expr, repl); % ...\alpha{}... -> ...}\alpha{}\text{... string = ['\text{' string '}']; % ...}\alpha{}\text{... -> \text{...}\alpha{}\text{...} % '_' has to be in math mode so long as it's not escaped as '\_' in which % case it remains as-is. Extra care has to be taken to make sure any % backslashes in front of the underscore are not themselves escaped and % thus printable backslashes. This is the case if there's an even number % of backslashes in a row. repl = switchMatOct(m2t, '$1}_\\text{', '$1}_\text{'); string = regexprep(string, '(? 'abc ef' % 'abc&\deltaef' -> 'abc ef' % 'abc&$ef' -> 'abc ef' % 'abcdef&' -> 'abcdef' % Don't remove closing brace after '&' as this would result in % unbalanced braces string = regexprep(string, '(? '..._\$\text{bc}'. % Note that the problem does not occur for the majority of special characters % like '\alpha' because they use math mode and therefore are never inside a % \text{...} block to begin with. This means that the number of special % characters affected by this issue is actually quite small: % $ # % & _ { } \o § ~ \ ^ expr = ['(_|\^)(\\text)\{([^}\\]|\\\$|\\#|\\%|\\&|\\_|\\\{|\\\}|', ... ... % (_/^)(\text) {(non-}\| \$ | \#| \%| \&| \_| \{ | \} | ... % ($1)( $2 ) ( $3 -> '\\o\{\}|\\S\{\}|\\textasciitilde\{\}|\\textbackslash\{\}|', ... ... % \o{} | \S{} | \textasciitilde{} | \textbackslash{} | ... % <- $3 -> '\\textasciicircum\{\})']; % \textasciicircum{} ) % <- $3 ) string = regexprep(string, expr, '$1$2{$3}$2{'); % Some further processing makes the output behave more like TeX math mode, % but only if the matlab2tikz parameter parseStringsAsMath=true. if m2t.cmdOpts.Results.parseStringsAsMath % Some characters should be in math mode: =-+/,.()<>0-9 expr = '(\\text)\{([^}=\-+/,.()<>0-9]*)([=\-+/,.()<>0-9]+)([^}]*)\}'; % \text {(any non-"x"/'}'char)( any "x" char )(non-}) } % ( $1 ) ( $2 )( $3 )( $4) while regexp(string, expr) % Iterating is necessary to catch all occurrences. See above. string = regexprep(string, expr, '$1{$2}$3$1{$4}'); end % \text{ } should be a math-mode space string = regexprep(string, '\\text\{(\s+)}', '$1'); % '<<' probably means 'much smaller than', i.e. '\ll' repl = switchMatOct(m2t, '$1\\ll{}$2', '$1\ll{}$2'); string = regexprep(string, '([^<])<<([^<])', repl); % Single letters are most likely variables and thus should be in math mode string = regexprep(string, '\\text\{([a-zA-Z])\}', '$1'); end % parseStringsAsMath % Clean up: remove empty \text{} string = strrep(string, '\text{}', ''); % \text{}\alpha{}\text{...} -> \alpha{}\text{...} % Clean up: convert '{}\' to '\' unless it's prefixed by a backslash which % means the opening brace is escaped and thus a printable character instead % of a grouping brace. string = regexprep(string, '(? \alpha\text{...} % Clean up: convert '{}}' to '}' unless it's prefixed by a backslash string = regexprep(string, '(? vB(i) isBelow = false; break; elseif vA(i) < vB(i) isBelow = true; break end end end % ========================================================================= function arr = versionArray(env, str) % Converts a version string to an array. if ischar(str) % Translate version string from '2.62.8.1' to [2, 62, 8, 1]. switch env case 'MATLAB' split = regexp(str, '\.', 'split'); case 'Octave' split = strsplit(str, '.'); otherwise errorUnknownEnvironment(); end arr = str2num(char(split)); %#ok else arr = str; end end % ========================================================================= function [retval] = switchMatOct(m2t, matlabValue, octaveValue) % Returns one of two provided values depending on whether matlab2tikz is % run on MATLAB or on Octave. switch m2t.env case 'MATLAB' retval = matlabValue; case 'Octave' retval = octaveValue; otherwise errorUnknownEnvironment(); end end % ========================================================================= function checkDeprecatedEnvironment(m2t, minimalVersions) if isempty(m2t.envVersion) warning('matlab2tikz:cannotDetermineEnvironment',... 'Could not determine environment version. Continuing and hoping for the best.'); else if isfield(minimalVersions, m2t.env) minVersion = minimalVersions.(m2t.env); envWithVersion = sprintf('%s %s',m2t.env, minVersion.name); if isVersionBelow(m2t.env, m2t.envVersion, minVersion.num) warningMessage = ['\n',... '================================================================================\n\n', ... ' matlab2tikz is tested and developed on %s and\n', ... ' later versions of %s.\n', ... ' This script may still be able to handle your plots, but if you\n', ... ' hit a bug, please consider upgrading your environment first.\n', ... '\n', ... ' Every time you submit a bug report with a deprecated environment...\n', ... ' God kills a kitten.\n', ... '\n', ... '================================================================================']; warning('matlab2tikz:deprecatedEnvironment',warningMessage, ... envWithVersion, m2t.env); end else errorUnknownEnvironment(); end end end % ========================================================================= function errorUnknownEnvironment() error('matlab2tikz:unknownEnvironment',... 'Unknown environment. Need MATLAB(R) or Octave.') end % ========================================================================= function [formatted,treeish] = VersionControlIdentifier() % This function gives the (git) commit ID of matlab2tikz % % This assumes the standard directory structure as used by Nico's master branch: % SOMEPATH/src/matlab2tikz.m with a .git directory in SOMEPATH. % % The HEAD of that repository is determined from file information % only (i.e. git doesn't have to be installed at the user side): in git, a % branch file just contains a tree-ish (commit hash OR dynamic reference) % % When the tree-ish is a dynamic reference (ref:refs/heads/master), % this reference is followed as to obtain an absolute tree-ish (hash). maxIter = 10; % stop following dynamic references after a while refPrefix = 'ref:'; try % get the matlab2tikz directory m2tDir = fileparts(mfilename('fullpath')); gitDir = fullfile(m2tDir,'..','.git'); treeish = [refPrefix,'HEAD']; formatted = ''; nIter = 1; while any(strfind(treeish, refPrefix)) && nIter < maxIter refName = treeish(numel(refPrefix)+1:end); branchFile = fullfile(gitDir, refName); if exist(branchFile, 'file') fid = fopen(branchFile,'r'); treeish = fscanf(fid,'%s'); fclose(fid); else treeish = ''; return; end nIter = nIter + 1; end if nIter >= maxIter treeish = ''; return; end catch %#ok treeish = ''; end if ~isempty(treeish) formatted = sprintf('(commit %s)',treeish); end end % ========================================================================= matlab2tikz-0.4.4/src/matlab2tikzInputParser.m000066400000000000000000000222121226131721500213300ustar00rootroot00000000000000function parser = matlab2tikzInputParser() %MATLAB2TIKZINPUTPARSER Input parsing for matlab2tikz.. % This implementation exists because Octave is lacking one. % Copyright (c) 2008--2013 Nico Schlömer % All rights reserved. % % Redistribution and use in source and binary forms, with or without % modification, are permitted provided that the following conditions are % met: % % * Redistributions of source code must retain the above copyright % notice, this list of conditions and the following disclaimer. % * Redistributions in binary form must reproduce the above copyright % notice, this list of conditions and the following disclaimer in % the documentation and/or other materials provided with the distribution % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % ========================================================================= % Initialize the structure. parser = struct (); % Public Properties parser.Results = {}; % Enabel/disable parameters case sensitivity. parser.CaseSensitive = false; % Keep parameters not defined by the constructor. parser.KeepUnmatched = false; % Enable/disable warning for parameters not defined by the constructor. parser.WarnUnmatched = true; % Enable/disable passing arguments in a structure. parser.StructExpand = true; % Names of parameters defined in input parser constructor. parser.Parameters = {}; % Names of parameters not defined in the constructor. parser.Unmatched = struct (); % Names of parameters using default values. parser.UsingDefaults = {}; % Names of deprecated parameters and their alternatives parser.DeprecatedParameters = struct(); % Handles for functions that act on the object. parser.addRequired = @addRequired; parser.addOptional = @addOptional; parser.addParamValue = @addParamValue; parser.deprecateParam = @deprecateParam; parser.parse = @parse; % Initialize the parser plan parser.plan = {}; end % ========================================================================= function p = parser_plan (q, arg_type, name, default, validator) p = q; plan = p.plan; if (isempty (plan)) plan = struct (); n = 1; else n = numel (plan) + 1; end plan(n).type = arg_type; plan(n).name = name; plan(n).default = default; plan(n).validator = validator; p.plan = plan; end % ========================================================================= function p = addRequired (p, name, validator) p = parser_plan (p, 'required', name, [], validator); end % ========================================================================= function p = addOptional (p, name, default, validator) p = parser_plan (p, 'optional', name, default, validator); end % ========================================================================= function p = addParamValue (p, name, default, validator) p = parser_plan (p, 'paramvalue', name, default, validator); end % ========================================================================= function p = deprecateParam (p, name, alternatives) if isempty(alternatives) alternatives = {}; elseif ischar(alternatives) alternatives = {alternatives}; % make cellstr elseif ~iscellstr(alternatives) error('matlab2tikzInputParser:BadAlternatives',... 'Alternatives for a deprecated parameter must be a char or cellstr'); end p.DeprecatedParameters.(name) = alternatives; end % ========================================================================= function p = parse (p, varargin) plan = p.plan; results = p.Results; using_defaults = {}; if (p.CaseSensitive) name_cmp = @strcmp; else name_cmp = @strcmpi; end if (p.StructExpand) k = find (cellfun (@isstruct, varargin)); for m = numel(k):-1:1 n = k(m); s = varargin{n}; c = [fieldnames(s).'; struct2cell(s).']; c = c(:).'; if (n > 1 && n < numel (varargin)) varargin = horzcat (varargin(1:n-1), c, varargin(n+1:end)); elseif (numel (varargin) == 1) varargin = c; elseif (n == 1); varargin = horzcat (c, varargin(n+1:end)); else % n == numel (varargin) varargin = horzcat (varargin(1:n-1), c); end end end if (isempty (results)) results = struct (); end type = {plan.type}; n = find( strcmp( type, 'paramvalue' ) ); m = setdiff (1:numel( plan ), n ); plan = plan ([n,m]); for n = 1 : numel (plan) found = false; results.(plan(n).name) = plan(n).default; if (~ isempty (varargin)) switch plan(n).type case 'required' found = true; if (strcmpi (varargin{1}, plan(n).name)) varargin(1) = []; end value = varargin{1}; varargin(1) = []; case 'optional' m = find (cellfun (@ischar, varargin)); k = find (name_cmp (plan(n).name, varargin(m))); if (isempty (k) && validate_arg (plan(n).validator, varargin{1})) found = true; value = varargin{1}; varargin(1) = []; elseif (~ isempty (k)) m = m(k); found = true; value = varargin{max(m)+1}; varargin(union(m,m+1)) = []; end case 'paramvalue' m = find( cellfun (@ischar, varargin) ); k = find (name_cmp (plan(n).name, varargin(m))); if (~ isempty (k)) found = true; m = m(k); value = varargin{max(m)+1}; varargin(union(m,m+1)) = []; end otherwise error( sprintf ('%s:parse', mfilename), ... 'parse (%s): Invalid argument type.', mfilename ... ) end end if (found) if (validate_arg (plan(n).validator, value)) results.(plan(n).name) = value; else error( sprintf ('%s:invalidinput', mfilename), ... '%s: Input argument ''%s'' has invalid value.\n', mfilename, plan(n).name ... ); end p.Parameters = union (p.Parameters, {plan(n).name}); elseif (strcmp (plan(n).type, 'required')) error( sprintf ('%s:missinginput', mfilename), ... '%s: input ''%s'' is missing.\n', mfilename, plan(n).name ... ); else using_defaults = union (using_defaults, {plan(n).name}); end end if ~isempty(varargin) % Include properties that do not match specified properties for n = 1:2:numel(varargin) if ischar(varargin{n}) if p.KeepUnmatched results.(varargin{n}) = varargin{n+1}; end if p.WarnUnmatched warning(sprintf('%s:unmatchedArgument',mfilename), ... 'Ignoring unknown argument "%s"', varargin{n}); end p.Unmatched.(varargin{n}) = varargin{n+1}; else error (sprintf ('%s:invalidinput', mfilename), ... '%s: invalid input', mfilename) end end end % Store the results of the parsing p.Results = results; p.UsingDefaults = using_defaults; warnForDeprecatedParameters(p); end % ========================================================================= function result = validate_arg (validator, arg) try result = validator (arg); catch %#ok result = false; end end % ========================================================================= function warnForDeprecatedParameters(p) usedDeprecatedParameters = intersect(p.Parameters, fieldnames(p.DeprecatedParameters)); for iParam = 1:numel(usedDeprecatedParameters) oldParameter = usedDeprecatedParameters{iParam}; alternatives = p.DeprecatedParameters.(oldParameter); switch numel(alternatives) case 0 replacements = ''; case 1 replacements = ['''' alternatives{1} '''']; otherwise replacements = deblank(sprintf('''%s'' and ',alternatives{:})); replacements = regexprep(replacements,' and$',''); end if ~isempty(replacements) replacements = sprintf('From now on, please use %s to control the output.\n',replacements); end message = ['\n===============================================================================\n', ... 'You are using the deprecated parameter ''%s''.\n', ... '%s', ... '===============================================================================']; warning('matlab2tikz:deprecatedParameter', ... message, oldParameter, replacements); end endmatlab2tikz-0.4.4/src/updater.m000066400000000000000000000131331226131721500163550ustar00rootroot00000000000000function updater(name, fileExchangeUrl, version, verbose, env) %UPDATER Auto-update matlab2tikz. % Only for internal usage. % Copyright (c) 2012--2013, Nico Schlömer % All rights reserved. % % Redistribution and use in source and binary forms, with or without % modification, are permitted provided that the following conditions are % met: % % * Redistributions of source code must retain the above copyright % notice, this list of conditions and the following disclaimer. % * Redistributions in binary form must reproduce the above copyright % notice, this list of conditions and the following disclaimer in % the documentation and/or other materials provided with the distribution % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % ========================================================================= try html = urlread([fileExchangeUrl, '/all_files']); catch %#ok % Couldn't load the URL -- never mind. html = ''; end % Search for a string "/version-1.6.3" in the HTML. This assumes % that the package author has added a file by that name to % to package. This is a rather dirty hack around FileExchange's % lack of native versioning information. mostRecentVersion = regexp(html, '/version-(\d+\.\d+\.\d+)', 'tokens'); if ~isempty(mostRecentVersion) if isVersionBelow(env, version, mostRecentVersion{1}{1}) userInfo(verbose, '**********************************************\n'); userInfo(verbose, 'New version available! (%s)\n', mostRecentVersion{1}{1}); userInfo(verbose, '**********************************************\n'); reply = input([' *** Would you like ', name, ' to self-upgrade? y/n [n]:'],'s'); if strcmp(reply, 'y') % Download the files and unzip its contents into the folder % above the folder that contains the current script. % This assumes that the file structure is something like % % src/matlab2tikz.m % src/[...] % AUTHORS % ChangeLog % [...] % % on the hard drive and the zip file. In particular, this assumes % that the folder on the hard drive is writable by the user % and that matlab2tikz.m is not symlinked from some other place. pathstr = fileparts(mfilename('fullpath')); targetPath = [pathstr, filesep, '..', filesep]; userInfo(verbose, ['Downloading and unzipping to ', targetPath, '...']); upgradeSuccess = false; try unzippedFiles = unzip([fileExchangeUrl, '?download=true'], targetPath); upgradeSuccess = true; %~isempty(unzippedFiles); userInfo(verbose, 'done.'); catch userInfo(verbose, 'FAILED.'); end if upgradeSuccess % TODO explicitly delete all of the old content % Delete old version number file. versionFile = [pathstr, filesep, 'version-', version]; if exist(versionFile, 'file') == 2 delete(versionFile); end % TODO anything better than error()? error('Upgrade successful. Please re-execute.'); else error('Upgrade failed.'); end end userInfo(verbose, ''); end end end % ========================================================================= function isBelow = isVersionBelow(env, versionA, versionB) % Checks if version string or vector versionA is smaller than % version string or vector versionB. vA = versionArray(env, versionA); vB = versionArray(env, versionB); isBelow = false; for i = 1:min(length(vA), length(vB)) if vA(i) > vB(i) isBelow = false; break; elseif vA(i) < vB(i) isBelow = true; break end end end % ========================================================================= function arr = versionArray(env, str) % Converts a version string to an array, e.g., % '2.62.8.1' to [2, 62, 8, 1]. if ischar(str) if strcmpi(env, 'MATLAB') split = regexp(str, '\.', 'split'); elseif strcmpi(env, 'Octave') split = strsplit(str, '.'); end arr = str2num(char(split)); %#ok else arr = str; end end % ========================================================================= function userInfo(verbose, message, varargin) % Display usage information. if ~verbose return end mess = sprintf(message, varargin{:}); % Replace '\n' by '\n *** ' and print. mess = strrep( mess, sprintf('\n'), sprintf('\n *** ') ); fprintf( ' *** %s\n', mess ); end % ========================================================================= matlab2tikz-0.4.4/test/000077500000000000000000000000001226131721500147225ustar00rootroot00000000000000matlab2tikz-0.4.4/test/README000066400000000000000000000020551226131721500156040ustar00rootroot00000000000000This test module is part of matlab2tikz. It provides the means for easily comparing the results of a direct PDF print of a figure in MATLAB as opposed to having it exported by matlab2tikz. As a matter of fact, this test suite can take any matlab2xxx-converter as argument (see step 2 below) with possibly minor modifications to the LaTeX file output. ======= USAGE: ======= 1.) Open MATLAB, make matlab2tikz and matlab2tikz_acidtest available for calling (by putting in the MATLAB Path,for example). 2.) Call the script by >> matlab2tikz_acidtest( @matlab2tikz ); What happens it that MATLAB generates a number of figures as defined in testfunctions.m, and exports them as PDF (using the print command) and by matlab2tikz. At the same time, a LaTeX file is created in the tex-subfolder. 3.) You can compile 'tex/acid.tex' with 'make' (making use of 'tex/Makefile'). If all goes well, the result will be the file 'tex/acid.pdf' which contains a list of the test figures, exported as PDF and right next to it the matlab2tikz generated plot. matlab2tikz-0.4.4/test/data/000077500000000000000000000000001226131721500156335ustar00rootroot00000000000000matlab2tikz-0.4.4/test/data/.gitignore000066400000000000000000000003571226131721500176300ustar00rootroot00000000000000test*-reference.pdf test*-reference.eps test*-converted* # exclude files generated by test suite !.gitignore # git cannot presently store empty directories, so committing the # .gitignore file makes sure the directory isn't actually empty matlab2tikz-0.4.4/test/eps2pdf.m000066400000000000000000000247331226131721500164540ustar00rootroot00000000000000function [result,msg] = eps2pdf(epsFile,fullGsPath,orientation) %EPS2PDF Converts an eps file to a pdf file using GhostScript (GS) % % [result,msg] = eps2pdf(epsFile,fullGsPath,orientation) % % - epsFile: eps file name to be converted to pdf file % - fullGsPath: (optional) FULL GS path, including the file name, to % the GS executable (on win32 it could be c:\program % files\gs\gs8.14\bin\gswin32c.exe). The existence for % fullGsPath will be checked for if given. On the other % hand, if fullGsPath is not given or empty it defaults % to 'gswin32c' for pcs and 'gs' for unix and the % existence will not be checked for. But in this, latter % case, GS's path must be in the system's path variable. % - orientation: (optional) a flag that tells how the orientation tag in eps file should be treated % just before the conversion (orientation tag is changed or even removed): % 0 -> no change (default) % 1 -> flip orientation % 2 -> remove orientation % % - result: 0 if ok, anything else otherwise % - msg: resulting status on file being processed % % NOTES: GhostScript is needed for this function to work. Orientation can % also be changed - use this only if you have problems with the orientation - in % such a case try with orientation=1 first and then orientation=2 if the first option is % not the right one. % % EPS2PDF converts an existing EPS file to a PDF file using Ghostscript. EPS2PDF % reads an eps file, modifies the bounding box and creates a pdf file whose size % is determined by the bounding box and not by the paper size. This can not be % accomplished by using Ghostscript only. So, all that one needs is of course % Matlab and Ghostscript drivers. % % This tool is especially suited for LaTeX (TeX) users who want to create pdf % documents on the fly (by including pdf graphics and using either pdftex or % pdflatex). An example would be, if you are using LaTeX (TeX) to typeset % documents then the usual (simple) way to include graphics is to include eps % graphics using for example (if there exists myfigure.eps) % \begin{figure} % \centering % \includegraphics[scale=0.8]{myfigure}\\ % \caption{some caption.} % \end{figure} % To use pdflatex (pdftex) you do not need to change anything but provide another % file myfigure.pdf in the same directory along with myfigure.eps. And this file, % of course, can be generated by EPS2PDF. % % This function was tested on win32 system running Matlab R13sp1. It should work % on all platforms, if not, contact the author. % % SOURCE: The original idea came from the "eps-to-pdf" converter written in perl by Sebastian Rahtz % % Primoz Cermelj, 24.08.2004 % (c) Primoz Cermelj, primoz.cermelj@email.si % % Version: 0.9.3 % Last revision: 04.10.2004 %-------------------------------------------------------------------------- global epsFileContent if ispc [dummy,DEF_GS_PATH] = system('where gswin*c.exe'); DEF_GS_PATH = DEF_GS_PATH(end-12:end-1); else DEF_GS_PATH = 'gs'; end GS_PARAMETERS = '-q -dNOPAUSE -dBATCH -dDOINTERPOLATE -dUseFlateCompression=true -sDEVICE=pdfwrite -r1200'; narginchk(1,3); if nargin < 2 || isempty(fullGsPath) fullGsPath = DEF_GS_PATH; else if ~exist(fullGsPath,'dir') status = ['Ghostscript executable could not be found: ' fullGsPath]; if nargout, result = 1; end; if nargout > 1, msg = status; else disp(status); end; return end end if nargin < 3 || isempty(orientation) orientation = 0; end orientation = abs(round(orientation)); orientation = orientation(1); if orientation < 0 || orientation > 2 orientation = 0; end epsFileContent = []; %--------- % Get file name, path %--------- source = epsFile; [pathstr,sourceName,ext] = fileparts(source); if isempty(pathstr) pathstr = cd; source = fullfile(pathstr,source); end targetName = [sourceName '.pdf']; target = fullfile(pathstr,targetName); % target - pdf file tmpFileName = sourceName; tmpFile = fullfile(pathstr,[tmpFileName ext '.eps2pdf~']); % Create tmp file,... [ok,errStr] = create_tmpepsfile(source,tmpFile,orientation); if ~ok status = ['Error while creating temporary eps file: ' epsFile ' - ' errStr]; if nargout, result = 1; end; if nargout > 1, msg = status; else disp(status); end; else % Run Ghostscript comandLine = ['"' fullGsPath '"' ' ' GS_PARAMETERS ' -sOutputFile=' '"' target '"' ' -f ' '"' tmpFile '"']; [stat, result] = system(comandLine); if stat status = ['pdf file not created - error running Ghostscript - check GS path: ' result]; if nargout, result = 1; end; if nargout > 1, msg = status; else disp(status); end; else status = 'pdf successfully created'; if nargout, result = 0; end; if nargout > 1, msg = status; else disp(status); end; end end % Delete tmp file if exist(tmpFile,'file') delete(tmpFile); end %///////////////////////////////////////////////////////////////////// % SUBFUNCTIONS SECTION %///////////////////////////////////////////////////////////////////// %-------------------------------------------------------------------- function [ok,errStr] = create_tmpepsfile(epsFile,tmpFile,orientation) % Creates tmp eps file - file with refined content global epsFileContent [ok,errStr] = read_epsfilecontent( epsFile ); if ~ok return end [ok,errStr] = update_epsfilecontent( epsFile,orientation ); if ~ok return end fh = fopen(tmpFile,'w'); if fh == -1 errStr = ['Temporary file cannot be created. Check write permissions.']; return end try fwrite(fh,epsFileContent,'char'); % fwrite is faster than fprintf ok = 1; catch errStr = ['Error writing temporary file. Check write permissions.']; end fclose(fh); %-------------------------------------------------------------------- %-------------------------------------------------------------------- function [ok,errStr] = read_epsfilecontent( epsFile ) % Reads the content of the eps file into epsFileContent global epsFileContent ok = 0; errStr = []; fh = fopen(epsFile,'r'); if fh == -1 errStr = ['File: ' epsFile ' cannot be accessed or does not exist']; return end try epsFileContent = fread(fh,'char=>char')'; % fread is faster than fscanf ok = 1; catch errStr = lasterror; end fclose(fh); %-------------------------------------------------------------------- %-------------------------------------------------------------------- function [ok,errStr] = update_epsfilecontent(epsFile,orientation) % Updates eps file by adding some additional information into the header % section concerning the bounding box (BB) global epsFileContent ok = 0; errStr = []; % Read current BB coordinates ind = strfind( lower(epsFileContent), lower('%%BoundingBox:')); if isempty(ind) errStr = ['Cannot find Bounding Box in file: ' epsFile]; return end ii = ind(1) + 14; fromBB = ii; while ~((epsFileContent(ii) == sprintf('\n')) || (epsFileContent(ii) == sprintf('\r')) || (epsFileContent(ii) == '%')) ii = ii + 1; end toBB = ii - 1; coordsStr = epsFileContent(fromBB:toBB); coords = str2num( coordsStr ); if isempty(coords) errStr = ['Error reading BB coordinates from file: ' epsFile]; return end NL = getnl; w = abs(coords(3)-coords(1)); h = abs(coords(4)-coords(2)); % Change the orientation if requested changeOrientation = 0; if orientation ~= 0 ind = strfind( lower(epsFileContent), lower('%%Orientation:')); if ~isempty(ind) ii = ind(1) + 14; fromOR = ii; while ~((epsFileContent(ii) == sprintf('\n')) || (epsFileContent(ii) == sprintf('\r')) || (epsFileContent(ii) == '%')) ii = ii + 1; end toOR = ii - 1; orientStr = strim(epsFileContent(fromOR:toOR)); if ~isempty(orientStr) && orientation == 1 % flip if strfind(lower(orientStr),'landscape') changeOrientation = 1; orientStr = 'Portrait'; elseif strfind(lower(orientStr),'portrait') changeOrientation = 1; orientStr = 'Landscape'; end elseif ~isempty(orientStr) && orientation == 2 % remove if strfind(lower(orientStr),'landscape') || strfind(lower(orientStr),'portrait') changeOrientation = 1; orientStr = ' '; end end end end % Refine the content - add additional information and even change the % orientation addBBContent = [' 0 0 ' int2str(w) ' ' int2str(h) ' ' NL... '<< /PageSize [' int2str(w) ' ' int2str(h) '] >> setpagedevice' NL... 'gsave ' int2str(-coords(1)) ' ' int2str(-coords(2)) ' translate']; if changeOrientation if fromOR > fromBB epsFileContent = [epsFileContent(1:fromBB-1) addBBContent epsFileContent(toBB+1:fromOR-1) orientStr epsFileContent(toOR+1:end)]; else epsFileContent = [epsFileContent(1:fromOR-1) orientStr epsFileContent(toOR+1:fromBB-1) addBBContent epsFileContent(toBB+1:end)]; end else epsFileContent = [epsFileContent(1:fromBB-1) addBBContent epsFileContent(toBB+1:end)]; end ok = 1; %-------------------------------------------------------------------- %-------------------------------------------------------------------- function NL = getnl % Returns new-line string as found from first occurance from epsFileContent global epsFileContent NL = '\r\n'; % default (for Windows systems) ii = 1; len = length(epsFileContent); while ~(epsFileContent(ii)==sprintf('\n') || epsFileContent(ii)==sprintf('\r') || ii 2, if ~isstr(l), l = l(:); end if nargin > 3 if ~isstr(u) u = u(:); end end end else [npt,n] = size(x); end if nargin == 3 if ~isstr(l) u = l; symbol = '-'; else symbol = l; l = y; u = y; y = x; [m,n] = size(y); x(:) = (1:npt)'*ones(1,n);; end end if nargin == 4 if isstr(u), symbol = u; u = l; else symbol = '-'; end end if nargin == 2 l = y; u = y; y = x; [m,n] = size(y); x(:) = (1:npt)'*ones(1,n);; symbol = '-'; end u = abs(u); l = abs(l); if isstr(x) | isstr(y) | isstr(u) | isstr(l) error('Arguments must be numeric.') end if ~isequal(size(x),size(y)) | ~isequal(size(x),size(l)) | ~isequal(size(x),size(u)), error('The sizes of X, Y, L and U must be the same.'); end tee = (max(y(:))-min(y(:)))/100; % make tee .02 x-distance for error bars % changed from errorbar.m xl = x - l; xr = x + u; ytop = y + tee; ybot = y - tee; n = size(y,2); % end change % Plot graph and bars hold_state = ishold; cax = newplot; next = lower(get(cax,'NextPlot')); % build up nan-separated vector for bars % changed from errorbar.m xb = zeros(npt*9,n); xb(1:9:end,:) = xl; xb(2:9:end,:) = xl; xb(3:9:end,:) = NaN; xb(4:9:end,:) = xl; xb(5:9:end,:) = xr; xb(6:9:end,:) = NaN; xb(7:9:end,:) = xr; xb(8:9:end,:) = xr; xb(9:9:end,:) = NaN; yb = zeros(npt*9,n); yb(1:9:end,:) = ytop; yb(2:9:end,:) = ybot; yb(3:9:end,:) = NaN; yb(4:9:end,:) = y; yb(5:9:end,:) = y; yb(6:9:end,:) = NaN; yb(7:9:end,:) = ytop; yb(8:9:end,:) = ybot; yb(9:9:end,:) = NaN; % end change [ls,col,mark,msg] = colstyle(symbol); if ~isempty(msg), error(msg); end symbol = [ls mark col]; % Use marker only on data part esymbol = ['-' col]; % Make sure bars are solid h = plot(xb,yb,esymbol); hold on h = [h;plot(x,y,symbol)]; if ~hold_state, hold off; end if nargout>0, hh = h; end matlab2tikz-0.4.4/test/matlab2tikz_acidtest.m000066400000000000000000000440111226131721500212040ustar00rootroot00000000000000function matlab2tikz_acidtest( varargin ) %MATLAB2TIKZ_ACIDTEST unit test driver for matlab2tikz % Copyright (c) 2008--2013, Nico Schlömer % All rights reserved. % % Redistribution and use in source and binary forms, with or without % modification, are permitted provided that the following conditions are met: % % * Redistributions of source code must retain the above copyright % notice, this list of conditions and the following disclaimer. % * Redistributions in binary form must reproduce the above copyright % notice, this list of conditions and the following disclaimer in % the documentation and/or other materials provided with the distribution % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % % ========================================================================= % In which environment are we? env = getEnvironment(); if ~strcmp( env, 'MATLAB' ) && ~strcmp( env, 'Octave' ) error( 'Unknown environment. Need MATLAB(R) or GNU Octave.' ) end % ----------------------------------------------------------------------- matlab2tikzOpts = matlab2tikzInputParser; matlab2tikzOpts = matlab2tikzOpts.addOptional( matlab2tikzOpts, ... 'testFunctionIndices', ... [], @isfloat ); matlab2tikzOpts = matlab2tikzOpts.parse( matlab2tikzOpts, varargin{:} ); % ----------------------------------------------------------------------- % first, initialize the tex output texfile = 'tex/acid.tex'; fh = fopen( texfile, 'w' ); texfile_init( fh ); % output streams stdout = 1; stderr = 2; % query the number of test functions [dummya, dummyb, dummyc, n] = testfunctions(0); if ~isempty(matlab2tikzOpts.Results.testFunctionIndices) indices = matlab2tikzOpts.Results.testFunctionIndices; % kick out the illegal stuff I = find(indices>=1) & find(indices<=n); indices = indices(I); else indices = 1:n; end ploterrmsg = cell( length(indices), 1 ); tikzerrmsg = cell( length(indices), 1 ); pdferrmsg = cell( length(indices), 1 ); ploterror = false( length(indices), 1 ); tikzerror = false( length(indices), 1 ); pdferror = false( length(indices), 1 ); desc = cell( length(indices), 1 ); funcName = cell( length(indices), 1 ); for k = 1:length(indices) fprintf( stdout, 'Executing test case no. %d...\n', indices(k) ); % open a window fig_handle = figure; % plot the figure try [desc{k}, extraOpts, funcName{k}] = testfunctions( indices(k) ); catch %#ok e = lasterror( 'reset' ); %#ok if ~isempty( e.message ) ploterrmsg{k} = [ ploterrmsg{k}, sprintf( 'error: %s\n', e.message ) ]; end if ~isempty( e.identifier ) ploterrmsg{k} = [ ploterrmsg{k}, sprintf( 'error: %s\n', e.identifier ) ]; end if ~isempty( e.stack ) ploterrmsg{k} = [ ploterrmsg{k}, sprintf( 'error: called from:\n' ) ]; end for j = 1:length( e.stack ) ploterrmsg{k} = [ ploterrmsg{k}, ... sprintf( 'error: %s at line %d, in function %s\n', ... e.stack(j).file, e.stack(j).line, e.stack(j).name ) ]; if isempty(funcName{k}) && ~isempty(regexp(e.stack(j).name, '^testfunctions>','once')) % extract function name funcName{k} = regexprep(e.stack(j).name, '^testfunctions>(.*)', '$1'); end end desc{k} = '\textcolor{red}{Error during plot generation.}'; % When displaying the error message in MATLAB, all backslashes % have to be replaced by two backslashes. This must not, however, % be applied constantly as the string that's saved to the LaTeX % output must have only one backslash. if strcmp( env, 'MATLAB' ) fprintf( stderr, strrep( ploterrmsg{k}, '\', '\\' ) ); else fprintf( stderr, ploterrmsg{k} ); end ploterror(k) = true; end % plot not sucessful if isempty(desc{k}) close( fig_handle ); continue end pdf_file = sprintf( 'data/test%d-reference.pdf' , indices(k) ); eps_file = sprintf( 'data/test%d-reference.eps' , indices(k) ); gen_file = sprintf( 'data/test%d-converted.tex', indices(k) ); tic; % Save reference output as PDF try switch env case 'MATLAB' %% Make the inset tight. %ti = get(gca, 'TightInset'); %set(gca, ... % 'Position', [ti(1) ti(2) 1-ti(3)-ti(1) 1-ti(4)-ti(2)]); %set(gca, 'units', 'centimeters') %pos = get(gca, 'Position'); %ti = get(gca, 'TightInset'); %set(gcf, ... % 'PaperUnits', 'centimeters'); %set(gcf, 'PaperSize', [pos(3)+ti(1)+ti(3) pos(4)+ti(2)+ti(4)]); %set(gcf, 'PaperPositionMode', 'manual'); %set(gcf, 'PaperPosition',[0 0 pos(3)+ti(1)+ti(3) pos(4)+ti(2)+ti(4)]); %print(pdf_file, '-dpdf'); % Create a cropped PDF. % Unfortunately, MATLAB cannot do that directly, so first % create an EPS (which has a tight bounding box) and then % convert it to PDF. print(gcf, '-depsc2', eps_file); eps2pdf(eps_file); %print(gcf, '-dpdf', pdf_file); %savefig( pdf_file, 'pdf' ); case 'Octave' % In Octave, figures are automatically cropped when using print(). print(pdf_file, '-dpdf', '-S415,311', '-r150' ); pause( 1.0 ) otherwise error( 'Unknown environment. Need MATLAB(R) or GNU Octave.' ) end catch %#ok e = lasterror('reset'); %#ok if ~isempty( e.message ) pdferrmsg{k} = [ pdferrmsg{k}, sprintf( 'error: %s\n', e.message ) ]; end if ~isempty( e.identifier ) pdferrmsg{k} = [ pdferrmsg{k}, sprintf( 'error: %s\n', e.identifier ) ]; end if ~isempty( e.stack ) pdferrmsg{k} = [ pdferrmsg{k}, sprintf('error: called from:\n') ]; end for j = 1:length(e.stack) pdferrmsg{k} = [ pdferrmsg{k}, ... sprintf( 'error: %s at line %d, in function %s\n', ... e.stack(j).file, e.stack(j).line, e.stack(j).name ) ]; end % When displaying the error message in MATLAB, all backslashes % have to be replaced by two backslashes. This must not, however, % be applied constantly as the string that's saved to the LaTeX % output must have only one backslash. if strcmp( env, 'MATLAB' ) fprintf( stderr, strrep( pdferrmsg{k}, '\', '\\' ) ); else fprintf( stderr, pdferrmsg{k} ); end pdferror(k) = true; end % now, test matlab2tikz try cleanfigure; matlab2tikz('filename', gen_file, ... 'showInfo', false, ... 'checkForUpdates', false, ... 'relativePngPath', '../data/', ... 'width', '\figurewidth', ... extraOpts{:} ... ); catch %#ok e = lasterror('reset'); %#ok if ~isempty( e.message ) tikzerrmsg{k} = [ tikzerrmsg{k}, sprintf( 'error: %s\n', e.message ) ]; end if ~isempty( e.identifier ) tikzerrmsg{k} = [ tikzerrmsg{k}, sprintf( 'error: %s\n', e.identifier ) ]; end if ~isempty( e.stack ) tikzerrmsg{k} = [ tikzerrmsg{k}, sprintf('error: called from:\n') ]; end for j = 1:length(e.stack) tikzerrmsg{k} = [ tikzerrmsg{k}, ... sprintf( 'error: %s at line %d, in function %s\n', ... e.stack(j).file, e.stack(j).line, e.stack(j).name ) ]; end % When displaying the error message in MATLAB, all backslashes % have to be replaced by two backslashes. This must not, however, % be applied constantly as the string that's saved to the LaTeX % output must have only one backslash. if strcmp( env, 'MATLAB' ) fprintf( stderr, strrep( tikzerrmsg{k}, '\', '\\' ) ); else fprintf( stderr, tikzerrmsg{k} ); end tikzerror(k) = true; end % Make underscores in function names TeX compatible funcName{k} = strrep( funcName{k}, '_', '\_' ); % ...and finally write the bits to the LaTeX file texfile_addtest(fh, pdf_file, gen_file, desc{k}, funcName{k}, ... indices(k), pdferror(k), tikzerror(k)); close( fig_handle ); elapsedTime = toc; fprintf( stdout, '%s ', strrep( funcName{k}, '\_', '_' ) ); fprintf( stdout, 'done (%4.2fs).\n\n', elapsedTime ); end % Write the summary table to the LaTeX file texfile_tab_completion_init( fh ) for k = 1:length(indices) % Break table up into pieces if it gets too long for one page if ~mod(k,35) texfile_tab_completion_finish( fh ); texfile_tab_completion_init( fh ); end fprintf( fh, '%d & \\texttt{%s}', indices(k), funcName{k} ); if isempty( desc{k} ) fprintf( fh, ' & --- & skipped & ---' ); else for err = [ ploterror(k), pdferror(k), tikzerror(k) ] if err fprintf( fh, ' & \\textcolor{red}{failed}' ); else fprintf( fh, ' & \\textcolor{green!50!black}{passed}' ); end end end fprintf( fh, ' \\\\\n' ); end texfile_tab_completion_finish( fh ); % Write the error messages to the LaTeX file if there are any if any( [ploterror ; tikzerror ; pdferror ] ) fprintf( fh, '\\section*{Error messages}\n\\scriptsize\n' ); for k = 1:length(indices) if ~isempty( ploterrmsg{k} ) || ~isempty( tikzerrmsg{k} ) || ~isempty( pdferrmsg{k} ) % There are error messages for this test case fprintf( fh, '\n\\subsection*{Test case %d: \\texttt{%s}}\n', indices(k), funcName{k} ); else % No error messages for this test case continue end if ~isempty( ploterrmsg{k} ) fprintf( fh, [ '\\subsubsection*{Plot generation}\n' , ... '\\begin{verbatim}\n' , ... '%s' , ... '\\end{verbatim}\n' ], ... ploterrmsg{k} ); end if ~isempty( pdferrmsg{k} ) fprintf( fh, [ '\\subsubsection*{PDF generation}\n' , ... '\\begin{verbatim}\n' , ... '%s' , ... '\\end{verbatim}\n' ], ... pdferrmsg{k} ); end if ~isempty( tikzerrmsg{k} ) fprintf( fh, [ '\\subsubsection*{matlab2tikz}\n' , ... '\\begin{verbatim}\n' , ... '%s' , ... '\\end{verbatim}\n' ], ... tikzerrmsg{k} ); end end fprintf( fh, '\n\\normalsize\n\n' ); end % now, finish off the file and close file and window texfile_finish( fh ); fclose( fh ); end % ========================================================================= function texfile_init( texfile_handle ) fprintf( texfile_handle , ... [ '\\documentclass[landscape]{scrartcl}\n' , ... '\\pdfminorversion=6\n\n', ... '\\usepackage{amsmath} %% required for $\text{xyz}$\n\n', ... '\\usepackage{graphicx}\n' , ... '\\usepackage{tikz}\n' , ... '\\usetikzlibrary{plotmarks}\n\n' , ... '\\usepackage{pgfplots}\n' , ... '\\pgfplotsset{compat=newest}\n\n' , ... '\\usepackage[margin=0.5in]{geometry}\n' , ... '\\newlength\\figurewidth\n' , ... '\\setlength\\figurewidth{0.4\\textwidth}\n\n' , ... '\\begin{document}\n\n' ] ); end % ========================================================================= function texfile_finish( texfile_handle ) fprintf( texfile_handle, '\\end{document}' ); end % ========================================================================= function texfile_addtest( texfile_handle, ref_file, gen_file, desc, ... funcName, funcId, ref_error, gen_error ) % Actually add the piece of LaTeX code that'll later be used to display % the given test. fprintf ( texfile_handle , ... [ '\\begin{figure}\n' , ... '\\centering\n' , ... '\\begin{tabular}{cc}\n' ] ... ); if ~ref_error fprintf ( texfile_handle , ... '\\includegraphics[width=\\figurewidth]{../%s}\n' , ... ref_file ... ); else fprintf ( texfile_handle , ... [ '\\tikz{\\draw[red,thick] ' , ... '(0,0) -- (\\figurewidth,\\figurewidth) ' , ... '(0,\\figurewidth) -- (\\figurewidth,0);}\n' ] ... ); end fprintf ( texfile_handle , ... '&\n' ... ); if ~gen_error fprintf ( texfile_handle , ... '\\input{../%s}\\\\\n' , ... gen_file ... ); else fprintf ( texfile_handle , ... [ '\\tikz{\\draw[red,thick] ' , ... '(0,0) -- (\\figurewidth,\\figurewidth) ' , ... '(0,\\figurewidth) -- (\\figurewidth,0);}\\\\\n' ] ... ); end fprintf ( texfile_handle , ... [ 'reference rendering & generated\n', ... '\\end{tabular}\n' , ... '\\caption{%s \\texttt{%s}, \\texttt{testFunctions(%d)}}\n', ... '\\end{figure}\n' , ... '\\clearpage\n\n' ], ... desc, funcName, funcId ... ); end % ========================================================================= function texfile_tab_completion_init( texfile_handle ) fprintf( texfile_handle , ... [ '\\clearpage\n\n' , ... '\\begin{table}\n' , ... '\\centering\n' , ... '\\caption{Test case completion summary}\n' , ... '\\begin{tabular}{rlccc}\n' , ... 'No. & Test case & Plot & PDF & TikZ \\\\\n' , ... '\\hline\n' ] ); end % ========================================================================= function texfile_tab_completion_finish( texfile_handle ) fprintf( texfile_handle , ... [ '\\end{tabular}\n' , ... '\\end{table}\n\n' ] ); end % ========================================================================= function env = getEnvironment() env = ''; % Check if we are in MATLAB or Octave. % `ver' in MATLAB gives versioning information on all installed packages % separately, and there is no guarantee that MATLAB itself is listed first. % Hence, loop through the array and try to find 'MATLAB' or 'Octave'. versionData = ver; for k = 1:max(size(versionData)) if strcmp( versionData(k).Name, 'MATLAB' ) env = 'MATLAB'; break; elseif strcmp( versionData(k).Name, 'Octave' ) env = 'Octave'; break; end end end % ========================================================================= matlab2tikz-0.4.4/test/myCount.dat000066400000000000000000000007101226131721500170500ustar00rootroot00000000000000 11 11 9 7 13 11 14 17 20 11 13 9 43 51 69 38 46 76 61 132 186 75 135 180 38 88 115 28 36 55 12 12 14 18 27 30 18 19 29 17 15 18 19 36 48 32 47 10 42 65 92 57 66 151 44 55 90 114 145 257 35 58 68 11 12 15 13 9 15 10 9 7 matlab2tikz-0.4.4/test/pointReductionTest.m000066400000000000000000000014771226131721500207570ustar00rootroot00000000000000% ============================================================================== function pointReductionTest() breakTime = 5.0; testPlots = {@testPlot1, ... }; %@testPlot2}; for testPlot = testPlots testPlot(); 'a' %pause(breakTime); %pointReduction2d(0.1); pause(breakTime); 'b' end close all; end % ============================================================================== function testPlot1() x = -pi:pi/1000:pi; y = tan(sin(x)) - sin(tan(x)); plot(x,y,'--rs'); end % ============================================================================== function testPlot2() x = -pi:pi/1000:pi; y = exp(tan(sin(x)) - sin(tan(x))); semilogy(x,y,'--rs'); end % ============================================================================== matlab2tikz-0.4.4/test/testfunctions.m000066400000000000000000002122161226131721500200140ustar00rootroot00000000000000% ========================================================================= % *** FUNCTION testfunctions % *** % *** Standard example plot from MATLAB's help pages. % *** % ========================================================================= % *** % *** Copyright (c) 2008--2013, Nico Schlömer % *** All rights reserved. % *** % *** Redistribution and use in source and binary forms, with or without % *** modification, are permitted provided that the following conditions are % *** met: % *** % *** * Redistributions of source code must retain the above copyright % *** notice, this list of conditions and the following disclaimer. % *** * Redistributions in binary form must reproduce the above copyright % *** notice, this list of conditions and the following disclaimer in % *** the documentation and/or other materials provided with the distribution % *** % *** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" % *** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE % *** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE % *** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE % *** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR % *** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF % *** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS % *** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN % *** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) % *** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % *** POSSIBILITY OF SUCH DAMAGE. % *** % ========================================================================= function [desc, extraOpts, funcName, numFunctions] = testfunctions(k) % assign the functions to test testfunction_handles = { ... @one_point , ... @plain_cos , ... @sine_with_markers , ... @markerSizes , ... @sine_with_annotation, ... @linesWithOutliers , ... @peaks_contour , ... @contourPenny , ... @peaks_contourf , ... @many_random_points , ... @double_colorbar , ... @randomWithLines , ... @double_axes , ... @double_axes2 , ... @logplot , ... @colorbarLogplot , ... @legendplot , ... @legendplotBoxoff , ... @moreLegends , ... @zoom , ... @quiveroverlap , ... @quiverplot , ... @quiver3plot , ... @imageplot , ... @logicalImage , ... @imagescplot , ... @imagescplot2 , ... @stairsplot , ... @polarplot , ... @roseplot , ... @compassplot , ... @stemplot , ... @stemplot2 , ... @groupbars , ... @bars , ... @subplotBars , ... @hbars , ... @stackbars , ... @xAxisReversed , ... @errorBars , ... @errorBars2 , ... @subplot2x2 , ... @subplot2x2b , ... @manualAlignment , ... @subplot3x1 , ... @subplotCustom , ... @legendsubplots , ... @legendsubplots2 , ... @bodeplots , ... @rlocusPlot , ... @mandrillImage , ... @besselImage , ... @clownImage , ... @zplanePlot1 , ... @zplanePlot2 , ... @freqResponsePlot , ... @axesLocation , ... @axesColors , ... @multipleAxes , ... @scatterPlotRandom , ... @scatterPlot , ... @scatter3Plot , ... @scatter3Plot2 , ... @spherePlot , ... @surfPlot , ... @surfPlot2 , ... @superkohle , ... @meshPlot , ... @ylabels , ... @spectro , ... % takes pretty long to LuaLaTeX-compile @mixedBarLine , ... @decayingharmonic , ... @texcolor , ... @textext , ... @texrandom , ... @latexmath1 , ... @latexmath2 , ... @parameterCurve3d , ... @parameterSurf , ... @fill3plot , ... @rectanglePlot , ... @herrorbarPlot , ... @hist3d , ... @myBoxplot , ... @areaPlot , ... @customLegend , ... @pixelLegend , ... @croppedImage , ... @doubleAxes , ... @pColorPlot , ... @hgTransformPlot }; numFunctions = length( testfunction_handles ); if (k<=0) % This is used for querying numFunctions. desc = ''; funcName = ''; extraOpts = {}; return; elseif (k<=numFunctions) [desc, extraOpts] = testfunction_handles{k}(); funcName = func2str(testfunction_handles{k}); else error('testfunctions:outOfBounds', ... 'Out of bounds (number of testfunctions=%d)', numFunctions); end return; end % ========================================================================= % *** FUNCTION one_point function [description, extraOpts] = one_point() %%-------------------------------------------------- %t_start=0.0; %t_end=60; %delta_t = 0.1; %number_of_intpoints = (t_end - t_start ) / delta_t; % %xp = linspace(t_start, t_end, number_of_intpoints); %yp1 = xp.^2+2; %yp2 = xp.^2+50.*sin(xp)-1; %yp3 = sin(xp); % %xp = reshape(xp,size(xp,2),size(xp,1)); %yp1 = reshape(yp1,size(yp1,2),size(yp1,1)); %yp2 = reshape(yp2,size(yp2,2),size(yp2,1)); %yp3 = reshape(yp3,size(yp3,2),size(yp3,1)); %%-------------------------------------------------- % %% figure %% plotyy %[AX,P1,P2] = plotyy(xp, [ yp2 , yp1 ], xp , yp3); %% setting axis labels %set(get(AX(1),'Ylabel'),'String','$E_{kin}$,$E_{pot}$ [J] x $10^{-3}$','Interpreter','tex'); %set(get(AX(2),'Ylabel'),'String','$E_{pot}$ [J] x $10^{-3}$'); %xlabel('t [ns]'); %% line Properties %set(P1,'LineWidth',1); %set(P1(1),'LineStyle','-','Color',[1 0 0]) %set(P1(2),'LineStyle','-','Color',[0 0 0]); %set(P2,'LineStyle','-','LineWidth',1,'Color',[0 0 1]) %grid on; %hold on; %legend1 = legend([P1(1) P1(2) P2],'$E_{tot}$','$E_{kin}$','$E_{pot}$'); %set(legend1,'Box','off','Orientation','horizontal','Location','NorthOutside'); %-------------------------------------------------- % output %matlab2tikz('parseStrings', false, 'interpretTickLabelsAsTex', true,'width', '\figurewidth', 'height','\figureheight', 'test.tex') m = [0 1 1.5 1 -1]; k = 1:1:length(m); plot(k,m,'*-'); %plot(1:10) title({'title', 'multline'}) %legend(char('Multi-Line Legend Entry','Wont Work 2^2=4')) legend('Multi-Line Legend Entry Wont Work 2^2=4') xlabel({'one','two','three'}); ylabel({'one','° ∞', 'three'}); % plot(0.123, 0.145, 'x'); set(gca, 'YTick', []); set(gca,'XTick',0:1:length(m)-1); set(gca,'XTickLabel',{}); description = 'Plot only one single point.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = plain_cos() fplot( @cos, [0,2*pi] ); % add some minor ticks set(gca, 'XMinorTick', 'on'); set(gca, 'YTick', []); % Adjust the aspect ratio when in MATLAB(R) or Octave >= 3.4. env = getEnvironment(); switch env case 'MATLAB' daspect([ 1 2 1 ]) case 'Octave' if isVersionBelow( env, 3, 4 ) % Octave < 3.4 doesn't have daspect unfortunately. else daspect([ 1 2 1 ]) end otherwise error( 'Unknown environment. Need MATLAB(R) or GNU Octave.' ) end description = 'Plain cosine function with minimumPointsDistance of $0.5$.' ; extraOpts = {'minimumPointsDistance', 0.5}; end % ========================================================================= function [description, extraOpts] = sine_with_markers () % Standard example plot from MATLAB's help pages. x = -pi:pi/10:pi; y = tan(sin(x)) - sin(tan(x)); y(3) = NaN; y(7) = Inf; y(11) = -Inf; plot(x,y,'--o', 'Color', [0.6,0.2,0.0], ... 'LineWidth', 1*360/127,... 'MarkerEdgeColor','k',... 'MarkerFaceColor',[0.3,0.1,0.0],... 'MarkerSize', 5*360/127 ); set( gca, 'Color', [0.9 0.9 1], ... 'XTickLabel', [], ... 'YTickLabel', [] ... ); set(gca,'XTick',[0]); set(gca,'XTickLabel',{'null'}); description = [ 'Twisted plot of the sine function. ' ,... 'Pay particular attention to how markers and Infs/NaNs are treated.' ]; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = markerSizes() hold on; h = fill([1 1 2 2],[1 2 2 1],'r'); set(h,'LineWidth',10); plot([0],[0],'go','Markersize',14,'LineWidth',10) plot([0],[0],'bo','Markersize',14,'LineWidth',1) description = 'Marker sizes.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = sine_with_annotation () x = -pi:.1:pi; y = sin(x); h = plot(x,y); set(gca,'XTick',-pi:pi/2:pi); set(gca,'XTickLabel',{'-pi','-pi/2','0','pi/2','pi'}); xlabel('-\pi \leq \Theta \leq \pi'); ylabel('sin(\Theta)'); title({'Plot of sin(\Theta)','subtitle','and here''s one really long subtitle' }); text(-pi/4,sin(-pi/4),'\leftarrow sin(-\pi\div4)',... 'HorizontalAlignment','left'); set(findobj(gca,'Type','line','Color',[0 0 1]),... 'Color','red',... 'LineWidth',10); description = [ 'Plot of the sine function. ' ,... 'Pay particular attention to how titles and annotations are treated.' ]; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = linesWithOutliers() far = 200; x = [ -far, -1, -1, -far, -10, -0.5, 0.5, 10, far, 1, 1, far, 10, 0.5, -0.5, -10, -far ]; y = [ -10, -0.5, 0.5, 10, far, 1, 1, far, 10, 0.5, -0.5, -10, -far, -1, -1, -far, -0.5 ]; plot( x, y,'o-'); axis( [-2,2,-2,2] ); description = 'Lines with outliers.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = peaks_contour() [C, h] = contour(peaks(20),10); clabel(C, h); % remove y-ticks set(gca,'YTickLabel',[]); set(gca,'YTick',[]); colormap winter; description = 'Test contour plots.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = contourPenny() if ~exist('penny.mat','file') fprintf( 'penny data set not found. Abort.\n\n' ); description = []; extraOpts = {}; return; end load penny; contour(flipud(P)); axis square; description = 'Contour plot of a US\$ Penny.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = peaks_contourf () contourf(peaks(20), 10); colorbar(); legend('my legend'); % colorbar('NorthOutside'); % colorbar('SouthOutside'); % colorbar('WestOutside'); % colormap([0:0.1:1; 1:-0.1:0; 0:0.1:1]') colormap hsv; description = 'Test the contourfill plots.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = double_colorbar() vspace = linspace(-40,40,20); speed_map = rand(20); Q1_map = rand(20); subplot(1, 2, 1); contour(vspace(9:17),vspace(9:17),speed_map(9:17,9:17),20) colorbar axis tight axis square xlabel('$v_{2d}$') ylabel('$v_{2q}$') subplot(1, 2, 2) contour(vspace(9:17),vspace(9:17),Q1_map(9:17,9:17),20) colorbar axis tight axis square xlabel('$v_{2d}$') ylabel('$v_{2q}$') description = 'Double colorbar.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = randomWithLines() X = randn(150,2); X(:,1) = (X(:,1) * 90) + 75; plot(X(:,1),X(:,2),'o'); hold on; M(1)=min(X(:,1)); M(2)=max(X(:,1)); plot(M,[mean(X(:,2)) mean(X(:,2))],'k-'); plot(M,[2*std(X(:,2)) 2*std(X(:,2))],'k--'); plot(M,[-2*std(X(:,2)) -2*std(X(:,2))],'k--'); axis('tight'); description = 'Random points with lines.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = many_random_points () n = 1e3; xy = rand(n,2); plot ( xy(:,1), xy(:,2), '.r' ); axis([ 0, 1, 0, 1 ]) description = 'Test the performance when drawing many points.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = double_axes() dyb = 0.1; % normalized units, bottom offset dyt = 0.1; % separation between subsequent axes bottoms x = [0; 24; 48; 72; 96;]; y = [7.653 7.473 7.637 7.652 7.651]; figure(1) grid on h1 = plot(x,y,'Color','k'); % following code is taken from `floatAxisX.m' % get position of axes allAxes = get(gcf,'Children'); naxes = length(allAxes); ax1Pos = get(allAxes(naxes),'position'); % rescale and reposition all axes to handle additional axes for an=1:naxes-1 if isequal(rem(an,2),0) % even ones in array of axes handles represent axes on which lines are plotted set(allAxes(an),'Position',[ax1Pos(1,1) ax1Pos(1,2)+dyb ax1Pos(1,3) ax1Pos(1,4)-dyt]) else % odd ones in array of axes handles represent axes on which floating x-axss exist axPos = get(allAxes(an),'Position'); set(allAxes(an),'Position',[axPos(1,1) axPos(1,2)+dyb axPos(1,3) axPos(1,4)]) end end % first axis a special case (doesn't fall into even/odd scenario of figure children) set(allAxes(naxes),'Position',[ax1Pos(1,1) ax1Pos(1,2)+dyb ax1Pos(1,3) ax1Pos(1,4)-dyt]) ylimit1 = get(allAxes(naxes),'Ylim'); % get new position for plotting area of figure ax1Pos = get(allAxes(naxes),'position'); % axis to which the floating axes will be referenced ref_axis = allAxes(1); refPosition = get(ref_axis,'position'); % overlay new axes on the existing one ax2 = axes('Position',ax1Pos); % plot data and return handle for the line hl1 = plot(x,y,'k'); % make the new axes invisible, leaving only the line visible set(ax2,'visible','off','ylim',ylimit1) % set the axis limit mode so that it does not change if the % user resizes the figure window set(ax2,'xLimMode','manual') % set up another set of axes to act as floater ax3 = axes('Position',[refPosition(1) refPosition(2)-dyb refPosition(3) 0.01]); set(ax3,'box','off','ycolor','w','yticklabel',[],'ytick',[]) set(ax3,'XMinorTick','on','color','none','xcolor',get(hl1,'color')) xlabel('secondary axis') description = 'Double axes'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = double_axes2() ah1=axes; ph=plot([0 1],[0 1]); title('Title') ylabel('y') xlabel('x') % add a new set of axes % to make a gray grid ah2=axes; % make the background transparent set(ah1,'color','none') % move these axes to the back set(gcf,'Child',flipud(get(gcf,'Children'))) description = 'Double overlayed axes with a flip.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = logplot() x = logspace(-1,2); loglog(x,exp(x),'-s') grid on; description = 'Test logscaled axes.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = colorbarLogplot() switch getEnvironment() case 'MATLAB' imagesc([1 10 100]); case 'Octave' % TODO find out what to do for octave here description = 'Logscaled colorbar -- unavailable in Octave.'; extraOpts = {}; return; otherwise error( 'Unknown environment. Need MATLAB(R) or Octave.' ) end set(colorbar(), 'YScale', 'log'); description = 'Logscaled colorbar.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = legendplot() % x = -pi:pi/20:pi; % plot(x,cos(x),'-ro',x,sin(x),'-.b'); % h = legend('one pretty long legend cos_x','sin_x',2); % set(h,'Interpreter','none'); x = 0:0.01:2*pi; plot( x, sin(x), 'b', ... x, cos(x), 'r' ); xlim( [0 2*pi] ) ylim( [-0.9 0.9] ) title( '{tikz test}' ) xlabel( '{x-Values}' ) ylabel( '{y-Values}' ) legend( 'sin(x)', 'cos(x)', 'Location','NorthOutside', ... 'Orientation', 'Horizontal' ); grid on; description = 'Test inserting of legends.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = legendplotBoxoff () x = -pi:pi/20:pi; plot( x, cos(x),'-ro',... x, sin(x),'-.b' ... ); h = legend( 'cos_x', 'one pretty long legend sin_x', 2 ); set( h, 'Interpreter', 'none' ); legend boxoff; description = 'Test inserting of legends.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = moreLegends() x = 0:.1:7; y1 = sin(x); y2 = cos(x); [ax,h1,h2] = plotyy(x,y1,x,y2); legend([h1;h2],'Sine','Cosine'); description = 'More legends.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = zoom() fplot( @sin, [0,2*pi], '-*' ); hold on; delta = pi/10; plot( [pi/2, pi/2], [1-2*delta, 1+2*delta], 'r' ); % vertical line plot( [pi/2-2*delta, pi/2+2*delta], [1, 1], 'g' ); % horizontal line % diamond plot( [ pi/2-delta, pi/2 , pi/2+delta, pi/2 , pi/2-delta ], ... [ 1 , 1-delta, 1, 1+delta, 1 ], 'y' ); % boundary lines with markers plot([ pi/2-delta, pi/2 , pi/2+delta, pi/2+delta pi/2+delta, pi/2, pi/2-delta, pi/2-delta ], ... [ 1-delta, 1-delta, 1-delta, 1, 1+delta, 1+delta, 1+delta, 1 ], ... 'ok', ... 'MarkerSize', 20, ... 'MarkerFaceColor', 'g' ... ); hold off; axis([pi/2-delta, pi/2+delta, 1-delta, 1+delta] ); description = 'Plain cosine function, zoomed in.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = bars() bins = -0.5:0.1:0.5; bins = 10 * bins; numEntries = length(bins); numBars = 3; data = round(100 * rand(numEntries, numBars)); b = bar(bins,data, 1.5); set(b(1),'FaceColor','m','EdgeColor','none') description = 'Plot with bars.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = subplotBars() subplot(2,1,1); X = rand(1,10); bar(X); subplot(2,1,2); bins = -0.5:0.1:0.5; bins = 10 * bins; numEntries = length(bins); numBars = 3; data = round(100 * rand(numEntries, numBars)); bar(bins,data, 1.5); description = 'Bars in subplots.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = hbars() y = [75.995 91.972 105.711 123.203 131.669 ... 150.697 179.323 203.212 226.505 249.633 281.422]; barh(y); description = 'Horizontal bars.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = groupbars() X = [1,2,3,4,5]; Y = round(rand(5,2)*20); % bar(X,Y,'group','BarWidth',1.0); makebars(X,Y,1.0,'grouped'); % set(gca,'XTick',[4,4.2,4.25,4.3,4.4,4.45,4.5]); title 'Group'; description = 'Plot with bars in groups.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = stackbars() Y = round(rand(5,3)*10); bar(Y,'stack'); title 'Stack'; description = 'Plot of stacked bars.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = stemplot() x = 0:25; y = [exp(-.07*x).*cos(x); exp(.05*x).*cos(x)]'; h = stem(x, y); legend( 'exp(-.07x)*cos(x)', 'exp(.05*x)*cos(x)', 'Location', 'NorthWest'); set(h(1),'MarkerFaceColor','blue') set(h(2),'MarkerFaceColor','red','Marker','square') description = 'A simple stem plot.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = stemplot2() x = 0:25; y = [exp(-.07*x).*cos(x); exp(.05*x).*cos(x)]'; h = stem(x, y, 'filled'); legend( 'exp(-.07x)*cos(x)', 'exp(.05*x)*cos(x)', 'Location', 'NorthWest'); description = 'Another simple stem plot.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = stairsplot() x = linspace(-2*pi,2*pi,40); stairs(x,sin(x)) description = 'A simple stairs plot.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = quiverplot() [X,Y] = meshgrid(-2:.2:2); Z = X.*exp(-X.^2 - Y.^2); [DX,DY] = gradient(Z,.2,.2); contour(X,Y,Z); hold on quiver(X,Y,DX,DY); colormap hsv; hold off description = 'A combined quiver/contour plot of $x\exp(-x^2-y^2)$.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = quiver3plot() vz = 10; % Velocity a = -32; % Acceleration t = 0:.1:1; z = vz*t + 1/2*a*t.^2; vx = 2; x = vx*t; vy = 3; y = vy*t; u = gradient(x); v = gradient(y); w = gradient(z); scale = 0; quiver3(x,y,z,u,v,w,scale) view([70 18]) description = 'Three-dimensional quiver plot.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = quiveroverlap () x = [0 1]; y = [0 0]; u = [1 -1]; v = [1 1]; quiver(x,y,u,v); description = 'Quiver plot with avoided overlap.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = polarplot () t = 0:.01:2*pi; polar(t,sin(2*t).*cos(2*t),'--r') description = 'A simple polar plot.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = roseplot () theta = 2*pi*rand(1,50); rose(theta); description = 'A simple rose plot.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = compassplot () Z = eig(randn(20,20)); compass(Z); description = 'A simple compass plot.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = imageplot () n = 10; density = 0.5; subplot(1,2,1); A = sprand( n, n, density ); imagesc( A ); subplot(1,2,2); A = sprand( n, n, density ); imagesc( A ); description = 'An image plot of matrix values.' ; %extraOpts = {'imagesAsPng', false}; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = logicalImage() data = rand(10,10); imagesc(data > 0.5); description = 'An image plot of logical matrix values.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = imagescplot() pointsX = 10; pointsY = 20; x = 0:1/pointsX:1; y = 0:1/pointsY:1; z = sin(x)'*cos(y); imagesc(x,y,z); description = 'An imagesc plot of $\sin(x)\cos(y)$.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = imagescplot2() a=magic(10); x=-5:1:4; y=10:19; imagesc(x,y,a) xlim([-3,2]) ylim([12,15]) grid on; description = 'A trimmed imagesc plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = xAxisReversed () n = 100; x = (0:1/n:1); y = exp(x); plot(x,y); set(gca,'XDir','reverse'); set(gca,'YDir','reverse'); legend( 'Location', 'SouthWest' ); description = 'Reversed axes with legend.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = subplot2x2 () x = (1:5); subplot(2,2,1); y = rand(1,5); plot(x,y); subplot(2,2,2); y = rand(1,5); plot(x,y); subplot(2,2,3); y = rand(1,5); plot(x,y); subplot(2,2,4); y = rand(1,5); plot(x,y); description = 'Four aligned subplots on a $2\times 2$ subplot grid.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = subplot2x2b () x = (1:5); subplot(2,2,1); y = rand(1,5); plot(x,y); subplot(2,2,2); y = rand(1,5); plot(x,y); subplot(2,2,3:4); y = rand(1,5); plot(x,y); description = 'Three aligned subplots on a $2\times 2$ subplot grid.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = manualAlignment() xrange = linspace(-3,4,2*1024); axes('Position', [0.1 0.1 0.85 0.15]); plot(xrange); ylabel('$n$'); xlabel('$x$'); axes('Position', [0.1 0.25 0.85 0.6]); plot(xrange); set(gca,'XTick',[]); description = 'Manually aligned figures.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = subplot3x1 () x = (1:5); subplot(3,1,1); y = rand(1,5); plot(x,y); subplot(3,1,2); y = rand(1,5); plot(x,y); subplot(3,1,3); y = rand(1,5); plot(x,y); description = 'Three aligned subplots on a $3\times 1$ subplot grid.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = subplotCustom () x = (1:5); y = rand(1,5); subplot( 'Position', [0.05 0.1 0.3 0.3] ) plot(x,y); y = rand(1,5); subplot( 'Position', [0.35 0.5 0.3 0.3] ) plot(x,y); y = rand(1,5); subplot( 'Position', [0.65 0.1 0.3 0.3] ) plot(x,y); description = 'Three customized aligned subplots.' ; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = errorBars () data = 1:10; eH = rand(10,1); eL = rand(10,1); %hold on; %bar(1:10, data) errorbar(1:10, data, eL, eH, '.') description = 'Generic error bar plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = errorBars2 () data = load( 'myCount.dat' ); y = mean( data, 2 ); e = std( data, 1, 2 ); errorbar( y, e, 'xr' ); description = 'Another error bar example.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = legendsubplots() % size of upper subplot rows = 4; % number of points. A large number here (eg 1000) will stress-test % matlab2tikz and your TeX installation. Be prepared for it to run out of % memory length = 100; % generate some spurious data t = 0:(4*pi)/length:4*pi; x = t; a = t; y = sin(t) + 0.1*randn(1,length+1); b = sin(t) + 0.1*randn(1,length+1) + 0.05*cos(2*t); % plot the top figure subplot(rows+2,1,1:rows); % first line sigma1 = std(y); tracey = mean(y,1); plot123 = plot(x,tracey,'b-'); hold on % second line sigma2 = std(b); traceb = mean(b,1); plot456 = plot(a,traceb,'r-'); spec0 = ['Mean V(t)_A (\sigma \approx ' num2str(sigma1,'%0.4f') ')']; spec1 = ['Mean V(t)_B (\sigma \approx ' num2str(sigma2,'%0.4f') ')']; hold off %plot123(1:2) legend([plot123; plot456],spec0,spec1) legend boxoff xlabel('Time/s') ylabel('Voltage/V') title('Time traces'); % now plot a differential trace subplot(rows+2,1,rows+1:rows+2) plot7 = plot(a,traceb-tracey,'k'); legend(plot7,'\Delta V(t)') legend boxoff xlabel('Time/s') ylabel('\Delta V') title('Differential time traces'); description = [ 'Subplots with legends. ' , ... 'Increase value of "length" in the code to stress-test your TeX installation.' ]; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = legendsubplots2() if isempty(which('tf')) fprintf( 'function "tf" not found. Abort.\n\n' ); description = []; extraOpts = {}; return end Rc=1; C=1.5e-6; %F % Set inductors L1=4e-3; L2=0.8e-3; % Resistances of inductors R1=4; R2=2; % Transfer functions % Building transfer functions s=tf('s'); Zc=1/(s*C)+Rc; Z1=s*L1+R1; Z2=s*L2+R2; LCLd=(Z2+Zc)/(Z1+Zc); LCL=(s^2*C*L2+1)/(s^2*C*L1+1); t=logspace(3,5,1000); hold off bode(LCL,t) hold on bode(LCLd,t) title('Voltage transfer function of a LCL filter') set(findall(gcf,'type','line'),'linewidth',1.5) grid on legend('Perfect LCL',' Real LCL','Location','SW') description = ['Another subplot with legends.']; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = bodeplots() % check if the control toolbox is installed if length(ver('control')) ~= 1 fprintf( 'Control toolbox not found. Abort.\n\n' ); description = []; extraOpts = {}; return end g = tf([1 0.1 7.5],[1 0.12 9 0 0]); bode(g) description = 'Bode diagram of frequency response.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = rlocusPlot() if isempty(which('tf')) fprintf( 'function "tf" not found. Abort.\n\n' ); description = []; extraOpts = {}; return end s=tf('s'); rlocus(tf([1 1],[4 3 1])) description = 'rlocus plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = mandrillImage() if ~exist('mandrill.mat','file') fprintf( 'mandrill data set not found. Abort.\n\n' ); description = []; extraOpts = {}; return end data = load( 'mandrill' ); set( gcf, 'color', 'k' ) image( data.X ) colormap( data.map ) axis off axis image description = 'Picture of a mandrill.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = besselImage() nu = -5:0.25:5; beta = 0:0.05:2.5; m = length(beta); n = length(nu); trace = zeros(m,n); for i=1:length(beta); for j=1:length(nu) if (floor(nu(j))==nu(j)) trace(i,j)=abs(besselj(nu(j),beta(i))); end end end imagesc(nu,beta,trace); colorbar() xlabel('Order') ylabel('\beta') set(gca,'YDir','normal') description = 'Bessel function.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = clownImage() if ~exist('clown.mat','file') fprintf( 'clown data set not found. Abort.\n\n' ); description = []; extraOpts = {}; return end data = load( 'clown' ); imagesc( data.X ) colormap( gray ) description = 'Picture of a clown.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = zplanePlot1() % check of the signal processing toolbox is installed if length(ver('signal')) ~= 1 fprintf( 'Signal toolbox not found. Skip.\n\n' ); description = []; extraOpts = {}; return end [z,p] = ellip(4,3,30,200/500); zplane(z,p); title('4th-Order Elliptic Lowpass Digital Filter'); description = 'Representation of the complex plane with zplane.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = zplanePlot2() % check of the signal processing toolbox is installed if length(ver('signal')) ~= 1 fprintf( 'Signal toolbox not found. Skip.\n\n' ); description = []; extraOpts = {}; return end [b,a] = ellip(4,3,30,200/500); Hd = dfilt.df1(b,a); zplane(Hd) % FIXME: This opens a new figure that doesn't get closed automatically description = 'Representation of the complex plane with zplane.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = freqResponsePlot() % check of the signal processing toolbox is installed if length(ver('signal')) ~= 1 fprintf( 'Signal toolbox not found. Skip.\n\n' ); description = []; extraOpts = {}; return end b = fir1(80,0.5,kaiser(81,8)); hd = dfilt.dffir(b); freqz(hd); % FIXME: This opens a new figure that doesn't get closed automatically description = 'Frequency response plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = axesLocation() plot(rand(1,10)); set(gca,'XAxisLocation','top'); set(gca,'YAxisLocation','right'); description = 'Swapped axis locations.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = axesColors() plot(rand(1,10)); set(gca,'XColor','g','YColor','b'); % set(gca,'XColor','b','YColor','k'); box off; description = 'Custom axes colors.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = multipleAxes() x1 = 0:.1:40; y1 = 4.*cos(x1)./(x1+2); x2 = 1:.2:20; y2 = x2.^2./x2.^3; line(x1,y1,'Color','r'); ax1 = gca; set(ax1,'XColor','r','YColor','r') ax2 = axes('Position',get(ax1,'Position'),... 'XAxisLocation','top',... 'YAxisLocation','right',... 'Color','none',... 'XColor','k','YColor','k'); line(x2,y2,'Color','k','Parent',ax2); xlimits = get(ax1,'XLim'); ylimits = get(ax1,'YLim'); xinc = (xlimits(2)-xlimits(1))/5; yinc = (ylimits(2)-ylimits(1))/5; % Now set the tick mark locations. set(ax1,'XTick',xlimits(1):xinc:xlimits(2) ,... 'YTick',ylimits(1):yinc:ylimits(2) ) description = 'Multiple axes.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = scatterPlotRandom() n=1:100; scatter(n, n, 1000*rand(length(n),1), n.^8); colormap autumn; %x = randn( 10, 2 ); %scatter( x(:,1), x(:,2) ); description = 'Generic scatter plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = scatterPlot() if ~exist('seamount.mat','file') fprintf( 'seamount data set not found. Abort.\n\n' ); description = []; extraOpts = {}; return end data = load( 'seamount' ); scatter( data.x, data.y, 5, data.z, '^' ); description = 'Scatter plot with MATLAB(R) data.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = scatter3Plot() [x,y,z] = sphere(16); X = [x(:)*.5 x(:)*.75 x(:)]; Y = [y(:)*.5 y(:)*.75 y(:)]; Z = [z(:)*.5 z(:)*.75 z(:)]; S = repmat([1 .75 .5]*10,numel(x),1); C = repmat([1 2 3],numel(x),1); scatter3(X(:),Y(:),Z(:),S(:),C(:),'filled'), view(-60,60) view(40,35) description = 'Scatter3 plot with MATLAB(R) data.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = scatter3Plot2() % Read image (Note: "peppers.png" is available with MATLAB) InpImg_RGB = imread('peppers.png'); % Subsample image ("scatter3" can't cope with too many points) InpImg_RGB = InpImg_RGB(1:100:end, 1:100:end, 1:100:end ); InpImg_RGB = reshape(InpImg_RGB, [], 1, 3); % Split up into single components r = InpImg_RGB(:,:,1); g = InpImg_RGB(:,:,2); b = InpImg_RGB(:,:,3); % Scatter-plot points scatter3(r,g,b,15,[r g b]); xlabel('R'); ylabel('G'); zlabel('B'); description = 'Another Scatter3 plot.'; extraOpts = {}; return end % ========================================================================= function [description, extraOpts] = spherePlot() sphere(30); title('a sphere: x^2+y^2+z^2'); xlabel('x'); ylabel('y'); zlabel('z'); axis equal; description = 'Plot a sphere.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = surfPlot() [X,Y,Z] = peaks(30); surf(X,Y,Z) colormap hsv axis([-3 3 -3 3 -10 5]) set(gca,'View',[-37.5,36]); hc = colorbar('YTickLabel', ... {'Freezing','Cold','Cool','Neutral',... 'Warm','Hot','Burning','Nuclear'}); set(get(hc,'Xlabel'),'String','Multitude'); set(get(hc,'Ylabel'),'String','Magnitude'); set(hc,'YTick',0:0.7:7); set(hc,'YTickLabel',... {'-0.8' '-0.6' '-0.4' '-0.2' '0.0' ... '0.2' '0.4' '0.6' '0.8' '0.10' '0.12'}); set(get(hc,'Title'),... 'String', 'k(u,v)', ... 'FontSize', 12, ... 'interpreter', 'tex'); xlabel( 'x' ) ylabel( 'y' ) zlabel( 'z' ) description = 'Surface plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = surfPlot2() z = [ ones(15, 5) zeros(15,5); ... zeros(5,5) zeros(5,5) ]; surf(abs(fftshift(fft2(z))) + 1); set(gca,'ZScale','log'); legend( 'legendary', 'Location', 'NorthEastOutside' ); description = 'Another surface plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = superkohle() x1=0; x2=pi; y1=0; y2=pi; omegashape = [2 2 2 2 % 2 = line segment; 1 = circle segment; 4 = elipse segment x1 x2 x2 x1 % start point x x2 x2 x1 x1 % end point x y1 y1 y2 y2 % start point y y1 y2 y2 y1 % end point y 1 1 1 1 0 0 0 0]; [xy,edges,tri] = initmesh(omegashape,'Hgrad',1.05); mmin = 1; while size(xy,2) < mmin [xy,edges,tri] = refinemesh(omegashape,xy,edges,tri); end m = size(xy,2); x = xy(1,:)'; y = xy(2,:)'; y0 = cos(x).*cos(y); pdesurf(xy,tri,y0(:,1)); title('y_0'); xlabel('x1 axis'); ylabel('x2 axis'); axis([0 pi 0 pi -1 1]); grid on; description = 'Superkohle plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = meshPlot() [X,Y,Z] = peaks(30); mesh(X,Y,Z) colormap hsv axis([-3 3 -3 3 -10 5]) xlabel( 'x' ) ylabel( 'y' ) zlabel( 'z' ) description = 'Mesh plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = ylabels() x = 0:.01:2*pi; H = plotyy(x,sin(x),x,3*cos(x)); ylabel(H(1),'sin(x)'); ylabel(H(2),'3cos(x)'); xlabel(gca,'time') description = 'Separate y-labels.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = spectro() % In the original test case, this is 0:0.001:2, but that takes forever % for LaTeX to process. if isempty(which('chirp')) fprintf( 'chirp() not found. Abort.\n\n' ); description = []; extraOpts = {}; return end T = 0:0.005:2; X = chirp(T,100,1,200,'q'); spectrogram(X,128,120,128,1E3); title('Quadratic Chirp'); description = 'Spectrogram plot'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = mixedBarLine() x = rand(1000,1)*10; hist(x,10) y = ylim; hold on; plot([3 3], y, '-r'); hold off; description = 'Mixed bar/line plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = decayingharmonic() % Based on an example from % http://www.mathworks.com/help/techdoc/creating_plots/f0-4741.html#f0-28104 A = 0.25; alpha = 0.007; beta = 0.17; t = 0:901; y = A * exp(-alpha*t) .* sin(beta*t); plot(t, y) title('{\itAe}^{-\alpha\itt}sin\beta{\itt}, \alpha<<\beta') xlabel('Time \musec.') ylabel('Amplitude') description = 'Decaying harmonic oscillation with \TeX{} title.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = texcolor() % Taken from an example at % http://www.mathworks.com/help/techdoc/creating_plots/f0-4741.html#f0-28104 text(.1, .5, ['\fontsize{16}black {\color{magenta}magenta '... '\color[rgb]{0 .5 .5}teal \color{red}red} black again']) description = 'Multi-colored text using \TeX{} commands.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = textext() % Taken from an example at % http://www.mathworks.com/help/techdoc/creating_plots/f0-4741.html#f0-28303 txstr(1) = { 'Each cell is a quoted string' }; txstr(2) = { 'You can specify how the string is aligned' }; txstr(3) = { 'You can use LaTeX symbols like \pi \chi \Xi' }; txstr(4) = { '\bfOr use bold \rm\itor italic font\rm' }; txstr(5) = { '\fontname{courier}Or even change fonts' }; plot( 0:6, sin(0:6) ) text( 5.75, sin(2.5), txstr, 'HorizontalAlignment', 'right' ) description = 'Formatted text and special characters using \TeX{}.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = texrandom() num = 20; % number of symbols per line symbols = {'\it', '\bf', '\rm', '\sl', ... '\alpha', '\angle', '\ast', '\beta', '\gamma', '\delta', ... '\epsilon', '\zeta', '\eta', '\theta', '\vartheta', ... '\iota', '\kappa', '\lambda', '\mu', '\nu', '\xi', '\pi', ... '\rho', '\sigma', '\varsigma', '\tau', '\equiv', '\Im', ... '\otimes', '\cap', '{\int}', '\rfloor', '\lfloor', '\perp',... '\wedge', '\rceil', '\vee', '\langle', '\upsilon', '\phi', ... '\chi', '\psi', '\omega', '\Gamma', '\Delta', '\Theta', ... '\Lambda', '\Xi', '\Pi', '\Sigma', '\Upsilon', '\Phi', ... '\Psi', '\Omega', '\forall', '\exists', '\ni', '{\cong}', ... '\approx', '\Re', '\oplus', '\cup', '\subseteq', '\lceil', ... '\cdot', '\neg', '\times', '\surd', '\varpi', '\rangle', ... '\sim', '\leq', '\infty', '\clubsuit', '\diamondsuit', ... '\heartsuit', '\spadesuit', '\leftrightarrow', ... '\leftarrow', '\Leftarrow', '\uparrow', '\rightarrow', ... '\Rightarrow', '\downarrow', '\circ', '\pm', '\geq', ... '\propto', '\partial', '\bullet', '\div', '\neq', ... '\aleph', '\wp', '\oslash', '\supseteq', '\nabla', ... '{\ldots}', '\prime', '\0', '\mid', '\copyright', ... '\o', '\in', '\subset', '\supset', ... '\_', '\^', '\{', '\}', '$', '%', '#', ... '(', ')', '+', '-', '=', '/', ',', '.', '<', '>', ... '!', '?', ':', ';', '*', '[', ']', '§', '"', '''', ... '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ... 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', ... 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', ... 'w', 'x', 'y', 'z', ... 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', ... 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', ... 'W', 'X', 'Y', 'Z' ... }; % Note: Instead of '\ldots' the list of symbols contains the entry % '{\ldots}'. This is because TeX gives an error if it % encounters the sequence '$a_\ldots$' or '$a^\ldots$'. It % looks like that is a TeX bug. Nevertheless this sequence % could appear in the random output, therefore \ldots is % wrapped in braces since '$a_{\ldots}$' and '$a^{\ldots}$' % don't crash TeX. % Same thing with '\cong' and '\int'. % \color{red} etc. isn't included % \fontname{Times} etc. isn't included % \fontsize{12} etc. isn't included switch getEnvironment() case 'MATLAB' % MATLAB expects tilde and ampersand to be un-escaped and backslashes % to be escaped symbols = [ symbols, {'~', '&', '\\'} ]; case 'Octave' % Octave expects tilde and ampersand to be escaped for regular % output. If either are used un-escaped, that creates odd output in % Octave itself, but since matlab2tikz should be able to handle % those cases, let's include the un-escaped symbols in the list. symbols = [ symbols, {'\~', '\&', '~', '&'} ]; % Octave's backslash handling is weird to say the least. However, % matlab2tikz treats backslashes the same in Octave as it does in % MATLAB. Therefore, let's add an escaped backslash to the list symbols = [ symbols, {'\\'} ]; otherwise error( 'Unknown environment. Need MATLAB(R) or Octave.' ) end for ypos = [0.9:-.2:.1] % Generate `num' random indices to the list of symbols index = max(ceil(rand(1, num)*length(symbols)), 1); % Assemble symbols into one cell string array string = symbols(index); % Add random amount of balanced braces in random positions to `string'. % By potentially generating more than one set of braces randomly, it's % possible to create more complex patterns of nested braces. Increase % `braceprob' to get more braces, but don't use values greater than or % equal 1 which would result in an infinite loop. braceprob = 0.6; while rand(1,1) < braceprob % Generate two random numbers ranging from 1 to n with n = number % of symbols in `string' bracepos = max(ceil(rand(1, 2)*length(string)), 1); % Modify `string' so that an opening brace is inserted before % min(bracepos) symbols and a closing brace after max(bracepos) % symbols. That way any number of symbols from one to all in % `string' are wrapped in braces for min(bracepos) == max(bracepos) % and min(bracepos) == 1 && max(bracepos) == length(string), % respectively. string = [string(1:min(bracepos)-1), {'{'}, ... string(min(bracepos):max(bracepos)), ... {'}'}, string(max(bracepos)+1:end) ]; end % Clean up: remove '{}', '{{}}', etc. clean = false; while clean == false clean = true; for i = 1:length(string)-1 if strcmp( string(i), '{' ) && strcmp( string(i+1), '}' ) string = [string(1:i-1), string(i+2:end)]; clean = false; break end end end % Subscripts '_' and superscripts '^' in TeX are tricky in that certain % combinations are not allowed and there are some subtleties in regard % to more complicated combinations of sub/superscripts: % - ^a or _a at the beginning of a TeX math expression is permitted. % - a^ or a_ at the end of a TeX math expression is not. % - a__b, a_^b, a^_b, or a^^b is not allowed, as is any number of % consecutive sub/superscript operators. Actually a^^b does not % crash TeX, but it produces seemingly random output instead of `b', % therefore it should be avoided, too. % - a^b^c or a_b_c is not allowed as it results in a "double subscript/ % superscript" error. % - a^b_c or a_b^c, however, does work. % - a^bc^d or a_bc_d also works. % - a^b_c^d or a_b^c_d is not allowed and results in a "double % subscript/superscript" error. % - a{_}b, a{^}b, {a_}b or {a^}b is not permitted. % - a{_b} or a{^b} is valid TeX code. % - {a_b}_c produces the same output as a_{bc}. Likewise for '^'. % - a_{b_c} results in "a index b sub-index c". Likewise for '^'. % - a^{b}^c or a_{b}_c is not allowed as it results in a "double % subscript/superscript" error. % % From this we can derive a number of rules: % 1) The last symbol in a TeX string must not be '^' or '_'. % 2a) There must be at least one non-brace symbol between any '^' and '_'. % 2b) There must be at least one non-brace symbol between any '_' and '^'. % 3a) There must either be at least two non-brace, non-'_' symbols or at % least one non-brace, non-'_' symbol and one brace (opening or % closing) between any two '^'. % 3b) There must either be at least two non-brace, non-'^' symbols or at % least one brace (opening or closing) between any two '_'. % 4) '^' or '_' must not appear directly before '}'. % 5) '^' or '_' must not appear directly after '}'. % 6) Whenever braces were mentioned, that refers to non-empty braces, % i.e. '{}' counts as nothing. Printable/escaped braces '\{' and '\}' % also don't count as braces but as regular symbols. % 7) '^' or '_' must not appear directly before '\it', '\bf', '\rm', or % '\sl'. % 8) '^' or '_' must not appear directly after '\it', '\bf', '\rm', or % '\sl'. % % A few test cases: % Permitted: ^a... _a... a^b_c a_b^c a^bc^d a_bc_d a{_b} a{^b} % {a_b}_c a_{bc} {a^b}^c a^{bc} a_{b_c} a^{b^c} % Forbidden: ...z^ ...z_ a__b a_^b a^_b [a^^b] a^b^c a_b_c % a^b_c^d a_b^c_d a{_}b a{^}b {a_}b {a^}b % a^{_b} a_{^b} a^{b}^c a_{b}_c % % Now add sub/superscripts according to these rules subsupprob = 0.1; % Probability for insertion of a sub/superscript caretdist = Inf; % Distance to the last caret underscdist = Inf; % Distance to the last underscore bracedist = Inf; % Distance to the last brace (opening or closing) pos = 0; % Making sure the post-update `pos' in the while loop is less than the % number of symbols in `string' enforces rule 1: The last symbol in % a TeX string must not be '^' or '_'. while pos+1 < length(string) % Move one symbol further pos = pos + 1; % Enforce rule 7: No sub/superscript directly before '\it', '\bf', % '\rm', or '\sl'. if strcmp( string(pos), '\it' ) || strcmp( string(pos), '\bf' ) ... || strcmp( string(pos), '\rm' ) || strcmp( string(pos), '\sl' ) continue end % Enforce rule 8: No sub/superscript directly after '\it', '\bf', % '\rm', or '\sl'. if (pos > 1) ... && ( strcmp( string(pos-1), '\it' ) ... || strcmp( string(pos-1), '\bf' ) ... || strcmp( string(pos-1), '\rm' ) ... || strcmp( string(pos-1), '\sl' ) ... ) continue end bracedist = bracedist + 1; % Enforce rule 4: No sub/superscript directly before '}' if strcmp( string(pos), '}' ) bracedist = 0; % Also update braces distance continue end % Enforce rule 5: No sub/superscript directly after '}' if (pos > 1) && strcmp( string(pos-1), '}' ) continue end % Update distances for either braces or caret/underscore depending % on whether the symbol currently under scrutiny is a brace or not. if strcmp( string(pos), '{' ) bracedist = 0; else caretdist = caretdist + 1; underscdist = underscdist + 1; end % Generate two random numbers, then check if any of them is low % enough, so that with probability `subsupprob' a sub/superscript % operator is inserted into `string' at the current position. In % case both random numbers are below the threshold, whether a % subscript or superscript operator is to be inserted depends on % which of the two numbers is smaller. randomnums = rand(1, 2); if min(randomnums) < subsupprob if randomnums(1) < randomnums(2) % Enforce rule 2b: There must be at least one non-brace % symbol between previous '_' and to-be-inserted '^'. if underscdist < 1 continue end % Enforce rule 3a: There must either be at least two % non-brace, non-'_' symbols or at least one brace (opening % or closing) between any two '^'. if ~( ((caretdist >= 2) && (underscdist >= 2)) ... || ((bracedist < 2) && (caretdist >= 2)) ) continue end % Insert '^' before `pos'th symbol in `string' now that % we've made sure all rules are honored. string = [ string(1:pos-1), {'^'}, string(pos:end) ]; caretdist = 0; pos = pos + 1; else % Enforce rule 2a: There must be at least one non-brace % symbol between previous '^' and to-be-inserted '_'. if caretdist < 1 continue end % Enforce rule 3b: There must either be at least two % non-brace, non-'^' symbols or at least one brace (opening % or closing) between any two '_'. if ~( ((caretdist >= 2) && (underscdist >= 2)) ... || ((bracedist < 2) && (underscdist >= 2)) ) continue end % Insert '_' before `pos'th symbol in `string' now that % we've made sure all rules are honored. string = [ string(1:pos-1), {'_'}, string(pos:end) ]; underscdist = 0; pos = pos + 1; end end end % while pos+1 < length(string) % Now convert the cell string array of symbols into one regular string string = [string{:}]; % Print the string in the figure to be converted by matlab2tikz text( .05, ypos, string, 'interpreter', 'tex' ) % And print it to the console, too, in order to enable analysis of % failed tests fprintf( 'Original string: %s\n', string ) end title('Random TeX symbols \\\{\}\_\^$%#&') description = 'Random TeX symbols'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = latexmath1() % Adapted from an example at % http://www.mathworks.com/help/techdoc/ref/text_props.html#Interpreter axes title( '\omega\subseteq\Omega' ); text( 0.5, 0.5, '$$\int_0^x\!\int_{\Omega} dF(u,v) d\omega$$', ... 'Interpreter', 'latex', ... 'FontSize', 16 ) description = 'A formula typeset using the \LaTeX{} interpreter.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = latexmath2() % Adapted from an example at % http://www.mathworks.com/help/techdoc/creating_plots/f0-4741.html#bq558_t set(gcf, 'color', 'white') set(gcf, 'units', 'inches') set(gcf, 'position', [2 2 4 6.5]) set(gca, 'visible', 'off') % Note: Most likely due to a bug in matlab2tikz the pgfplots output will % appear empty even though the LaTeX strings are contained in the % output file. This is because the following (or something like it) % is missing from the axis environment properties: % xmin=0, xmax=4, ymin=-1, ymax=6 % Note: The matrices in h(1) and h(2) cannot be compiled inside pgfplots. % They are therefore disabled. % h(1) = text( 'units', 'inch', 'position', [.2 5], ... % 'fontsize', 14, 'interpreter', 'latex', 'string', ... % [ '$$\hbox {magic(3) is } \left( {\matrix{ 8 & 1 & 6 \cr' ... % '3 & 5 & 7 \cr 4 & 9 & 2 } } \right)$$' ]); % h(2) = text( 'units', 'inch', 'position', [.2 4], ... % 'fontsize', 14, 'interpreter', 'latex', 'string', ... % [ '$$\left[ {\matrix{\cos(\phi) & -\sin(\phi) \cr' ... % '\sin(\phi) & \cos(\phi) \cr}} \right]' ... % '\left[ \matrix{x \cr y} \right]$$' ]); h(3) = text( 'units', 'inch', 'position', [.2 3], ... 'fontsize', 14, 'interpreter', 'latex', 'string', ... [ '$$L\{f(t)\} \equiv F(s) = \int_0^\infty\!\!{e^{-st}' ... 'f(t)dt}$$' ]); h(4) = text( 'units', 'inch', 'position', [.2 2], ... 'fontsize', 14, 'interpreter', 'latex', 'string', ... '$$e = \sum_{k=0}^\infty {1 \over {k!} } $$' ); h(5) = text( 'units', 'inch', 'position', [.2 1], ... 'fontsize', 14, 'interpreter', 'latex', 'string', ... [ '$$m \ddot y = -m g + C_D \cdot {1 \over 2}' ... '\rho {\dot y}^2 \cdot A$$' ]); h(6) = text( 'units', 'inch', 'position', [.2 0], ... 'fontsize', 14, 'interpreter', 'latex', 'string', ... '$$\int_{0}^{\infty} x^2 e^{-x^2} dx = \frac{\sqrt{\pi}}{4}$$' ); % TODO: On processing the matlab2tikz_acidtest output, LaTeX complains % about the use of \over: % Package amsmath Warning: Foreign command \over; % (amsmath) \frac or \genfrac should be used instead description = 'Some nice-looking formulas typeset using the \LaTeX{} interpreter.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = parameterCurve3d() ezplot3('sin(t)','cos(t)','t',[0,6*pi]); text(0.5, 0.5, 10, 'abs'); description = 'Parameter curve in 3D.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = parameterSurf() if ~exist('TriScatteredInterp') fprintf( 'TriScatteredInterp() not found. Abort.\n\n' ); description = []; extraOpts = {}; return; end x = rand(100,1)*4 - 2; y = rand(100,1)*4 - 2; z = x.*exp(-x.^2 - y.^2); % Construct the interpolant % F = TriScatteredInterp(x,y,z,'nearest'); % F = TriScatteredInterp(x,y,z,'natural'); F = TriScatteredInterp(x,y,z,'linear'); % Evaluate the interpolant at the locations (qx, qy), qz % is the corresponding value at these locations. ti = -2:.25:2; [qx,qy] = meshgrid(ti,ti); qz = F(qx,qy); hold on surf(qx,qy,qz) plot3(x,y,z,'o') view(gca,[-69 14]); hold off description = 'Parameter and surface plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = fill3plot() if ~exist('fill3','builtin') fprintf( 'fill3() not found. Abort.\n\n' ); description = []; extraOpts = {}; return end x1 = -10:0.1:10; x2 = -10:0.1:10; p = sin(x1); d = zeros(1,numel(p)); d(2:2:end) = 1; h = p.*d; grid on; fill3(x1,x2,h,'k'); view(45,22.5); box on; description = 'fill3 plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = rectanglePlot() rectangle('Position', [0.59,0.35,3.75,1.37],... 'Curvature', [0.8,0.4],... 'LineWidth', 2, ... 'LineStyle', '--' ... ); daspect([1,1,1]); description = 'Rectangle handle.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = herrorbarPlot() hold on; X = 1:10; Y = 1:10; err = repmat(0.2, 1, 10); h1 = errorbar(X, Y, err, 'r'); h_vec = herrorbar(X, Y, err); for h=h_vec set(h, 'color', [1 0 0]); end h2 = errorbar(X, Y+1, err, 'g'); h_vec = herrorbar(X, Y+1, err); for h=h_vec set(h, 'color', [0 1 0]); end legend([h1 h2], {'test1', 'test2'}) description = 'herrorbar plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = hist3d() if ~exist('hist3','builtin') && isempty(which('hist3')) fprintf( 'Statistics toolbox not found. Abort.\n\n' ); description = []; extraOpts = {}; return end % load carbig % X = [MPG,Weight]; % hist3(X,[7 7]); % xlabel('MPG'); ylabel('Weight'); % set(get(gca,'child'),'FaceColor','interp','CDataMode','auto'); load carbig X = [MPG,Weight]; hist3(X,[7 7]); xlabel('MPG'); ylabel('Weight'); hist3(X,[7 7],'FaceAlpha',.65); xlabel('MPG'); ylabel('Weight'); % Linux crashed with OpenGL. %%set(gcf,'renderer','opengl'); % load seamount % dat = [-y,x]; % Grid corrected for negative y-values % n = hist3(dat); % Extract histogram data; % % default to 10x10 bins % view([-37.5, 30]); description = '3D histogram plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = myBoxplot() if ~exist('boxplot','builtin') && isempty(which('boxplot')) fprintf( 'Statistics toolbox not found. Abort.\n\n' ); description = []; extraOpts = {}; return end errors =[ 0.810000 3.200000 0.059500 0.762500 -3.200000 0.455500 0.762500 4.000000 0.901000 0.762500 3.600000 0.406000 0.192500 3.600000 0.307000 0.810000 -3.600000 0.604000 1.000000 -2.400000 0.505000 0.430000 -2.400000 0.455500 1.000000 3.200000 0.158500 ]; boxplot(errors); description = 'Boxplot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = areaPlot() area(1:3, rand(3)); legend('foo', 'bar', 'foobar'); description = 'Area plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = customLegend() x = -pi:pi/10:pi; y = tan(sin(x)) - sin(tan(x)); plot(x,y,'--rs'); lh=legend('y',4); set(lh,'color','g') set(lh,'edgecolor','r') set(lh, 'position',[.5 .6 .1 .05]) description = 'Custom legend.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = pixelLegend() x = linspace(0,1); plot(x, [x;x.^2]); set(gca, 'units', 'pixels') lh=legend('1', '2'); set(lh, 'position', [100 200 65 42]) description = 'Legend with pixel position.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = croppedImage() if ~exist('flujet.mat','file') fprintf( 'flujet data set not found. Abort.\n\n' ); description = []; extraOpts = {}; return; end load('flujet','X','map'); image(X) colormap(map) %axis off axis image xlim([50 200]) ylim([50 200]) % colorbar at top colorbar('north'); set(gca,'Units','normalized'); description = 'Custom legend.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = doubleAxes() ah = axes; set(ah,'Units','pixels'); set(ah,'Position',[18*4 18*3 114*4 114*3]); ah2 = axes; set(ah2,'units','pixels') set(ah2,'position',[18*4 18*3 114*4 114*3]) grid(ah2,'on') set(ah2,'GridLineStyle','-') description = 'Double axes.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = pColorPlot() n = 6; r = (0:n)'/n; theta = pi*(-n:n)/n; X = r*cos(theta); Y = r*sin(theta); C = r*cos(2*theta); pcolor(X,Y,C) axis equal tight description = 'pcolor() plot.'; extraOpts = {}; end % ========================================================================= function [description, extraOpts] = hgTransformPlot() % Check out % http://www.mathworks.de/de/help/matlab/ref/hgtransform.html. ax = axes('XLim',[-2 1],'YLim',[-2 1],'ZLim',[-1 1]); view(3); grid on; axis equal; [x y z] = cylinder([.2 0]); h(1) = surface(x,y,z,'FaceColor','red'); h(2) = surface(x,y,-z,'FaceColor','green'); h(3) = surface(z,x,y,'FaceColor','blue'); h(4) = surface(-z,x,y,'FaceColor','cyan'); h(5) = surface(y,z,x,'FaceColor','magenta'); h(6) = surface(y,-z,x,'FaceColor','yellow'); t1 = hgtransform('Parent',ax); t2 = hgtransform('Parent',ax); set(h,'Parent',t1); h2 = copyobj(h,t2); Txy = makehgtform('translate',[-1.5 -1.5 0]); set(t2,'Matrix',Txy) drawnow description = 'hgtransform() plot.'; extraOpts = {}; end % ========================================================================= function env = getEnvironment if ~isempty(ver('MATLAB')) env = 'MATLAB'; elseif ~isempty(ver('Octave')) env = 'Octave'; else env = []; end end % ========================================================================= function [below, noenv] = isVersionBelow ( env, threshMajor, threshMinor ) % get version string for `env' by iterating over all toolboxes versionData = ver; versionString = ''; for k = 1:max(size(versionData)) if strcmp( versionData(k).Name, env ) % found it: store and exit the loop versionString = versionData(k).Version; break end end if isempty( versionString ) % couldn't find `env' below = true; noenv = true; return end majorVer = str2double(regexprep( versionString, '^(\d+)\..*', '$1' )); minorVer = str2double(regexprep( versionString, '^\d+\.(\d+\.?\d*)[^\d]*.*', '$1' )); if (majorVer < threshMajor) || (majorVer == threshMajor && minorVer < threshMinor) % version of `env' is below threshold below = true; else % version of `env' is same as or above threshold below = false; end noenv = false; end % ========================================================================= matlab2tikz-0.4.4/test/tex/000077500000000000000000000000001226131721500155225ustar00rootroot00000000000000matlab2tikz-0.4.4/test/tex/.gitignore000066400000000000000000000001771226131721500175170ustar00rootroot00000000000000acid.* # Don't commit acid.tex which is generated by ../matlab2tikz_acidtest.m # nor files generated by LaTeX run on acid.tex matlab2tikz-0.4.4/test/tex/Makefile000066400000000000000000000014631226131721500171660ustar00rootroot00000000000000# ./Makefile # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ECHOCMD:=/bin/echo -e PDFLATEX:=lualatex # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### TARGET:=acid # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### # default: main #main: main: eps2pdf @$(PDFLATEX) $(TARGET) .PHONY: clean # make sure the EPS's got converted to PDF's eps2pdf: @echo -e -n "Building PDF files..." @find ../data/ -name "*.eps" -exec epstopdf {} \; @echo -e " done.\n\n" clean: @rm -f $(TARGET).aux \ $(TARGET).log \ $(TARGET).nav \ $(TARGET).out \ $(TARGET).snm \ $(TARGET).toc \ $(TARGET).vrb \ $(TARGET).pdf \ $(TARGET).dvi \ $(TARGET).ps \ missfont.log @rm -f *~ distclean: clean @rm -f ../data/* @rm -f $(TARGET).tex matlab2tikz-0.4.4/tools/000077500000000000000000000000001226131721500151035ustar00rootroot00000000000000matlab2tikz-0.4.4/tools/cleanfigure.m000066400000000000000000000431721226131721500175540ustar00rootroot00000000000000function cleanfigure(varargin) % CLEANFIGURE() removes the unnecessary objects from your MATLAB plot % to give you a better experience with matlab2tikz. % CLEANFIGURE comes with several options that can be combined at will. % % CLEANFIGURE('handle',HANDLE,...) explicitly specifies the % handle of the figure that is to be stored. (default: gcf) % % CLEANFIGURE('minimumPointsDistance',DOUBLE,...) explicitly specified the % minimum distance between two points. (default: 1.0e-10) % % Example % x = -pi:pi/1000:pi; % y = tan(sin(x)) - sin(tan(x)); % plot(x,y,'--rs'); % cleanfigure(); % % Copyright (c) 2013, Nico Schlömer % All rights reserved. % % Redistribution and use in source and binary forms, with or without % modification, are permitted provided that the following conditions are % met: % % * Redistributions of source code must retain the above copyright % notice, this list of conditions and the following disclaimer. % * Redistributions in binary form must reproduce the above copyright % notice, this list of conditions and the following disclaimer in % the documentation and/or other materials provided with the distribution % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % Treat hidden handles, too. shh = get(0, 'ShowHiddenHandles'); set(0, 'ShowHiddenHandles', 'on'); % Keep track of the current axes. meta.gca = []; % Set up command line options. m2t.cmdOpts = matlab2tikzInputParser; m2t.cmdOpts = m2t.cmdOpts.addParamValue(m2t.cmdOpts, 'minimumPointDistance', 1.0e-10, @isnumeric); % Finally parse all the elements. m2t.cmdOpts = m2t.cmdOpts.parse(m2t.cmdOpts, varargin{:}); % Recurse down the tree of plot objects and clean up the leaves. recursiveCleanup(meta, gcf, m2t.cmdOpts.Results.minimumPointDistance, 0); % Reset to initial state. set(0, 'ShowHiddenHandles', shh); return; end % ========================================================================= function indent = recursiveCleanup(meta, h, minimumPointsDistance, indent) type = get(h, 'Type'); %display(sprintf([repmat(' ',1,indent), type, '->'])) % Don't try to be smart about quiver groups. % NOTE: % A better way to write `strcmp(get(h,...))` would be to use % isa(handle(h), 'specgraph.quivergroup'). % The handle() function isn't supported by Octave, though, so let's stick % with strcmp(). if strcmp(get(h, 'Type'), 'specgraph.quivergroup') %if strcmp(class(handle(h)), 'specgraph.quivergroup') return; end % Update the current axes. if strcmp(get(h, 'Type'), 'axes') meta.gca = h; end children = get(h, 'Children'); if ~isempty(children) for child = children(:)' indent = indent + 4; indent = recursiveCleanup(meta, child, minimumPointsDistance, indent); indent = indent - 4; end else % We're in a leaf, so apply all the fancy simplications. %% Skip invisible objects. %if ~strcmp(get(h, 'Visible'), 'on') % display(sprintf([repmat(' ',1,indent), ' invisible'])) % return; %end %display(sprintf([repmat(' ',1,indent), ' handle this'])) if strcmp(type, 'line') pruneOutsideBox(meta, h); % Move some points closer to the box to avoid TeX:DimensionTooLarge % errors. This may involve inserting extra points. movePointsCloser(meta, h); % Don't be too precise. coarsenLine(meta, h, minimumPointsDistance); elseif strcmp(type, 'text') % Check if text is inside bounds by checking if the Extent rectangle % and the axes box overlap. xlim = get(meta.gca, 'XLim'); ylim = get(meta.gca, 'YLim'); extent = get(h, 'Extent'); extent(3:4) = extent(1:2) + extent(3:4); overlap = xlim(1) < extent(3) && xlim(2) > extent(1) ... && ylim(1) < extent(4) && ylim(2) > extent(2); if ~overlap % Artificially disable visibility. m2t will check and skip. set(h, 'Visible', 'off'); end end end return; end % ========================================================================= function pruneOutsideBox(meta, handle) % Some sections of the line may sit outside of the visible box. % Cut those off. xData = get(handle, 'XData'); yData = get(handle, 'YData'); zData = get(handle, 'ZData'); if isempty(zData) data = [xData(:), yData(:)]; else data = [xData(:), yData(:), zData(:)]; end if isempty(data) return; end %hasLines = ~strcmp(lineStyle,'none') && lineWidth>0.0; %hasMarkers = ~strcmp(marker,'none'); hasLines = true; hasMarkers = true; xLim = get(meta.gca, 'XLim'); yLim = get(meta.gca, 'YLim'); tol = 1.0e-10; relaxedXLim = xLim + [-tol, tol]; relaxedYLim = yLim + [-tol, tol]; numPoints = size(data, 1); % Get which points are inside a (slightly larger) box. dataIsInBox = isInBox(data(:,1:2), ... relaxedXLim, relaxedYLim); % By default, don't plot any points. shouldPlot = false(numPoints, 1); if hasMarkers shouldPlot = shouldPlot | dataIsInBox; end if hasLines % Check if the connecting line is in the box. segvis = segmentVisible(data(:,1:2), ... dataIsInBox, xLim, yLim); % Plot points which are next to an edge which is in the box. shouldPlot = shouldPlot | [false; segvis] | [segvis; false]; end if ~all(shouldPlot) % There are two options here: % data = data(shouldPlot, :); % i.e., simply removing the data that isn't supposed to be plotted. % For line plots, this has the disadvantage that the line between two % 'loose' ends may now appear in the figure. % To avoid this, add a row of NaNs wherever a block of actual data is % removed. chunkIndices = []; k = 1; while k <= numPoints % fast forward to shouldPlot==True while k<=numPoints && ~shouldPlot(k) k = k+1; end kStart = k; % fast forward to shouldPlot==False while k<=numPoints && shouldPlot(k) k = k+1; end kEnd = k-1; if kStart <= kEnd chunkIndices = [chunkIndices; ... [kStart, kEnd]]; end end % Create masked data with NaN padding. % Make sure that there are no NaNs at the beginning of the data since % this would be interpreted as column names by Pgfplots. if size(chunkIndices, 1) > 0 ci = chunkIndices(1,:); newData = data(ci(1):ci(2), :); n = size(data, 2); for ci = chunkIndices(2:end,:)' newData = [newData; ... NaN(1, n); ... data(ci(1):ci(2), :)]; end data = newData; end end % Override with the new data. set(handle, 'XData', data(:, 1)); set(handle, 'YData', data(:, 2)); if ~isempty(zData) set(handle, 'ZData', data(:, 3)); end return; end % ========================================================================= function out = segmentVisible(data, dataIsInBox, xLim, yLim) % Given a bounding box {x,y}Lim, loop through all pairs of subsequent nodes % in p and determine whether the line between the pair crosses the box. n = size(data, 1); out = false(n-1, 1); for k = 1:n-1 out(k) = (dataIsInBox(k) && all(isfinite(data(k+1,:)))) ... % one of the neighbors is inside the box || (dataIsInBox(k+1) && all(isfinite(data(k,:)))) ... % and the other is finite || segmentsIntersect(data(k,:), data(k+1,:), ... [xLim(1);yLim(1)], [xLim(1);yLim(2)]) ... % left border || segmentsIntersect(data(k,:), data(k+1,:), ... [xLim(1);yLim(1)], [xLim(2);yLim(1)]) ... % bottom border || segmentsIntersect(data(k,:), data(k+1,:), ... [xLim(2);yLim(1)], [xLim(2);yLim(2)]) ... % right border || segmentsIntersect(data(k,:), data(k+1,:), ... [xLim(1);yLim(2)], [xLim(2);yLim(2)]); % top border end end % ========================================================================= function out = segmentsIntersect(X1, X2, X3, X4) % Checks whether the segments X1--X2 and X3--X4 intersect. lambda = crossLines(X1, X2, X3, X4); out = all(lambda > 0.0) && all(lambda < 1.0); return end % ========================================================================= function coarsenLine(meta, handle, minimumPointsDistance) % Reduce the number of data points in the line handle. % Given a minimum distance at which two nodes are considered different, % this can help with plots that contain a large amount of data points not % all of which need to be plotted. % if ( abs(minimumPointsDistance) < 1.0e-15 ) % bail out early return end % Extract the data from the current line handle. xData = get(handle, 'XData'); yData = get(handle, 'YData'); zData = get(handle, 'ZData'); if ~isempty(zData) % Don't do funny stuff when zData is present. return; end data = [xData(:), yData(:)]; if isempty(data) return; end % Generate a mask which is true for the first point, and all % subsequent points which have a greater norm2-distance from % the previous point than 'threshold'. n = size(data, 1); % Get info about log scaling. isXlog = strcmp(get(meta.gca, 'XScale'), 'log'); isYlog = strcmp(get(meta.gca, 'YScale'), 'log'); mask = false(n, 1); XRef = data(1,:); mask(1) = true; for kk = 2:n % Compute the visible distance of those points, % incorporating possible log-scaling of the axes. visDiff = XRef - data(kk,:); if isXlog % visDiff(1) = log10(XRef(1)) - log10(data(kk,1)); visDiff(1) = log10(visDiff(1)); end if isYlog visDiff(2) = log10(visDiff(2)); end % Check if it's larger than the threshold and % update the reference point in that case. if norm(visDiff) > minimumPointsDistance XRef = data(kk,:); mask(kk) = true; end end mask(end) = true; % Make sure to keep NaNs. mask = mask | any(isnan(data)')'; % Set the new (masked) data. set(handle, 'XData', data(mask, 1)); set(handle, 'YData', data(mask, 2)); return; end % ========================================================================= function movePointsCloser(meta, handle) % Move all points outside a box much larger than the visible one % to the boundary of that box and make sure that lines in the visible % box are preserved. This typically involves replacing one point by % two new ones and a NaN. % Extract the data from the current line handle. xData = get(handle, 'XData'); yData = get(handle, 'YData'); zData = get(handle, 'ZData'); if ~isempty(zData) && any(zData(1)~=zData) % Don't do funny stuff with varying zData. return; end data = [xData(:), yData(:)]; xlim = get(meta.gca, 'XLim'); ylim = get(meta.gca, 'YLim'); xWidth = xlim(2) - xlim(1); yWidth = ylim(2) - ylim(1); % Don't choose the larger box too large to make sure that the values inside % it can still be treated by TeX. extendFactor = 0.1; largeXLim = xlim + extendFactor * [-xWidth, xWidth]; largeYLim = ylim + extendFactor * [-yWidth, yWidth]; % Get which points are in an extended box (the limits of which % don't exceed TeX's memory). dataIsInLargeBox = isInBox(data(:,1:2), ... largeXLim, largeYLim); % Count the NaNs as being inside the box. dataIsInLargeBox = dataIsInLargeBox | any(isnan(data)')'; % Loop through all points which are to be included in the plot yet do not % fit into the extended box, and gather the points by which they are to be % replaced. replaceIndices = find(~dataIsInLargeBox)'; m = length(replaceIndices); r = cell(m, 1); for k = 1:m i = replaceIndices(k); r{k} = []; if i > 1 && all(isfinite(data(i-1,:))) newPoint = moveToBox(data(i,:), data(i-1,:), largeXLim, largeYLim); % Don't bother if the point is inf: % There's no intersection with the large box, so even the % connection between the two after they have been moved % won't be probably be visible. if all(isfinite(newPoint)) r{k} = [r{k}; newPoint]; end end if i < size(data,1) && all(isfinite(data(i+1,:))) newPoint = moveToBox(data(i,:), data(i+1,:), largeXLim, largeYLim); % Don't bother if the point is inf: % There's no intersection with the large box, so even the % connection between the two after they have been moved % won't be probably be visible. if all(isfinite(newPoint)) r{k} = [r{k}; newPoint]; end end end % Insert all r{k}{:} at replaceIndices[k]. dataNew = []; lastReplIndex = 0; lastEntryIsReplacement = false; for k = 1:m % Make sure that two subsequent moved points are separated by a NaN entry. % This is to make sure that there is no visible line between two moved % points that wasn't there before. d = data(lastReplIndex+1:replaceIndices(k)-1,:); if size(r{k}, 1) == 2 % Two replacement entries -- pad them with a NaN. rep = [r{k}(1, :); ... NaN(1, size(r{k}, 2)); ... r{k}(2, :)]; else rep = r{k}; end if isempty(d) && ~isempty(rep) && lastEntryIsReplacement % The last entry was a replacment, and the first one now is. % Prepend a NaN. rep = [NaN(1, size(r{k}, 2)); ... rep]; end % Add the data. if ~isempty(d) dataNew = [dataNew; ... d]; lastEntryIsReplacement = false; end if ~isempty(rep) dataNew = [dataNew; ... rep]; lastEntryIsReplacement = true; end lastReplIndex = replaceIndices(k); end dataNew = [dataNew; ... data(lastReplIndex+1:end,:)]; % Set the new (masked) data. set(handle, 'XData', dataNew(:,1)); set(handle, 'YData', dataNew(:,2)); if ~isempty(zData) % As per precondition, all zData entries are equal. zDataNew = zData(1) * ones(size(dataNew,1), 1); set(handle, 'zData', zDataNew); end return; end % ========================================================================= function xNew = moveToBox(x, xRef, xlim, ylim) % Takes a box defined by xlim, ylim, one point x and a reference point % xRef. % Returns the point xNew that sits on the line segment between x and xRef % *and* on the box. If several such points exist, take the closest one % to x. % Find out with which border the line x---xRef intersects, and determine % the smallest parameter alpha such that x + alpha*(xRef-x) % sits on the boundary. minAlpha = inf; % left boundary: lambda = crossLines(x, xRef, [xlim(1);ylim(1)], [xlim(1);ylim(2)]); if 0.0 < lambda(2) && lambda(2) < 1.0 && abs(minAlpha) > abs(lambda(1)) minAlpha = lambda(1); end % bottom boundary: lambda = crossLines(x, xRef, [xlim(1);ylim(1)], [xlim(2);ylim(1)]); if 0.0 < lambda(2) && lambda(2) < 1.0 && abs(minAlpha) > abs(lambda(1)) minAlpha = lambda(1); end % right boundary: lambda = crossLines(x, xRef, [xlim(2);ylim(1)], [xlim(2);ylim(2)]); if 0.0 < lambda(2) && lambda(2) < 1.0 && abs(minAlpha) > abs(lambda(1)) minAlpha = lambda(1); end % top boundary: lambda = crossLines(x, xRef, [xlim(1);ylim(2)], [xlim(2);ylim(2)]); if 0.0 < lambda(2) && lambda(2) < 1.0 && abs(minAlpha) > abs(lambda(1)) minAlpha = lambda(1); end % create the new point xNew = x + minAlpha*(xRef-x); end % ========================================================================= function out = isInBox(data, xLim, yLim) out = data(:,1) > xLim(1) & data(:,1) < xLim(2) ... & data(:,2) > yLim(1) & data(:,2) < yLim(2); end % ========================================================================= function lambda = crossLines(X1, X2, X3, X4) % Given four points X_k=(x_k,y_k), k\in{1,2,3,4}, and the two lines defined % by those, % % L1(lambda) = X1 + lambda (X2 - X1) % L2(lambda) = X3 + lambda (X4 - X3) % % returns the lambda for which they intersect (and Inf if they are parallel). % Technically, one needs to solve the 2x2 equation system % % x1 + lambda1 (x2-x1) = x3 + lambda2 (x4-x3) % y1 + lambda1 (y2-y1) = y3 + lambda2 (y4-y3) % % for lambda and mu. rhs = X3(:) - X1(:); % Divide by det even if it's 0: Infs are returned. % A = [X2-X1, -(X4-X3)]; detA = -(X2(1)-X1(1))*(X4(2)-X3(2)) + (X2(2)-X1(2))*(X4(1)-X3(1)); invA = [-(X4(2)-X3(2)), X4(1)-X3(1);... -(X2(2)-X1(2)), X2(1)-X1(1)] / detA; lambda = invA * rhs; end % ========================================================================= matlab2tikz-0.4.4/tools/figure2dot.m000066400000000000000000000116521226131721500173400ustar00rootroot00000000000000function figure2dot(filename) %FIGURE2DOT Save figure in Graphviz (.dot) file. % FIGURE2DOT() saves the current figure as dot-file. % % Copyright (c) 2008--2013, Nico Schlömer % All rights reserved. % % Redistribution and use in source and binary forms, with or without % modification, are permitted provided that the following conditions are % met: % % * Redistributions of source code must retain the above copyright % notice, this list of conditions and the following disclaimer. % * Redistributions in binary form must reproduce the above copyright % notice, this list of conditions and the following disclaimer in % the documentation and/or other materials provided with the distribution % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % % ========================================================================= global node_number % also show hidden handles set(0, 'ShowHiddenHandles', 'on'); filehandle = fopen(filename, 'w'); % start printing fprintf(filehandle, 'digraph simple_hierarchy {\n\n'); fprintf(filehandle, 'node[shape=box];\n\n'); % define the root node node_number = 0; p = get(gcf, 'Parent'); % define root element type = get(p, 'Type'); fprintf(filehandle, 'N%d [label="%s"]\n\n', node_number, type); % start recursion plot_children(filehandle, p, node_number); % finish off fprintf(filehandle, '}'); fclose(filehandle); set(0, 'ShowHiddenHandles', 'off'); end % ========================================================================= function plot_children(fh, h, id) global node_number % get the children children = get(h, 'Children'); % ----------------------------------------------------------------------- % loop through the children for child = children(:)' % define child number node_number = node_number + 1; type = get(child, 'Type'); % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % skip certain entries if strcmp(type, 'uimenu' ) || ... strcmp(type, 'uitoolbar' ) || ... strcmp(type, 'uicontextmenu') continue; end % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - label = cell(0); label = [label, sprintf('Type: %s', type)]; hClass = class(handle(child)); label = [label, sprintf('Class: %s', hClass)]; tag = get(child, 'Tag'); if ~isempty(tag) label = [label, sprintf('Tag: %s', tag)]; end visibility = get(child, 'Visible'); color = []; % set default value if ~strcmp(visibility, 'on') label = [label, sprintf('Visible: %s', visibility)]; color = 'gray'; end handlevisibility = get(child, 'HandleVisibility'); if ~strcmp(handlevisibility, 'on') label = [label, sprintf('HandleVisibility: %s', handlevisibility)]; end % gather options options = cell(0); if ~isempty(label) options = [options, ['label=', collapse(label,'\n')]]; end if ~isempty(color) options = [options, ['color=', color]]; end % print node fprintf(fh, 'N%d [label="%s"]\n', node_number, collapse(label, '\n')); % connect to the child fprintf(fh, 'N%d -> N%d;\n\n', id, node_number); % recurse plot_children(fh, child, node_number); end % ----------------------------------------------------------------------- end % ========================================================================= function newstr = collapse(cellstr, delimiter) % This function collapses a cell of strings to a single string (with a % given delimiter inbetween two strings, if desired). % % Example of usage: % collapse(cellstr, ',') if length(cellstr)<1 newstr = []; return end if isnumeric(cellstr{1}) newstr = my_num2str(cellstr{1}); else newstr = cellstr{1}; end for k = 2:length(cellstr) if isnumeric(cellstr{k}) str = my_num2str(cellstr{k}); else str = cellstr{k}; end newstr = [newstr, delimiter, str]; end end % ========================================================================= matlab2tikz-0.4.4/version-0.4.4000066400000000000000000000003301226131721500160100ustar00rootroot00000000000000This file is there to make sure that the HTML page http://www.mathworks.de/matlabcentral/fileexchange/22022-matlab2tikz/all_files contains the version number in clear text. This is used by the automatic updater.