From 49a726372eea231fe4c3170c8406b18c68932f23 Mon Sep 17 00:00:00 2001 From: Liam Toney <38269494+liamtoney@users.noreply.github.com> Date: Fri, 8 Nov 2019 14:39:08 -0900 Subject: [PATCH 1/7] Implement default position/box for legend (#359) Checks for presence of position/D arg before assigning default position ("JTR+jTR+o0.2c") and box ("+gwhite+p1p"). --- pygmt/base_plotting.py | 16 +++++++++++++--- .../baseline/test_legend_default_position.png | Bin 0 -> 25896 bytes pygmt/tests/test_legend.py | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 pygmt/tests/baseline/test_legend_default_position.png diff --git a/pygmt/base_plotting.py b/pygmt/base_plotting.py index f54cf2e2bd1..64dfbbbbf5d 100644 --- a/pygmt/base_plotting.py +++ b/pygmt/base_plotting.py @@ -621,7 +621,7 @@ def image(self, imagefile, **kwargs): @fmt_docstring @use_alias(R="region", J="projection", D="position", F="box") @kwargs_to_strings(R="sequence") - def legend(self, spec=None, **kwargs): + def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwargs): """ Plot legends on maps. @@ -644,13 +644,23 @@ def legend(self, spec=None, **kwargs): {R} position (D) : str ``'[g|j|J|n|x]refpoint+wwidth[/height][+jjustify][+lspacing][+odx[/dy]]'`` - Defines the reference point on the map for the legend. + Defines the reference point on the map for the legend. By default, uses + 'JTR+jTR+o0.2c' which places the legend at the top-right corner inside + the map frame, with a 0.2 cm offset. box (F) : bool or str ``'[+cclearances][+gfill][+i[[gap/]pen]][+p[pen]][+r[radius]][+s[[dx/dy/][shade]]]'`` Without further options, draws a rectangular border around the - legend using **MAP_FRAME_PEN**. + legend using **MAP_FRAME_PEN**. By default, uses '+gwhite+p1p' which draws + a box around the legend using a 1 point black pen and adds a white background. """ kwargs = self._preprocess(**kwargs) + + if "D" not in kwargs: + kwargs["D"] = position + + if "F" not in kwargs: + kwargs["F"] = box + with Session() as lib: if spec is None: specfile = "" diff --git a/pygmt/tests/baseline/test_legend_default_position.png b/pygmt/tests/baseline/test_legend_default_position.png new file mode 100644 index 0000000000000000000000000000000000000000..67bd7f2adc20c4e266d39a597b29fac6da229142 GIT binary patch literal 25896 zcmeHwcUV+O+HW;Ukt9YC0TmTd1Qa9)0*(qJ2q=mONH72*IW##m&I~9L#t{L@4gw02 zr5l>m4k)8UVW1^v8fbEApy}>geHv$Xzwh2Z_PO8g-Mwo)&qzO~-l}@*P4(8V>YRCW zSznuP%bqO&0KSXgpEm?xGyJ*f(PlRIXa1yXGW^5s^1X>W05THH|4`oP8lLc>sK8T|QLp0M4lt`8CWPnDrr4JVgy6A4(3>hPe8ZZH5ZGOL zM`Znqp^iE6%$l7!QLpu7bh{H5VebX}89kQL@-Lbv4J zaSbaV-OJ8iZ(Lq?@*W4jp2<9KJvcIoZCg^@-!T4kdC`)gPTE_?92-=3S{+;C8wc@Mo4EMT z$8x%C#*+&4dG`cAy&9t?i6XR%Szk9Y%JFLX99vVu@ujE&ZSp~w5c6p{ z*pD2HO8#ONYu&tgGNo`>#e{7v+$K`j;TFea@ZU;y|5z?g5?IAl=y9@n4_3?A`x=~Y zR7t<4_cFSBf^$;uFG>rw`f+u?Ed10|0aN#66Dw zt@S`zRQ?`@U8>g_ZLUPJ_#v0v-Nq@M>mYukd=pn(o;Q;zIqkXWwL}h(X_dk2vd?e2 za6%(PW4=knN^sXKD$cISJm#zfp&_}9{4}3qD_F1g@Nn}g^lU7Js((k*AYCGJ0cG|d zv;hA*UI4r^9J|UGYGg)-BEFz5hYtYK-R8{%b#4IqUtk?mnm#Af-5V2~0Hz3XXoZtT zaR7!(g@xs5b<$0vwy77?QUDqWse+hua_j)8qrF0v01$#^WaVcA!jCKSIBS@#{ehku zWwUZUhK|#oER4?(#&+a75xStPwI_pvTTkC+PAjolu#9ZQ0qzWFJQ?WQm;an^?P;2a zNsJ3;`(>QJ!1&x z994F2e_^6RaECnLrTgpQ*uGZ%njR(~G__2oQ4Dk|t+^@cUClZKs!a3i_C#J7o%xv2 z#IfaQ7w0$#W`~nk=BOAc%rftJ6=-8*)I;}+(9qGb6H21_h8ag~x^elPjQtl8BKpii ziu>9ntFwOz0@6(H)&)uLj~t_-Jx;F2o7nMuxdF*n$P1Z!C**@UpNV3jFKoKqyxC>5 zR-83AXuSQFaJ>t=AfWh}>&urw{2P_*?U2wK1|&)=JNx>54MfS?spGi@_un1gyIRu~ z6n%yNI&rC9q6=H$_hn3XWtbDyUZfR!s;GJ|Eo%PrYfE1}Oze(HcH`5k1RdTzD0QXD zRExC>67^7V{pZ~pt7Xkv6;aLoO>-}zZUg2m+T}!#s|KwCokBA z16e6m2YDD_YElLJw}#8<3W7vko!5?CSA3W6T{a{Zmu=h|VMU-wC+No8rI>DM3W`!`AFPUbgk#H4d_ze)d!*H_FP zIJkD}lZRWwd$%76^c|Ch)5*R?MeH|q1iD~2U};vO{y4OFX4$t7x+(LArY3W(f@Smf ztiMcCL(0B=tn~wM9ArJfU|6;Yw*I_9%C?R5+~gzid$nq zs0n^Q@XM^`h`ShC8f2L+LO5qmTw)9yft@_(SsTNN@`vXg67G@3Th>7Jv2d+|0ln^VL+FX*kK8F6VgQ?J#b`6xof@0f6u5_)Kw4F$VqBreRJr=f+p_R*F% zr}5mCL`XpLmyAy|pGSUWpdWi?&Zg|ZTSry@m3uxZpE)P+jo)dO70#)5`gwMBmU*1p zvhbv2?uk_mZs-FpjU?eZB=PQ{b8UpPc9Ztt2ki%f;*UgPf6c5epL?R56OrAW5?fN$ zZhtfHT9jOaR`Omo)AO$#&H5~mabV6zuQtia1CNDCc9<9aw(X;`XF{V%2aFAaF z)HiAQrd0^OVM7cDY&t7HRa|?dI=M~roczp4ihKl1rr1T#N7NlCf{5oSFBat}m9dRd{PV4=yMpGf zG#5-b=iH)IsWUkx{8Cv}#nXQ6u}~$=+S2FsHm`MIuxlAH-~LpnguF^_7eQ4Mg6-&U zmyoGxQ&Je~q>8YywBw#l4zNKzu#)urN(1V7j53P1>yM1578|irHqu6lmih1kK*LP z1YV|xWW7p_xB8@PF z8H_pVTFVQ1c9$P-_^hnhK$la{AZOoxLcJYfhUb=?xZ{^C=BNs?BThSh` z{bP1ZC-N9z9_*5G4dnw`xY?+dDAFb~#wKP3@>pCJd@p6hZqPmGdj6(-beN22%Y#z+#YYS{(5Hl%9OJIzBf$YvSW5 zw-c*#D@k=}*G&SzP{*+=lI>@0)x$(IjjYAYp#jK`5YX*@5(_4lcHa|v)ZK>7nP7EU zHh=L^8Qvl<`;>#FTccx_zU28ujiZ0OqGo07IdjL8rIPJZ>En81_v7sS(rQHgxl><6 z|FT45$@f!C1nOb{qY1dRSS5+0gi1&8WDbBN?SdTDzK!zd{MJi!61WYwq^?d$guwdOECFy z(T1%G3)u`9mK}w`%jhg(dbH=xE5nIYr54&1BcpMxiaRT$FKs(Vn_0%6k4bd54581W z*S0M?Ip3+;*+IGdvQec<6h{zd`CI?hfJ46Tc00t|;Dj~v$oOc(4lNnKhW%oGET*(~ z<2CnhuZ(<3>yH(M?dB!oF8r|}0 zuy1D5<*YLViH)k-m_sua&xkWNAbk(J+5u!RjF*GSeD5uvGwBMQUS7^poL1Ydm=)d~ z%kQV7TLKl?$3_yfvwW#unW~!<^orj7B$|vT<8Or*;EwT%v({2V9k%LFQ0P-26RT@Z z#Dz3C+|n8U{DiiEHrJ4<>5JHl&lOP*s<0rX_^wT4$1kSZX08 zjM{EfAzd+@ttm8GiPi6UirV_aAq;Z@{io8e4|R}^YMzTSRX+ZXa%`qAY?6jwPqTE6 zx51k>x_qQ}&81B})XqrY3vXX7o!TPjK%PtD5{h#@$aQq&B-{G_(QsQITG7tMM>q17b%9iy{8`^qM zxN~4|X-p|xXBL{}>zkxRZOTf}jZracfhJ4G#n$mZP|CYl{+a*lE#Zn>vZZ|Z=Ld>B z*9TJab|^4}l(%doKF9VPf5RZpNu>`IekVTdFQ=APJg*|M(KO~WjV>Q6cR$|dwP;kR z{aAI!hJSzgZM_X`<1|}V^4XKq#lwa*DSMNb$-UUAPOmviUf!C4+=h+3dyw5)?zL=~ zNxw-%8yP)wdaseO`_;%@@c5kHef7Z8!}zUv+8F5U0AF{s{aN3dLlBIN%< z??pWpF@MWUWUh>m4u0*&aAc_BS&n;Sl@qvpAA8=}}x$Dx+43+@Kv4G zBy`GK7w>0~rS57RPu3Gd8+7UtE+TcHfZx>tV$3YDhQnX>!$)>TuWlJ;V ztbQfEh2fRY-46t+qpmE^uJ=c`h~OqPq7-`l^lpT)fmNMOW)XQl>i)5+vvYe@*2;8xyr~`a$L1EORJxFV1EY{K3G{c6JU0a`$ zB$t!#Wlo%#?y_a~;u&%53M^T^l5(coqP$5?%dW=byXx7MN>p0S?KRIe0YV!0Cf$JV zrm>ElY9)e5X9R6S9U>Xs(N*D9INv0JHm@@E2=s`hr9EEuS*jv7na8<*pzB5Om(VD$ zPPE1bEPm3hc=CE+oC9=QbMIqzaf9%Hikif(SrXCaL?XF3Z?tNSEH8V-oXE4Q;VN8O z>At=6cnWoIz1?tqtT}eAs>y)U&xQ*bURr{b=Wod+U zoJJKbz=ScKl9AURWpV$sK>x?O-T>Lw*b0k0=wYK>CjPnH1+0X_>V(1lh9*aoHQC(n zmtBsv%X$x|*Z7?fz^rnB_uo%2$NCj-^s{)+M4&r`-$VJ=t`Ch8W#%mtyewVj$K2{E zO4-%Sp!hf~Z`!gA>}Zueo+EBo#{q+mfI5MS^fUwHYkYr{;sW3GX&q5tu%d@J4Yk@PM~}8|Cnq1nJRQ} z2*EZO`A;gbPHY5xJ!{;5{059Q&cDJ|@Ea#A34p&OlyL9sVxdC9I_lz(C~JiZqAeNg z*sb}uDtM*Xva?}scVegTxgN)mrn_b-eL)&Wy|)0J0*H_?3&&k9%@ZmlZH=s~`*ktM zBmY;qWXV$oVN6(yS^hE{E0X_R#{M&_k8hoTZ>|a% zdWe;K!;Hf#J4q_NMNd`sE0c?G6(O}LG^B~6&2iScNLT8MG#YJTK|X+faes6%Hwe2Z zbtZoO_Rf9G+Ws4Xfq@XKg8Tn}ht1!gYs>#Tcn^{3w}A3*7i7OV&o}4!x5x_u9Q`Y! zTSnZ*@wq`ah)W}GcJUcOESPF}QqyR9%7%$gWli9xJfS z)cr`-2WQimE9+=fV^Q^>}7uaw~R7AHN5i`j)LFOn|{W-h)7#CRh z;Ysfiv4X8EfR$6U;#0-67?2gtv0YqUe>l)*qtPXU^tH96&}h0zx7(f*q)|-D=}zaY zkd8*XjGj>|wo$a?fsJD0^$O(SWV2v)x2h@Iz2R!nZ5fY`jU-;xX*;j;aUH1zF-sSp z`90Z2A$Dc(0^ueE9|@4oli2Mi)xzy5>tHF6&1=&xnwvDP@F>D5Ei`MN-_Z?$J9 zT&f`?E?^taVgTt=Ve!_SL+;#ZLYmxti|q}bpg zT}soL=N73KuFsTKk{7Nb?Hyj{+K)6pD>onHFXL#=PDw~~H!{M79%f|}mp>giG<~%m z#J!$WZ$vtq#o9gc%K`ll-!Ep^g$V36;oQu8j*&Qh^O>J1bH;=#F|AkT5DeaGVyn@# z-J>oR?gh3s2eMH zh6FwOT<6q^v;mDauMaH1QwL}-_*`d`+QjBGrjZ$7heeZR(iIlij(=ehM&@37=J$FV zCCm?m{}y4HpzNw*8FC($pyuJVS>C^YljfrwVJP z-9!H8ML`&o^c!N07MHi zpdsyQ3_+ZC?P^3E`n1SkA-$05Wl+)4VF@wxvFFw#Eo64(Q`3&)lCN*YWVuxt5B4em zs|^FmH?!pjk=Bn7VGue@#J9xkU+F9wQOe()tYR2e4;E+cUI@q z58pq$L*F!^e}c>1%Axd@UyhQ)goiv@?2U7_H5})`25hx?<2ZfaM!JFdx`X;3B?x(* zVdwQ>EC+EV{|0>SjJ|57-JXhK>LJ#gHJhu)_`36k=DeqK(B{si+nJ9sJZIF^rzuoi zUXa{oYkM|=T&qHo>iVFRCbO2%RMNi|?%rR1@n9ND|o!LY|W#hWlqVi9~W| zH$YkKh}t++-X{q{Okzg5&B}VFV^k6EDrp{YS+N@ZxK*Du#c#gwO%6;6{JXilT)l!` znY@-WayZy;-;NIO>QvEd9n0zY3ZFd?({k<)6pgBNcg`XE*0FX|H^=7YT&w!30%$*+ zJz};UdQirA_rPug6ap;=#?S(*r0d4aXLtYULWtM=vlm3fCjYT(?zbVJ1pYbc%|A`l zW49K$riq2p3u;lloXk-PJJrsd(Q92?UK*NPnI?B*fLy&=6B!@*XSIe#iU>T9N%Q`C z9;1Sit1px$^>$8q;<}N%i0~7CX!Ry}gAkXE^Oyh8-0zcn-Jp;SQa4dMXy{>Sb#Q71QTRY_Xn4$3@mmdJLvb9ANb%1a41+Ijv6_vPh70JV9erXI=)N7ab}IxEi0!n)ohk2hNPf z>Va7*qhVovKKfS;nINZeiis!yipArL3}T)o86P4$01t1TGF#mA?E?AIb!47jVv{N= ze~inpGl_Y6+#)+7+??42J@4uzA@+U z6Mr=5=Oz2+asf=)NtZ_d)fN#h3=Tc`gQa?@Z|VA;JBa*Vn774nGP*Cjtq_C8paXz`H>@)xlBzV`QI5&Id6C3E~ z=S!5gv>tb?V(-`0&pqPg|Mc^hHWcVzNW8%bFf+_PdeU)QfaK$zNuE!Y)o_UBG}wuY zGn{!|@nVEN@SiWAwdFs#Uczh_#-$!s>wXdiN^F_>DPL6beG1ySvDR^sqJ<(4TFl)@<}g^w))#@)5{V*LyDV?!p$ zy6!X%OW)yN`lkCpF#eMKF0mU4@h<8 zsEe{tXrK}^D9%c;S5crOSCDIZ>jyJt5qsDPK3K$*9AN{PY*n$SG#sSF$wN+Z(w$w| ztR{^$sDpL@=y2%|z};@K0s!GGKE;@?SZI8FB~^YE3p*e3?*sk&zk|PI#IHlSXbaJ| zzQ|!C6iVj>tq(iu5Kn8JV5$A*OpxUN0jj+mnyLM98kA__`bDM6EMcay{CgGjlq#S8 z{v7(=N;stOitUvH<(1#BTw07Htu96FR_|iD)@!rgs37IN-E;v!2-pJ+?Gw|2o|ep| z5P9<$A$2oyEbUL(q?jf}a)N#*mg@P~2^YJS#|6Y0^CLu|JI0#;Cg*sa+YekW%6k+4 zijHX_!$1F4s#PFecQI+Df6txxjGklS>!Z7}*#Uu4fM%baWh!qiaWzI_8rt|r&X056 z{?uCOIyb}ba?$K`#IU%q_8@}+1fTQ-4d2;=}lEzrW zR8QWLXW0j7Q47uHCtYVTkO8st)q`gf%alvktUn;#D&}^9Q6En;sL=HjP+bEpUFvLO z@9TCk7Odvgn#}6^YMD_12bs53rvy&AD96zu+h)*6W2GyoG%5w{wGbR@{|iogn?>*a zJo+Id^khQRV&x^S3DCk}Jeb~o0je^`D=MY;BdCb{bn!d0zJ(BY z<)*UKj~{5%jrK8(t{ZAF$cYq0sSKo0*@0#; znJt6`5+R96jJxxcXPMbF0-E=K7g{~=!*j`V%%qT6zM;(Dl|DZ7nU3 zvAiU}^}<09x=MV8d#I%v>y&xLWSL4Uluq+{XZfc)eeL<5a_mH}?G;UvjC|`TbirL^ zto&S)^p9seUbP%B>I~g|a>`}?OdZ~A{W^!Qr%l0MCwGuV`K=3RLjS?CXs+wz@wO;#ubd%Tu+Tc*-rimv zsn94dbISOTv?jQr*GH+AdsDFmaY5nosw#0NSZ80rxfL-X4mVE1{rfq!mGF}2FUJtO zEHUiDO4=m9`Hgiw1#JChmf)Lu`YY_ldKvqxdar zUY#Dv1xL~q^yGP~r%N0Z6XxpXn*T6$UVLeZ4h@n-?6SRhJ(~JSkg^Sx+HR`Tp>ZJe z1G~p#*5(uty_=<&HDr8itu;fEbmp|Jx-8OcZ&5qatbv^{;CULp!nEE(p_QC%(I=vD z7OZHRIPRL+jpGBw?KI63V$rm<6HZ|YDyNk?A25a-ywDM>G3-lIq$r#c(_LJc${9+P zn&OR=y-Bx(Y=qyH#j=JX-f;aCKzm3HLG{apC$0>9JSF(_j&DV46WrIsvYjG7Qt40= zPz_vcgoK|N9`+f&UWdeWjJ(=fG_%>d+{yT1K@rv)()qt?r?~Ykivi1%9Zh3vWQk>l zBE`MS8tLpngX&0SU`;?akn>5(ZtCmV3b*xeNnPk^i>4L|Qob_=iKWW82_y#e^Pd@v zrbc2xe91gNcWA<~Hd9@xhG4@mG6Zd4i6fr6I&GrWExTKTmekdE6Mn6h6ZRI#}h6XSV zq6Vc+;;yw$D32A~sz+#wseK=Xs-Y&9YO>6BKYn!0lC`KaLT;5f99Wy1J3+n8R)2D^ zvM&KNWzSFzY}bZ@<6iz!#;1ymrS_sutGmD$Op>Ye#SiL3Jx?hldeKb|mpSa^Ey!9p zd&9!g64y1=nf<%R+(T7G;J;M(#FR{5k}3-Cm(}0A%#VyHR_9rkWNnMqDhe-2vF1s2 zf8!@^iwsfnW#A!oWbr3<%fb||PHaF)05sNwfZh9$S|^g0#B>9@eyMZA4W(^jw6st)Q0h7NAFslherU9R5wYC1sK{I!YUdnqBeIC}a8kTHV z+T-ecAfsE>Uba8zuyzp{|2U|PZaKIvvf5aJ^bL|5Zk`)0)#_H_1ytPk>XN>T0ac8V zQ@G)z?(vm+c7-8iK;Z3RuUAUi2KvckHCJZ> zNvk{vZ~YhR)kiGcY67~zW&0kD)8<6c$~aT<%OC5vX&sI=4mSw!4!@uC^jy*ECq32* zvKiYR?H40R;d5pyH*2T63sg5NG(6%9A6;9d4b+K++@g%ob3_j7Th<`_5U!e7e>zk5 zkUEM=jfU=f&}*-mNf%Z=aE;!&=<16K=9tYr3KWKNO2u@D-HOu+$XwrQ1z(BX~Ve z>^Y@#Gm{qcIAE<{QS$k%T-e5;rs5vxzr>Qa3ocm&sKp%GP&n9im`M*4^KYr#e{>%9 z_vGg{^rX^NZcn8nw(j2`$D5+Bsw-tLJLU6r8!%=)#i^E;OO6b%7YaFKjF_HFI*~}6 z^7LC-d35#&?l5?h5$!fPxVwx6nnhWc^|YJ99FTE~XCGpb|H)bL-=hsgSl>2W@VxY2 zBg<#mJ~M5w&qEB~ip$yAIX$|%wk(&r=(=kkwEP+BEur>5_d9)kQA|9o_{#>K##YK^ zb*i}iP9OZv!N+HaewiuGc6o#A1IRAuKYPpg%{l&mfK>?hb)*^u?PWLau7%uM@#r+s zG4Zo&V!h)DFq+Kl(g$tsHEC8YCtZr{eK5x=Dl46EUDdS)yx*0cLRpI(}@ z^Oo+K!nWg=kFE%qv6hu@Y0bA-!3?1PcCaI2`)#JwN=rZ17DV3L&+l0JUiDsdPi9mR zfR-Q7Cs3Wgd=yz9Y-Z{7K!<)Q@aFw4P2|be-*#Yj9xyVklAAWx%InJkW zi!nm+E$4?~_?Bh53bhknJ!z^()=(NyD%0yX5;7`|}> zo=LQOE=4&dF}>~wJj}gpe*DZb*OFtz@Dd_7sG8a-ul{-X3D!{~aGYA{*hQQ1G{+IL z5GwC`b(c!>_PXY6g?-bBrj(R>YBE&R-SRWP4FlFIGXO|RLu4zkrs5{}(v$36P<8;p zCJLqk4sW_A#3h14Ha2q1>8uG->ZW!nLExv|VD5FbqT67oWWtf9fEjp`h*=bm>6O|F zyVmw{tkf%>Jeq!K%g3A;1j7PV@^wr!C$UdU>#3i_#tMZgW@1IFyEJRBdpf5SrcAEh z*}!QO1x}98J!%3LfXigsqEgQ(yLm&&aTeay_;x+oFIUiOa+fBxab23B5_<(1o$!l{ zn5)JGP(m;_FJmDgBoXaymO20je)SBv9$Qe*B*&{%VUIi|oPy|jyTx}I_FCP~jlmZJ z3)0+liuh2Ku?4epwO*as^X$RizCPK6hk+1ls1(wIl&tZdx^oiv%*&OY9uH?ez|_u9 zb>YM{0wFq2KL<))n3Am-&An%tb%Z;sbQ<;j_A5^3L5X%=US2}OD2*0S)ZtHEo}yA_ z;5Sl;DM9qoWqkYG^0J~>nEkY8(yelZ;iV;XSx;_7%qf*ao{8I3`QQIucBfYAgqzN! z@*yq#N1~y(Ys>BoM}KkE35V6lgW;Znq3D&>1yUb;bF@i=u}+<-O0Zn0&n358?7k|S z9$gwpqzxxw9mRcjC#7fvIR%<;njNZ*qN?O)A4v}nYLL|6Pq56a@hl6NKR3YadQy3Z z#7v}UX3g(Xuxla6%HA;1naC$sZ+~S4K6v6)8+rBiTh&7!d`83S;>gB5P2wK8&|=OB zd}{+2*2k1)Q$Gk&#Kjj(s5@y*ce69(m4d^n zt|7sCU$`Kpao}OsPQY+>)9fkO!)%Muo*QQx)#S{8d!sg$TG_{N`=F}La;sQqT9JI< zY1FL2MC}Wj#MlPb{N^4+uIeW1@Y`V(B_L?<9PO!d2ZNNmzFZ$D=2gts5yliG_u+C? z&vI3!h%-61_lm0aib`bGL|%Qs4gWoNVqSa{{^o>Z1ePBIFn3Gdp6BECsHTAN0%B!~ zw;AxN8Z1t?J_=HXI57)trWAq8M099qVf*RT@~S8X!el<4tleE;1|smeT?XRSateCx zgQMK)@QNKQgrpL;8c{LWc|e~5+wTRchjEVf67tL{FkSOZVtV*EMr#PwX>cHAg4(-? z42UUnYd|82Oy$*O&O2*{@JqGrofO&tr(i6Nb$=(h!}{v<}=@27Z zW>u3^wQ-1~wx8ubfbGoZU77;6-Q{*}LAHQ@RbYGnUU~|L@>7N!s&QDOo=UvwFK>bL z(C^gob;I@*_xQisff5+SUS7IcgH}5<)9;I&nEjc1X6&YNX6O$(X$Qpj+nX;%^)#nX z_HJV(!rM*NUyqE6RHrof|X^-)L{0;jhlGwm_*J zEX2gTw@KyTI(ncGFv(ZVA1V5|2F+ajsA7OSdFI2eWl~2qs647xxSq$s_TI+In~nX= zZZQ)biOZ)l51CnUX~w0Pna{}o?pb=%M!U0UH6%TH{GDQC+Ve*Q`fZ6ig>(C^J8&J1 z(7X^0zdx^hykiGD@FUZOYF%-6F!8}Z!lUm9=KmvL(ycVwFe9N%ye}bMui&}pub|KK z)$gXgrwOCC|kpS*Y%b^LLICO7Z3^LJ6#&fctDll0vbzc6VO_;%n;hhd0{?PC$P z&|;svdh$N)Y9R737Au9Yoa(Bti~R@)y~zBJbB;BTY+_Xct`?t-?Y=5n_%bczi8tmYW+uPTgfJZ(24b}bt(|x_X)+)VT z?{-lrDAu#%IQpvs+qJXR>pvgDfPPsOQcBcSoq#?Kdl6iomwBwAoACjF$$*A(?Hw;> zH0~_>wS#JfA6##`=e$#n%$;CU+?^0S03~JNeOD?1*#B6IhLTcvcS$()fOh1Y#abG! zJc(WL7D^oREOIa8m=GmVi9w(j_+0Ah zA4@j@IDUB#>eU12O0%y+y}a20MhbRLdybOB4M>*{b+<^S4-c|gxm#|j-y;E`&~f#$ zY>`>)7v47~f`e_^gdnrcse6Xj?(%~AB>GODHI1!b8u)z-b?=(|wsR!}(j5v$$t<0Z zY1yoh8&je#yz!AtruSOyJhqcu-EH~HZ0ztCFxpBKKMCZ#dh{1l=Bqlg9vrh3 zjeo{2O*OO%lTNiR5Izzd9QIHebMztEWg11eQ}lzoP{^w@sFk*mC#R+kkY_#~mJik} z5IhJFzcux&{wrMZbAlp=J@Rt0^j9Dh|w`Cz{H?TYDw zuO7B+&PV)sn`Ta2#4}o_en#l?XIM-Ur&jx7Ezv+F`Z*!wwtYg&=4NikNd{XI`1hBV+rezI}q}Ow`hZmvtvq{*u>pCS=ru=$C=Xs8^6>?{T7+Q#p}#iz@Y^8u zct9U1(KgMtN#~-@M*85|HTXX=X1Zadhovhf^-Rt literal 0 HcmV?d00001 diff --git a/pygmt/tests/test_legend.py b/pygmt/tests/test_legend.py index b966b691e32..525574c5f90 100644 --- a/pygmt/tests/test_legend.py +++ b/pygmt/tests/test_legend.py @@ -28,6 +28,22 @@ def test_legend_position(): return fig +@pytest.mark.mpl_image_compare +def test_legend_default_position(): + """ + Try using the default legend position. + """ + + fig = Figure() + + fig.basemap(region=[-1, 1, -1, 1], frame=True) + + fig.plot(x=[0], y=[0], style="p10p", label="Default") + fig.legend() + + return fig + + @pytest.mark.mpl_image_compare def test_legend_entries(): """ From de69e589519dfab11c07867cb0e6d8c65eba4c21 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Sat, 9 Nov 2019 15:03:40 +1300 Subject: [PATCH 2/7] Allow passing in scalar number to x and y in plot (#376) Enables users to plot a single symbol easily by just giving an x and y coordinate e.g. `fig.plot(x=1.2, y=1.4)` instead of having to wrap things in a list (e.g. `fig.plot(x=[1.2], y=[1.4])`. This makes it consistent with `pygmt.Figure.text`. --- pygmt/base_plotting.py | 8 +++++--- pygmt/tests/baseline/test_plot_scalar_xy.png | Bin 0 -> 23654 bytes pygmt/tests/test_plot.py | 11 +++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 pygmt/tests/baseline/test_plot_scalar_xy.png diff --git a/pygmt/base_plotting.py b/pygmt/base_plotting.py index 64dfbbbbf5d..90648e02d6a 100644 --- a/pygmt/base_plotting.py +++ b/pygmt/base_plotting.py @@ -361,8 +361,8 @@ def plot(self, x=None, y=None, data=None, sizes=None, direction=None, **kwargs): Parameters ---------- - x, y : 1d arrays - Arrays of x and y coordinates of the data points. + x, y : float or 1d arrays + The x and y coordinates, or arrays of x and y coordinates of the data points data : str or 2d array Either a data file name or a 2d numpy array with the tabular data. Use option *columns* (i) to choose which columns are x, y, color, @@ -426,7 +426,9 @@ def plot(self, x=None, y=None, data=None, sizes=None, direction=None, **kwargs): elif kind == "matrix": file_context = lib.virtualfile_from_matrix(data) elif kind == "vectors": - file_context = lib.virtualfile_from_vectors(x, y, *extra_arrays) + file_context = lib.virtualfile_from_vectors( + np.atleast_1d(x), np.atleast_1d(y), *extra_arrays + ) with file_context as fname: arg_str = " ".join([fname, build_arg_string(kwargs)]) diff --git a/pygmt/tests/baseline/test_plot_scalar_xy.png b/pygmt/tests/baseline/test_plot_scalar_xy.png new file mode 100644 index 0000000000000000000000000000000000000000..44d36d4dea24e68411db715587f877931c5c5b88 GIT binary patch literal 23654 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

C*8ars@2vQgo=Hr>8 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 K$p6XVm;VEw%26Ev literal 0 HcmV?d00001 diff --git a/pygmt/tests/test_plot.py b/pygmt/tests/test_plot.py index 9233aa97786..e1f842b4642 100644 --- a/pygmt/tests/test_plot.py +++ b/pygmt/tests/test_plot.py @@ -256,3 +256,14 @@ def test_plot_vectors(): frame="af", ) return fig + + +@pytest.mark.mpl_image_compare +def test_plot_scalar_xy(): + "Plot symbols given scalar x, y coordinates" + fig = Figure() + fig.basemap(region=[-2, 2, -2, 2], frame=True) + fig.plot(x=-1.5, y=1.5, style="c1c") + fig.plot(x=0, y=0, style="t1c") + fig.plot(x=1.5, y=-1.5, style="s1c") + return fig From d2135dce934c65dbbc81c2527519e872e3c6e33d Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Sat, 9 Nov 2019 22:24:03 +1300 Subject: [PATCH 3/7] Allow passing in list to 'region' argument in surface (#378) --- pygmt/gridding.py | 6 ++++-- pygmt/tests/test_surface.py | 14 +++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pygmt/gridding.py b/pygmt/gridding.py index 0fe57c3ca9a..ed0da5b9c38 100644 --- a/pygmt/gridding.py +++ b/pygmt/gridding.py @@ -6,17 +6,19 @@ from .clib import Session from .helpers import ( build_arg_string, + data_kind, + dummy_context, fmt_docstring, GMTTempFile, + kwargs_to_strings, use_alias, - data_kind, - dummy_context, ) from .exceptions import GMTInvalidInput @fmt_docstring @use_alias(I="spacing", R="region", G="outfile") +@kwargs_to_strings(R="sequence") def surface(x=None, y=None, z=None, data=None, **kwargs): """ Grids table data using adjustable tension continuous curvature splines. diff --git a/pygmt/tests/test_surface.py b/pygmt/tests/test_surface.py index 7817bf12a1e..9af4f3f5bca 100644 --- a/pygmt/tests/test_surface.py +++ b/pygmt/tests/test_surface.py @@ -21,7 +21,7 @@ def test_surface_input_file(): Run surface by passing in a filename """ fname = which("@tut_ship.xyz", download="c") - output = surface(data=fname, spacing="5m", region="245/255/20/30") + output = surface(data=fname, spacing="5m", region=[245, 255, 20, 30]) assert isinstance(output, xr.Dataset) return output @@ -32,7 +32,7 @@ def test_surface_input_data_array(): """ ship_data = load_sample_bathymetry() data = ship_data.values # convert pandas.DataFrame to numpy.ndarray - output = surface(data=data, spacing="5m", region="245/255/20/30") + output = surface(data=data, spacing="5m", region=[245, 255, 20, 30]) assert isinstance(output, xr.Dataset) return output @@ -47,7 +47,7 @@ def test_surface_input_xyz(): y=ship_data.latitude, z=ship_data.bathymetry, spacing="5m", - region="245/255/20/30", + region=[245, 255, 20, 30], ) assert isinstance(output, xr.Dataset) return output @@ -63,7 +63,7 @@ def test_surface_input_xy_no_z(): x=ship_data.longitude, y=ship_data.latitude, spacing="5m", - region="245/255/20/30", + region=[245, 255, 20, 30], ) @@ -75,7 +75,7 @@ def test_surface_wrong_kind_of_input(): data = ship_data.bathymetry.to_xarray() # convert pandas.Series to xarray.DataArray assert data_kind(data) == "grid" with pytest.raises(GMTInvalidInput): - surface(data=data, spacing="5m", region="245/255/20/30") + surface(data=data, spacing="5m", region=[245, 255, 20, 30]) def test_surface_with_outfile_param(): @@ -86,7 +86,7 @@ def test_surface_with_outfile_param(): data = ship_data.values # convert pandas.DataFrame to numpy.ndarray try: output = surface( - data=data, spacing="5m", region="245/255/20/30", outfile=TEMP_GRID + data=data, spacing="5m", region=[245, 255, 20, 30], outfile=TEMP_GRID ) assert output is None # check that output is None since outfile is set assert os.path.exists(path=TEMP_GRID) # check that outfile exists at path @@ -104,7 +104,7 @@ def test_surface_short_aliases(): ship_data = load_sample_bathymetry() data = ship_data.values # convert pandas.DataFrame to numpy.ndarray try: - output = surface(data=data, I="5m", R="245/255/20/30", G=TEMP_GRID) + output = surface(data=data, I="5m", R=[245, 255, 20, 30], G=TEMP_GRID) assert output is None # check that output is None since outfile is set assert os.path.exists(path=TEMP_GRID) # check that outfile exists at path grid = xr.open_dataset(TEMP_GRID) From 63d23d4e0702edb94234f10d23d210cdf1adb54b Mon Sep 17 00:00:00 2001 From: Mark Wieczorek Date: Mon, 11 Nov 2019 06:18:03 +0100 Subject: [PATCH 4/7] Allow for grids with negative lat/lon increments (#369) Flips grids with negative latitude/longitude increments properly using xarray sortby(). Includes tests that check to make sure that dataarray_to_matrix works for standard case where longitude (x) and latitude (y) dimensions of grids are in positive increments (ascending order). Also ensures that grids are flipped correctly when the x and/or y axis are in negative increments (descending order). --- pygmt/clib/conversion.py | 11 +++++++-- pygmt/tests/test_clib.py | 52 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/pygmt/clib/conversion.py b/pygmt/clib/conversion.py index a1bdaeeb44a..f86a1c6261d 100644 --- a/pygmt/clib/conversion.py +++ b/pygmt/clib/conversion.py @@ -9,13 +9,15 @@ def dataarray_to_matrix(grid): """ - Transform a xarray.DataArray into a data 2D array and metadata. + Transform an xarray.DataArray into a data 2D array and metadata. Use this to extract the underlying numpy array of data and the region and increment for the grid. Only allows grids with two dimensions and constant grid spacing (GMT - doesn't allow variable grid spacing). + doesn't allow variable grid spacing). If the latitude and/or longitude + increments of the input grid are negative, the output matrix will be + sorted by the DataArray coordinates to yield positive increments. If the underlying data array is not C contiguous, for example if it's a slice of a larger grid, a copy will need to be generated. @@ -102,6 +104,11 @@ def dataarray_to_matrix(grid): ) region.extend([coord.min(), coord.max()]) inc.append(coord_inc) + + if any([i < 0 for i in inc]): # Sort grid when there are negative increments + inc = [abs(i) for i in inc] + grid = grid.sortby(variables=list(grid.dims), ascending=True) + matrix = as_c_contiguous(grid.values[::-1]) return matrix, region, inc diff --git a/pygmt/tests/test_clib.py b/pygmt/tests/test_clib.py index f507f16d034..e02d8ed5fd4 100644 --- a/pygmt/tests/test_clib.py +++ b/pygmt/tests/test_clib.py @@ -764,6 +764,58 @@ def test_write_data_fails(): ) +def test_dataarray_to_matrix_works(): + "Check that dataarray_to_matrix returns correct output" + data = np.diag(v=np.arange(3)) + x = np.linspace(start=0, stop=4, num=3) + y = np.linspace(start=5, stop=9, num=3) + grid = xr.DataArray(data, coords=[("y", y), ("x", x)]) + + matrix, region, inc = dataarray_to_matrix(grid) + npt.assert_allclose(actual=matrix, desired=np.flipud(data)) + npt.assert_allclose(actual=region, desired=[x.min(), x.max(), y.min(), y.max()]) + npt.assert_allclose(actual=inc, desired=[x[1] - x[0], y[1] - y[0]]) + + +def test_dataarray_to_matrix_negative_x_increment(): + "Check that dataarray_to_matrix returns correct output with flipped x dimensions" + data = np.diag(v=np.arange(3)) + x = np.linspace(start=4, stop=0, num=3) + y = np.linspace(start=5, stop=9, num=3) + grid = xr.DataArray(data, coords=[("y", y), ("x", x)]) + + matrix, region, inc = dataarray_to_matrix(grid) + npt.assert_allclose(actual=matrix, desired=np.flip(data, axis=(0, 1))) + npt.assert_allclose(actual=region, desired=[x.min(), x.max(), y.min(), y.max()]) + npt.assert_allclose(actual=inc, desired=[abs(x[1] - x[0]), abs(y[1] - y[0])]) + + +def test_dataarray_to_matrix_negative_y_increment(): + "Check that dataarray_to_matrix returns correct output with flipped y dimensions" + data = np.diag(v=np.arange(3)) + x = np.linspace(start=0, stop=4, num=3) + y = np.linspace(start=9, stop=5, num=3) + grid = xr.DataArray(data, coords=[("y", y), ("x", x)]) + + matrix, region, inc = dataarray_to_matrix(grid) + npt.assert_allclose(actual=matrix, desired=data) + npt.assert_allclose(actual=region, desired=[x.min(), x.max(), y.min(), y.max()]) + npt.assert_allclose(actual=inc, desired=[abs(x[1] - x[0]), abs(y[1] - y[0])]) + + +def test_dataarray_to_matrix_negative_x_and_y_increment(): + "Check that dataarray_to_matrix returns correct output with flipped x/y dimensions" + data = np.diag(v=np.arange(3)) + x = np.linspace(start=4, stop=0, num=3) + y = np.linspace(start=9, stop=5, num=3) + grid = xr.DataArray(data, coords=[("y", y), ("x", x)]) + + matrix, region, inc = dataarray_to_matrix(grid) + npt.assert_allclose(actual=matrix, desired=np.fliplr(data)) + npt.assert_allclose(actual=region, desired=[x.min(), x.max(), y.min(), y.max()]) + npt.assert_allclose(actual=inc, desired=[abs(x[1] - x[0]), abs(y[1] - y[0])]) + + def test_dataarray_to_matrix_dims_fails(): "Check that it fails for > 2 dims" # Make a 3D regular grid From 343c7adbd57e6fd2b0824cd1d14bfd68314acefc Mon Sep 17 00:00:00 2001 From: Leonardo Uieda Date: Thu, 28 Nov 2019 09:33:29 +0000 Subject: [PATCH 5/7] Wrap docstrings to 79 chars and check with flake8 (#384) Jupyter, IPython, and other IDEs don't usually render the rst in the docstrings and just show them literally. The problem is that many of these break lines at 79 characters. So docstrings with more characters look terrible in these settings and sometimes almost unreadable. Wrap all docstrings to 79 characters instead of Black's 88. Set `max-doc-length=79` to make flake8 check if any docstring exceeds it. The setting checks comments as well and we found no way of disabling that. So we'll format comments to 79 characters for consistency as well. Minor modifications to the first line of some docstrings was required to make them fit into a single line. Also made minor modifications on some doctests to wrap to 79 characters. --- .gitignore | 1 + CONTRIBUTING.md | 15 +- pygmt/__init__.py | 12 +- pygmt/base_plotting.py | 171 ++++++++++----------- pygmt/clib/__init__.py | 4 +- pygmt/clib/loading.py | 8 +- pygmt/clib/session.py | 264 ++++++++++++++++++--------------- pygmt/datasets/earth_relief.py | 5 +- pygmt/datasets/tutorial.py | 5 +- pygmt/exceptions.py | 4 +- pygmt/figure.py | 28 ++-- pygmt/gridding.py | 7 +- pygmt/helpers/decorators.py | 4 +- pygmt/helpers/utils.py | 16 -- pygmt/mathops.py | 45 +++--- pygmt/session_management.py | 6 +- pygmt/sphinx_gallery.py | 7 +- pygmt/tests/test_clib.py | 10 +- pygmt/tests/test_colorbar.py | 13 +- pygmt/tests/test_helpers.py | 20 ++- pygmt/tests/test_makecpt.py | 10 +- pygmt/tests/test_surface.py | 3 +- pygmt/tests/test_text.py | 5 +- setup.cfg | 4 + 24 files changed, 365 insertions(+), 302 deletions(-) diff --git a/.gitignore b/.gitignore index 6573fc43a34..7e18dc2d5bb 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ MANIFEST .pytest_cache/ .ipynb_checkpoints/ .vscode/ +tmp-test-dir-with-unique-name/ build/ dist/ doc/_build diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f4b09da6834..98c1ef166a5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -269,6 +269,17 @@ make check # Runs flake8 and black (in check mode) make lint # Runs pylint, which is a bit slower ``` +#### Docstrings + +**All docstrings** should follow the +[numpy style guide](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard). +All functions/classes/methods should have docstrings with a full description of all +arguments and return values. + +While the maximum line length for code is automatically set by *Black*, docstrings +must be formatted manually. To play nicely with Jupyter and IPython, **keep docstrings +limited to 79 characters** per line. + ### Testing your code Automated testing helps ensure that our code is as free of bugs as it can be. @@ -360,7 +371,7 @@ Sphinx will create a link to the automatically generated page for that function/class/module. **All docstrings** should follow the -[numpy style guide](https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt). +[numpy style guide](https://numpydoc.readthedocs.io/en/latest/format.html). All functions/classes/methods should have docstrings with a full description of all arguments and return values. @@ -379,7 +390,7 @@ Some things that will increase the chance that your pull request is accepted qui *reason* behind non-obvious things. * Include an example of new features in the gallery or tutorials. * Follow the [PEP8](http://pep8.org) style guide for code and the - [numpy guide](https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt) + [numpy guide](https://numpydoc.readthedocs.io/en/latest/format.html) for documentation. Pull requests will automatically have tests run by TravisCI. diff --git a/pygmt/__init__.py b/pygmt/__init__.py index b886a267acf..2c035e913ef 100644 --- a/pygmt/__init__.py +++ b/pygmt/__init__.py @@ -2,10 +2,10 @@ # # The main API for PyGMT. # -# All of PyGMT is operated on a "modern mode session" (new to GMT6). When you import the -# pygmt library, a new session will be started automatically. The session will be -# closed when the current Python process terminates. Thus, the Python API does not -# expose the `gmt begin` and `gmt end` commands. +# All of PyGMT is operated on a "modern mode session" (new to GMT6). When you +# import the pygmt library, a new session will be started automatically. The +# session will be closed when the current Python process terminates. Thus, the +# Python API does not expose the `gmt begin` and `gmt end` commands. import atexit as _atexit @@ -34,8 +34,8 @@ def print_clib_info(): """ Print information about the GMT shared library that we can find. - Includes the GMT version, default values for parameters, the path to the ``libgmt`` - shared library, and GMT directories. + Includes the GMT version, default values for parameters, the path to the + ``libgmt`` shared library, and GMT directories. """ from .clib import Session diff --git a/pygmt/base_plotting.py b/pygmt/base_plotting.py index 90648e02d6a..575880c43eb 100644 --- a/pygmt/base_plotting.py +++ b/pygmt/base_plotting.py @@ -36,8 +36,8 @@ def _preprocess(self, **kwargs): # pylint: disable=no-self-use insert special arguments into the kwargs or make any actions that are required before ``call_module``. - For example, the :class:`pygmt.Figure` needs this to tell the GMT modules - to plot to a specific figure. + For example, the :class:`pygmt.Figure` needs this to tell the GMT + modules to plot to a specific figure. This is a dummy method that does nothing. @@ -147,63 +147,61 @@ def colorbar(self, **kwargs): """ Plot a gray or color scale-bar on maps. - Both horizontal and vertical scales are supported. For CPTs with gradational - colors (i.e., the lower and upper boundary of an interval have different colors) - we will interpolate to give a continuous scale. Variations in intensity due to - shading/illumination may be displayed by setting the option -I. Colors may be - spaced according to a linear scale, all be equal size, or by providing a file - with individual tile widths. + Both horizontal and vertical scales are supported. For CPTs with + gradational colors (i.e., the lower and upper boundary of an interval + have different colors) we will interpolate to give a continuous scale. + Variations in intensity due to shading/illumination may be displayed by + setting the option -I. Colors may be spaced according to a linear + scale, all be equal size, or by providing a file with individual tile + widths. Full option list at :gmt-docs:`colorbar.html` Parameters ---------- position (D) : str - ``[g|j|J|n|x]refpoint[+wlength[/width]][+e[b|f][length]][+h|v][+jjustify] - [+m[a|c|l|u]][+n[txt]][+odx[/dy]]``. - Defines the reference point on the map for the color scale using one of four - coordinate systems: - (1) Use -Dg for map (user) coordinates, - (2) use -Dj or -DJ for setting refpoint via a 2-char justification code that - refers to the (invisible) map domain rectangle, - (3) use -Dn for normalized (0-1) coordinates, or - (4) use -Dx for plot coordinates (inches, cm, etc.).\ - All but -Dx requires both -R and -J to be specified. - Append +w followed by the length and width of the color bar. - If width is not specified then it is set to 4% of the given length. - Give a negative length to reverse the scale bar. - Append +h to get a horizontal scale [Default is vertical (+v)]. - By default, the anchor point on the scale is assumed to be the bottom left - corner (BL), but this can be changed by appending +j followed by a 2-char - justification code justify. + ``[g|j|J|n|x]refpoint[+wlength[/width]][+e[b|f][length]][+h|v] + [+jjustify][+m[a|c|l|u]][+n[txt]][+odx[/dy]]``. Defines the + reference point on the map for the color scale using one of four + coordinate systems: (1) Use -Dg for map (user) coordinates, (2) use + -Dj or -DJ for setting refpoint via a 2-char justification code + that refers to the (invisible) map domain rectangle, (3) use -Dn + for normalized (0-1) coordinates, or (4) use -Dx for plot + coordinates (inches, cm, etc.). All but -Dx requires both -R and + -J to be specified. Append +w followed by the length and width of + the color bar. If width is not specified then it is set to 4% of + the given length. Give a negative length to reverse the scale bar. + Append +h to get a horizontal scale [Default is vertical (+v)]. By + default, the anchor point on the scale is assumed to be the bottom + left corner (BL), but this can be changed by appending +j followed + by a 2-char justification code justify. box (F) : bool or str - ``[+cclearances][+gfill][+i[[gap/]pen]][+p[pen]][+r[radius]][+s[[dx/dy/] - [shade]]]``. - If set to True, draws a rectangular border around the color scale. - Alternatively, specify a different pen with +ppen. - Add +gfill to fill the scale panel [no fill]. + ``[+cclearances][+gfill][+i[[gap/]pen]][+p[pen]][+r[radius]] + [+s[[dx/dy/][shade]]]``. If set to True, draws a rectangular + border around the color scale. Alternatively, specify a different + pen with +ppen. Add +gfill to fill the scale panel [no fill]. Append +cclearance where clearance is either gap, xgap/ygap, or - lgap/rgap/bgap/tgap where these items are uniform, separate in x- and - y-direction, or individual side spacings between scale and border. - Append +i to draw a secondary, inner border as well. We use a uniform gap - between borders of 2p and the MAP_DEFAULTS_PEN unless other values are - specified. - Append +r to draw rounded rectangular borders instead, with a 6p corner - radius. You can override this radius by appending another value. - Finally, append +s to draw an offset background shaded region. Here, dx/dy - indicates the shift relative to the foreground frame [4p/-4p] and shade sets - the fill style to use for shading [gray50]. + lgap/rgap/bgap/tgap where these items are uniform, separate in x- + and y-direction, or individual side spacings between scale and + border. Append +i to draw a secondary, inner border as well. We use + a uniform gap between borders of 2p and the MAP_DEFAULTS_PEN unless + other values are specified. Append +r to draw rounded rectangular + borders instead, with a 6p corner radius. You can override this + radius by appending another value. Finally, append +s to draw an + offset background shaded region. Here, dx/dy indicates the shift + relative to the foreground frame [4p/-4p] and shade sets the fill + style to use for shading [gray50]. truncate (G) : list or str - ``zlo/zhi`` - Truncate the incoming CPT so that the lowest and highest z-levels are to zlo - and zhi. If one of these equal NaN then we leave that end of the CPT alone. - The truncation takes place before the plotting. + ``zlo/zhi`` Truncate the incoming CPT so that the lowest and + highest z-levels are to zlo and zhi. If one of these equal NaN then + we leave that end of the CPT alone. The truncation takes place + before the plotting. scale (W) : float - Multiply all z-values in the CPT by the provided scale. By default the CPT - is used as is. + Multiply all z-values in the CPT by the provided scale. By default + the CPT is used as is. {aliases} """ @@ -362,7 +360,8 @@ def plot(self, x=None, y=None, data=None, sizes=None, direction=None, **kwargs): Parameters ---------- x, y : float or 1d arrays - The x and y coordinates, or arrays of x and y coordinates of the data points + The x and y coordinates, or arrays of x and y coordinates of the + data points data : str or 2d array Either a data file name or a 2d numpy array with the tabular data. Use option *columns* (i) to choose which columns are x, y, color, @@ -594,7 +593,8 @@ def image(self, imagefile, **kwargs): """ Place images or EPS files on maps. - Reads an Encapsulated PostScript file or a raster image file and plots it on a map. + Reads an Encapsulated PostScript file or a raster image file and plots + it on a map. Full option list at :gmt-docs:`image.html` @@ -605,12 +605,13 @@ def image(self, imagefile, **kwargs): {J} {R} D: str - ``'[g|j|J|n|x]refpoint+rdpi+w[-]width[/height][+jjustify][+nnx[/ny]][+odx[/dy]]'`` - Sets reference point on the map for the image. + ``'[g|j|J|n|x]refpoint+rdpi+w[-]width[/height][+jjustify] + [+nnx[/ny]][+odx[/dy]]'`` Sets reference point on the map for the + image. F : bool or str - ``'[+cclearances][+gfill][+i[[gap/]pen]][+p[pen]][+r[radius]][+s[[dx/dy/][shade]]]'`` - Without further options, draws a rectangular border around the - image using **MAP_FRAME_PEN**. + ``'[+cclearances][+gfill][+i[[gap/]pen]][+p[pen]][+r[radius]] + [+s[[dx/dy/][shade]]]'`` Without further options, draws a + rectangular border around the image using **MAP_FRAME_PEN**. M : bool Convert color image to monochrome grayshades using the (television) YIQ-transformation. @@ -627,11 +628,11 @@ def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwarg """ Plot legends on maps. - Makes legends that can be overlaid on maps. Reads specific legend-related - information from an input file, or automatically creates legend entries from - plotted symbols that have labels. Unless otherwise noted, annotations will be - made using the primary annotation font and size in effect - (i.e., FONT_ANNOT_PRIMARY). + Makes legends that can be overlaid on maps. Reads specific + legend-related information from an input file, or automatically creates + legend entries from plotted symbols that have labels. Unless otherwise + noted, annotations will be made using the primary annotation font and + size in effect (i.e., FONT_ANNOT_PRIMARY). Full option list at :gmt-docs:`legend.html` @@ -641,19 +642,21 @@ def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwarg ---------- spec : None or str Either None (default) for using the automatically generated legend - specification file, or a filename pointing to the legend specification file. + specification file, or a filename pointing to the legend + specification file. {J} {R} position (D) : str - ``'[g|j|J|n|x]refpoint+wwidth[/height][+jjustify][+lspacing][+odx[/dy]]'`` - Defines the reference point on the map for the legend. By default, uses - 'JTR+jTR+o0.2c' which places the legend at the top-right corner inside - the map frame, with a 0.2 cm offset. + ``'[g|j|J|n|x]refpoint+wwidth[/height][+jjustify][+lspacing] + [+odx[/dy]]'`` Defines the reference point on the map for the + legend. By default, uses 'JTR+jTR+o0.2c' which places the legend at + the top-right corner inside the map frame, with a 0.2 cm offset. box (F) : bool or str - ``'[+cclearances][+gfill][+i[[gap/]pen]][+p[pen]][+r[radius]][+s[[dx/dy/][shade]]]'`` - Without further options, draws a rectangular border around the - legend using **MAP_FRAME_PEN**. By default, uses '+gwhite+p1p' which draws - a box around the legend using a 1 point black pen and adds a white background. + ``'[+cclearances][+gfill][+i[[gap/]pen]][+p[pen]][+r[radius]] + [+s[[dx/dy/][shade]]]'`` Without further options, draws a + rectangular border around the legend using **MAP_FRAME_PEN**. By + default, uses '+gwhite+p1p' which draws a box around the legend + using a 1 point black pen and adds a white background. """ kwargs = self._preprocess(**kwargs) @@ -709,28 +712,30 @@ def text( Parameters ---------- textfiles : str or list - A text data file name, or a list of filenames containing 1 or more records - with (x, y[, font, angle, justify], text). + A text data file name, or a list of filenames containing 1 or more + records with (x, y[, font, angle, justify], text). x, y : float or 1d arrays - The x and y coordinates, or an array of x and y coordinates to plot the text + The x and y coordinates, or an array of x and y coordinates to plot + the text text : str or 1d array The text string, or an array of strings to plot on the figure angle: int/float or bool - Set the angle measured in degrees counter-clockwise from horizontal. E.g. 30 - sets the text at 30 degrees. If no angle is given then the input textfile(s) - must have this as a column. + Set the angle measured in degrees counter-clockwise from + horizontal. E.g. 30 sets the text at 30 degrees. If no angle is + given then the input textfile(s) must have this as a column. font : str or bool - Set the font specification with format "size,font,color" where size is text - size in points, font is the font to use, and color sets the font color. E.g. - "12p,Helvetica-Bold,red" selects a 12p red Helvetica-Bold font. If no font - info is given then the input textfile(s) must have this information in one - of its columns. + Set the font specification with format "size,font,color" where size + is text size in points, font is the font to use, and color sets the + font color. E.g. "12p,Helvetica-Bold,red" selects a 12p red + Helvetica-Bold font. If no font info is given then the input + textfile(s) must have this information in one of its columns. justify: str or bool - Set the alignment which refers to the part of the text string that will be - mapped onto the (x,y) point. Choose a 2 character combination of L, C, R - (for left, center, or right) and T, M, B for top, middle, or bottom. E.g., - BL for lower left. If no justification is given then the input textfile(s) - must have this as a column. + Set the alignment which refers to the part of the text string that + will be mapped onto the (x,y) point. Choose a 2 character + combination of L, C, R (for left, center, or right) and T, M, B for + top, middle, or bottom. E.g., BL for lower left. If no + justification is given then the input textfile(s) must have this as + a column. {J} {R} """ diff --git a/pygmt/clib/__init__.py b/pygmt/clib/__init__.py index 5840e216a17..a6282f84122 100644 --- a/pygmt/clib/__init__.py +++ b/pygmt/clib/__init__.py @@ -2,7 +2,7 @@ # # Low-level wrapper for the GMT C API. # -# The pygmt.clib.Session class wraps the GMT C shared library (libgmt) with a pythonic -# interface. Access to the C library is done through ctypes. +# The pygmt.clib.Session class wraps the GMT C shared library (libgmt) with a +# pythonic interface. Access to the C library is done through ctypes. from .session import Session diff --git a/pygmt/clib/loading.py b/pygmt/clib/loading.py index 2de978534f3..58b33196e85 100644 --- a/pygmt/clib/loading.py +++ b/pygmt/clib/loading.py @@ -1,8 +1,8 @@ """ Utility functions to load libgmt as ctypes.CDLL. -The path to the shared library can be found automatically by ctypes or set through the -GMT_LIBRARY_PATH environment variable. +The path to the shared library can be found automatically by ctypes or set +through the GMT_LIBRARY_PATH environment variable. """ import os import sys @@ -91,8 +91,8 @@ def clib_name(os_name=None, is_64bit=None): The operating system name as given by ``sys.platform`` (the default if None). is_64bit : bool or None - Whether or not the OS is 64bit. Only used if the OS is ``win32``. If None, will - determine automatically. + Whether or not the OS is 64bit. Only used if the OS is ``win32``. If + None, will determine automatically. Returns ------- diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index f7c396a633a..bb39b57e384 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -1,6 +1,7 @@ """ -Defines the Session class to create and destroy a GMT API session and provides access to -the API functions. Uses ctypes to wrap most of the core functions from the C API. +Defines the Session class to create and destroy a GMT API session and provides +access to the API functions. Uses ctypes to wrap most of the core functions +from the C API. """ import sys import ctypes as ctp @@ -60,29 +61,29 @@ class Session: """ A GMT API session where most operations involving the C API happen. - Works as a context manager (for use in a ``with`` block) to create a GMT C API - session and destroy it in the end to clean up memory. + Works as a context manager (for use in a ``with`` block) to create a GMT C + API session and destroy it in the end to clean up memory. - Functions of the shared library are exposed as methods of this class. Most methods - MUST be used with an open session (inside a ``with`` block). If creating GMT data - structures to communicate data, put that code inside the same ``with`` block as the - API calls that will use the data. + Functions of the shared library are exposed as methods of this class. Most + methods MUST be used with an open session (inside a ``with`` block). If + creating GMT data structures to communicate data, put that code inside the + same ``with`` block as the API calls that will use the data. - By default, will let :mod:`ctypes` try to find the GMT shared library (``libgmt``). - If the environment variable ``GMT_LIBRARY_PATH`` is set, will look for the shared - library in the directory specified by it. + By default, will let :mod:`ctypes` try to find the GMT shared library + (``libgmt``). If the environment variable ``GMT_LIBRARY_PATH`` is set, will + look for the shared library in the directory specified by it. - A ``GMTVersionError`` exception will be raised if the GMT shared library reports a - version < 6.0.0. + A ``GMTVersionError`` exception will be raised if the GMT shared library + reports a version < 6.0.0. - The ``session_pointer`` attribute holds a ctypes pointer to the currently open - session. + The ``session_pointer`` attribute holds a ctypes pointer to the currently + open session. Raises ------ GMTCLibNotFoundError - If there was any problem loading the library (couldn't find it or couldn't - access the functions). + If there was any problem loading the library (couldn't find it or + couldn't access the functions). GMTCLibNoSessionError If you try to call a method outside of a 'with' block. GMTVersionError @@ -96,15 +97,18 @@ class Session: >>> grid = load_earth_relief() >>> type(grid) - >>> # Create a session and destroy it automatically when exiting the "with" block. + >>> # Create a session and destroy it automatically when exiting the "with" + >>> # block. >>> with Session() as ses: ... # Create a virtual file and link to the memory block of the grid. ... with ses.virtualfile_from_grid(grid) as fin: ... # Create a temp file to use as output. ... with GMTTempFile() as fout: - ... # Call the grdinfo module with the virtual file as input and the. - ... # temp file as output. - ... ses.call_module("grdinfo", "{} -C ->{}".format(fin, fout.name)) + ... # Call the grdinfo module with the virtual file as input + ... # and the temp file as output. + ... ses.call_module( + ... "grdinfo", "{} -C ->{}".format(fin, fout.name) + ... ) ... # Read the contents of the temp file before it's deleted. ... print(fout.read().strip()) -180 180 -90 90 -8596 5559 1 1 361 181 @@ -165,13 +169,14 @@ def __enter__(self): Raises ------ GMTVersionError - If the version reported by libgmt is less than ``Session.required_version``. - Will destroy the session before raising the exception. + If the version reported by libgmt is less than + ``Session.required_version``. Will destroy the session before + raising the exception. """ self.create("pygmt-session") - # Need to store the version info because 'get_default' won't work after the - # session is destroyed. + # Need to store the version info because 'get_default' won't work after + # the session is destroyed. version = self.info["version"] if Version(version) < Version(self.required_version): self.destroy() @@ -194,7 +199,8 @@ def __getitem__(self, name): """ Get the value of a GMT constant (C enum) from gmt_resources.h - Used to set configuration values for other API calls. Wraps ``GMT_Get_Enum``. + Used to set configuration values for other API calls. Wraps + ``GMT_Get_Enum``. Parameters ---------- @@ -204,8 +210,8 @@ def __getitem__(self, name): Returns ------- constant : int - Integer value of the constant. Do not rely on this value because it might - change. + Integer value of the constant. Do not rely on this value because it + might change. Raises ------ @@ -217,11 +223,11 @@ def __getitem__(self, name): "GMT_Get_Enum", argtypes=[ctp.c_void_p, ctp.c_char_p], restype=ctp.c_int ) - # The C lib introduced the void API pointer to GMT_Get_Enum so that it's - # consistent with other functions. It doesn't use the pointer so we can pass in - # None (NULL pointer). We can't give it the actual pointer because we need to - # call GMT_Get_Enum when creating a new API session pointer (chicken-and-egg - # type of thing). + # The C lib introduced the void API pointer to GMT_Get_Enum so that + # it's consistent with other functions. It doesn't use the pointer so + # we can pass in None (NULL pointer). We can't give it the actual + # pointer because we need to call GMT_Get_Enum when creating a new API + # session pointer (chicken-and-egg type of thing). session = None value = c_get_enum(session, name.encode()) @@ -279,21 +285,22 @@ def create(self, name): """ Create a new GMT C API session. - This is required before most other methods of :class:`pygmt.clib.Session` can be - called. + This is required before most other methods of + :class:`pygmt.clib.Session` can be called. .. warning:: - Usage of :class:`~gmt.clib.Session` as a context manager in a ``with`` block - is preferred over calling :meth:`~gmt.clib.Session.create` and + Usage of :class:`~gmt.clib.Session` as a context manager in a + ``with`` block is preferred over calling + :meth:`~gmt.clib.Session.create` and :meth:`~gmt.clib.Session.destroy` manually. - Calls ``GMT_Create_Session`` and generates a new ``GMTAPI_CTRL`` struct, which - is a :class:`ctypes.c_void_p` pointer. Sets the ``session_pointer`` attribute to - this pointer. + Calls ``GMT_Create_Session`` and generates a new ``GMTAPI_CTRL`` + struct, which is a :class:`ctypes.c_void_p` pointer. Sets the + ``session_pointer`` attribute to this pointer. - Remember to terminate the current session using :meth:`pygmt.clib.Session.destroy` - before creating a new one. + Remember to terminate the current session using + :meth:`pygmt.clib.Session.destroy` before creating a new one. Parameters ---------- @@ -304,13 +311,14 @@ def create(self, name): try: # Won't raise an exception if there is a currently open session self.session_pointer # pylint: disable=pointless-statement - # In this case, fail to create a new session until the old one is destroyed + # In this case, fail to create a new session until the old one is + # destroyed raise GMTCLibError( "Failed to create a GMT API session: There is a currently open session." " Must destroy it fist." ) - # If the exception is raised, this means that there is no open session and we're - # free to create a new one. + # If the exception is raised, this means that there is no open session + # and we're free to create a new one. except GMTCLibNoSessionError: pass @@ -320,25 +328,26 @@ def create(self, name): restype=ctp.c_void_p, ) - # Capture the output printed by GMT into this list. Will use it later to - # generate error messages for the exceptions raised by API calls. + # Capture the output printed by GMT into this list. Will use it later + # to generate error messages for the exceptions raised by API calls. self._error_log = [] @ctp.CFUNCTYPE(ctp.c_int, ctp.c_void_p, ctp.c_char_p) def print_func(file_pointer, message): # pylint: disable=unused-argument """ - Callback function that the GMT C API will use to print log and error - messages. We'll capture the messages and print them to stderr so that they - will show up on the Jupyter notebook. + Callback function that the GMT C API will use to print log and + error messages. We'll capture the messages and print them to stderr + so that they will show up on the Jupyter notebook. """ message = message.decode().strip() self._error_log.append(message) - # flush to make sure the messages are printed even if we have a crash. + # flush to make sure the messages are printed even if we have a + # crash. print(message, file=sys.stderr, flush=True) return 0 - # Need to store a copy of the function because ctypes doesn't and it will be - # garbage collected otherwise + # Need to store a copy of the function because ctypes doesn't and it + # will be garbage collected otherwise self._print_callback = print_func padding = self["GMT_PAD_DEFAULT"] @@ -371,17 +380,19 @@ def destroy(self): .. warning:: - Usage of :class:`~gmt.clib.Session` as a context manager in a ``with`` block - is preferred over calling :meth:`~gmt.clib.Session.create` and + Usage of :class:`~gmt.clib.Session` as a context manager in a + ``with`` block is preferred over calling + :meth:`~gmt.clib.Session.create` and :meth:`~gmt.clib.Session.destroy` manually. - Calls ``GMT_Destroy_Session`` to terminate and free the memory of a registered - ``GMTAPI_CTRL`` session (the pointer for this struct is stored in the - ``session_pointer`` attribute). + Calls ``GMT_Destroy_Session`` to terminate and free the memory of a + registered ``GMTAPI_CTRL`` session (the pointer for this struct is + stored in the ``session_pointer`` attribute). - Always use this method after you are done using a C API session. The session - needs to be destroyed before creating a new one. Otherwise, some of the - configuration files might be left behind and can influence subsequent API calls. + Always use this method after you are done using a C API session. The + session needs to be destroyed before creating a new one. Otherwise, + some of the configuration files might be left behind and can influence + subsequent API calls. Sets the ``session_pointer`` attribute to ``None``. """ @@ -893,8 +904,8 @@ def open_virtual_file(self, family, geometry, direction, data): GMT uses a virtual file scheme to pass in data to API modules. Use it to pass in your GMT data structure (created using - :meth:`~gmt.clib.Session.create_data`) to a module that expects an input - or output file. + :meth:`~gmt.clib.Session.create_data`) to a module that expects an + input or output file. Use in a ``with`` block. Will automatically close the virtual file when leaving the ``with`` block. Because of this, no wrapper for @@ -999,30 +1010,33 @@ def virtualfile_from_vectors(self, *vectors): """ Store 1d arrays as columns of a table inside a virtual file. - Use the virtual file name to pass in the data in your vectors to a GMT module. + Use the virtual file name to pass in the data in your vectors to a GMT + module. - Context manager (use in a ``with`` block). Yields the virtual file name that you - can pass as an argument to a GMT module call. Closes the virtual file upon exit - of the ``with`` block. + Context manager (use in a ``with`` block). Yields the virtual file name + that you can pass as an argument to a GMT module call. Closes the + virtual file upon exit of the ``with`` block. - Use this instead of creating the data container and virtual file by hand with - :meth:`~gmt.clib.Session.create_data`, :meth:`~gmt.clib.Session.put_vector`, and + Use this instead of creating the data container and virtual file by + hand with :meth:`~gmt.clib.Session.create_data`, + :meth:`~gmt.clib.Session.put_vector`, and :meth:`~gmt.clib.Session.open_virtual_file`. - If the arrays are C contiguous blocks of memory, they will be passed without - copying to GMT. If they are not (e.g., they are columns of a 2D array), they - will need to be copied to a contiguous block. + If the arrays are C contiguous blocks of memory, they will be passed + without copying to GMT. If they are not (e.g., they are columns of a 2D + array), they will need to be copied to a contiguous block. Parameters ---------- vectors : 1d arrays - The vectors that will be included in the array. All must be of the same - size. + The vectors that will be included in the array. All must be of the + same size. Yields ------ fname : str - The name of virtual file. Pass this as a file name argument to a GMT module. + The name of virtual file. Pass this as a file name argument to a + GMT module. Examples -------- @@ -1037,17 +1051,19 @@ def virtualfile_from_vectors(self, *vectors): ... with ses.virtualfile_from_vectors(x, y, z) as fin: ... # Send the output to a file so that we can read it ... with GMTTempFile() as fout: - ... ses.call_module('info', '{} ->{}'.format(fin, fout.name)) + ... ses.call_module( + ... 'info', '{} ->{}'.format(fin, fout.name) + ... ) ... print(fout.read().strip()) : N = 3 <1/3> <4/6> <7/9> """ - # Conversion to a C-contiguous array needs to be done here and not in put_matrix - # because we need to maintain a reference to the copy while it is being used by - # the C API. Otherwise, the array would be garbage collected and the memory - # freed. Creating it in this context manager guarantees that the copy will be - # around until the virtual file is closed. The conversion is implicit in - # vectors_to_arrays. + # Conversion to a C-contiguous array needs to be done here and not in + # put_matrix because we need to maintain a reference to the copy while + # it is being used by the C API. Otherwise, the array would be garbage + # collected and the memory freed. Creating it in this context manager + # guarantees that the copy will be around until the virtual file is + # closed. The conversion is implicit in vectors_to_arrays. arrays = vectors_to_arrays(vectors) columns = len(arrays) @@ -1073,25 +1089,27 @@ def virtualfile_from_matrix(self, matrix): """ Store a 2d array as a table inside a virtual file. - Use the virtual file name to pass in the data in your matrix to a GMT module. + Use the virtual file name to pass in the data in your matrix to a GMT + module. - Context manager (use in a ``with`` block). Yields the virtual file name that you - can pass as an argument to a GMT module call. Closes the virtual file upon exit - of the ``with`` block. + Context manager (use in a ``with`` block). Yields the virtual file name + that you can pass as an argument to a GMT module call. Closes the + virtual file upon exit of the ``with`` block. - The virtual file will contain the array as a ``GMT_MATRIX`` pretending to be a - ``GMT_DATASET``. + The virtual file will contain the array as a ``GMT_MATRIX`` pretending + to be a ``GMT_DATASET``. - **Not meant for creating ``GMT_GRID``**. The grid requires more metadata than - just the data matrix. Use :meth:`~gmt.clib.Session.virtualfile_from_grid` - instead. + **Not meant for creating ``GMT_GRID``**. The grid requires more + metadata than just the data matrix. Use + :meth:`~gmt.clib.Session.virtualfile_from_grid` instead. - Use this instead of creating the data container and virtual file by hand with - :meth:`~gmt.clib.Session.create_data`, :meth:`~gmt.clib.Session.put_matrix`, and + Use this instead of creating the data container and virtual file by + hand with :meth:`~gmt.clib.Session.create_data`, + :meth:`~gmt.clib.Session.put_matrix`, and :meth:`~gmt.clib.Session.open_virtual_file` - The matrix must be C contiguous in memory. If it is not (e.g., it is a slice of - a larger array), the array will be copied to make sure it is. + The matrix must be C contiguous in memory. If it is not (e.g., it is a + slice of a larger array), the array will be copied to make sure it is. Parameters ---------- @@ -1101,7 +1119,8 @@ def virtualfile_from_matrix(self, matrix): Yields ------ fname : str - The name of virtual file. Pass this as a file name argument to a GMT module. + The name of virtual file. Pass this as a file name argument to a + GMT module. Examples -------- @@ -1118,16 +1137,19 @@ def virtualfile_from_matrix(self, matrix): ... with ses.virtualfile_from_matrix(data) as fin: ... # Send the output to a file so that we can read it ... with GMTTempFile() as fout: - ... ses.call_module('info', '{} ->{}'.format(fin, fout.name)) + ... ses.call_module( + ... 'info', '{} ->{}'.format(fin, fout.name) + ... ) ... print(fout.read().strip()) : N = 4 <0/9> <1/10> <2/11> """ - # Conversion to a C-contiguous array needs to be done here and not in put_matrix - # because we need to maintain a reference to the copy while it is being used by - # the C API. Otherwise, the array would be garbage collected and the memory - # freed. Creating it in this context manager guarantees that the copy will be - # around until the virtual file is closed. + # Conversion to a C-contiguous array needs to be done here and not in + # put_matrix because we need to maintain a reference to the copy while + # it is being used by the C API. Otherwise, the array would be garbage + # collected and the memory freed. Creating it in this context manager + # guarantees that the copy will be around until the virtual file is + # closed. matrix = as_c_contiguous(matrix) rows, columns = matrix.shape @@ -1148,21 +1170,24 @@ def virtualfile_from_grid(self, grid): """ Store a grid in a virtual file. - Use the virtual file name to pass in the data in your grid to a GMT module. - Grids must be :class:`xarray.DataArray` instances. + Use the virtual file name to pass in the data in your grid to a GMT + module. Grids must be :class:`xarray.DataArray` instances. - Context manager (use in a ``with`` block). Yields the virtual file name that you - can pass as an argument to a GMT module call. Closes the virtual file upon exit - of the ``with`` block. + Context manager (use in a ``with`` block). Yields the virtual file name + that you can pass as an argument to a GMT module call. Closes the + virtual file upon exit of the ``with`` block. - The virtual file will contain the grid as a ``GMT_MATRIX`` with extra metadata. + The virtual file will contain the grid as a ``GMT_MATRIX`` with extra + metadata. - Use this instead of creating a data container and virtual file by hand with - :meth:`~gmt.clib.Session.create_data`, :meth:`~gmt.clib.Session.put_matrix`, and + Use this instead of creating a data container and virtual file by hand + with :meth:`~gmt.clib.Session.create_data`, + :meth:`~gmt.clib.Session.put_matrix`, and :meth:`~gmt.clib.Session.open_virtual_file` - The grid data matrix must be C contiguous in memory. If it is not (e.g., it is a - slice of a larger array), the array will be copied to make sure it is. + The grid data matrix must be C contiguous in memory. If it is not + (e.g., it is a slice of a larger array), the array will be copied to + make sure it is. Parameters ---------- @@ -1172,7 +1197,8 @@ def virtualfile_from_grid(self, grid): Yields ------ fname : str - The name of virtual file. Pass this as a file name argument to a GMT module. + The name of virtual file. Pass this as a file name argument to a + GMT module. Examples -------- @@ -1199,12 +1225,12 @@ def virtualfile_from_grid(self, grid): >>> # The output is: w e s n z0 z1 dx dy n_columns n_rows """ - # Conversion to a C-contiguous array needs to be done here and not in put_matrix - # because we need to maintain a reference to the copy while it is being used by - # the C API. Otherwise, the array would be garbage collected and the memory - # freed. Creating it in this context manager guarantees that the copy will be - # around until the virtual file is closed. The conversion is implicit in - # dataarray_to_matrix. + # Conversion to a C-contiguous array needs to be done here and not in + # put_matrix because we need to maintain a reference to the copy while + # it is being used by the C API. Otherwise, the array would be garbage + # collected and the memory freed. Creating it in this context manager + # guarantees that the copy will be around until the virtual file is + # closed. The conversion is implicit in dataarray_to_matrix. matrix, region, inc = dataarray_to_matrix(grid) family = "GMT_IS_GRID|GMT_VIA_MATRIX" geometry = "GMT_IS_SURFACE" diff --git a/pygmt/datasets/earth_relief.py b/pygmt/datasets/earth_relief.py index d5dbb1d3c40..aeca5d9c872 100644 --- a/pygmt/datasets/earth_relief.py +++ b/pygmt/datasets/earth_relief.py @@ -43,8 +43,9 @@ def load_earth_relief(resolution="60m"): grid.attrs["units"] = "meters" grid.attrs["vertical_datum"] = "EMG96" grid.attrs["horizontal_datum"] = "WGS84" - # Remove the actual range because it gets outdated when indexing the grid, which - # causes problems when exporting it to netCDF for usage on the command-line. + # Remove the actual range because it gets outdated when indexing the grid, + # which causes problems when exporting it to netCDF for usage on the + # command-line. grid.attrs.pop("actual_range") for coord in grid.coords: grid[coord].attrs.pop("actual_range") diff --git a/pygmt/datasets/tutorial.py b/pygmt/datasets/tutorial.py index bee3c18609d..77f7bbbd12d 100644 --- a/pygmt/datasets/tutorial.py +++ b/pygmt/datasets/tutorial.py @@ -73,8 +73,9 @@ def load_usgs_quakes(): Returns ------- - data : pandas.Dataframe - The data table. Use ``print(data.describe())`` to see the available columns. + data : pandas.Dataframe + The data table. Use ``print(data.describe())`` to see the available + columns. """ fname = which("@usgs_quakes_22.txt", download="c") diff --git a/pygmt/exceptions.py b/pygmt/exceptions.py index 4f74c61716f..d5b2c9584ef 100644 --- a/pygmt/exceptions.py +++ b/pygmt/exceptions.py @@ -1,7 +1,7 @@ # pylint: disable=missing-docstring # -# Custom exception types used throughout the library. All exceptions derive from -# GMTError. +# Custom exception types used throughout the library. All exceptions derive +# from GMTError. class GMTError(Exception): diff --git a/pygmt/figure.py b/pygmt/figure.py index eb00a27e698..3c867137646 100644 --- a/pygmt/figure.py +++ b/pygmt/figure.py @@ -33,8 +33,8 @@ class Figure(BasePlotting): A GMT figure to handle all plotting. Use the plotting methods of this class to add elements to the figure. You - can preview the figure using :meth:`pygmt.Figure.show` and save the figure to - a file using :meth:`pygmt.Figure.savefig`. + can preview the figure using :meth:`pygmt.Figure.show` and save the figure + to a file using :meth:`pygmt.Figure.savefig`. Unlike traditional GMT figures, no figure file is generated until you call :meth:`pygmt.Figure.savefig` or :meth:`pygmt.Figure.psconvert`. @@ -80,8 +80,8 @@ def _activate_figure(self): Unlike the command-line version (``gmt figure``), this method does not trigger the generation of a figure file. An explicit call to - :meth:`pygmt.Figure.savefig` or :meth:`pygmt.Figure.psconvert` must be made - in order to get a file. + :meth:`pygmt.Figure.savefig` or :meth:`pygmt.Figure.psconvert` must be + made in order to get a file. """ # Passing format '-' tells pygmt.end to not produce any files. fmt = "-" @@ -257,8 +257,8 @@ def show(self, dpi=300, width=500, method="static"): Only if ``method != 'external'``. """ - # Module level variable to know which figures had their show method called. - # Needed for the sphinx-gallery scraper. + # Module level variable to know which figures had their show method + # called. Needed for the sphinx-gallery scraper. SHOWED_FIGURES.append(self) if method not in ["static", "external"]: @@ -288,16 +288,18 @@ def shift_origin(self, xshift=None, yshift=None): """ Shift plot origin in x and/or y directions. - This method shifts plot origin relative to the current origin by (*xshift*,*yshift*) - and optionally append the length unit (**c**, **i**, or **p**). + This method shifts plot origin relative to the current origin by + (*xshift*,*yshift*) and optionally append the length unit (**c**, + **i**, or **p**). - Prepend **a** to shift the origin back to the original position - after plotting, prepend **c** to center the plot on the center of the - paper (optionally add shift), prepend **f** to shift the origin relative - to the fixed lower left corner of the page, or prepend **r** [Default] to + Prepend **a** to shift the origin back to the original position after + plotting, prepend **c** to center the plot on the center of the paper + (optionally add shift), prepend **f** to shift the origin relative to + the fixed lower left corner of the page, or prepend **r** [Default] to move the origin relative to its current location. - Detailed usage at :gmt-docs:`GMT_Docs.html#plot-positioning-and-layout-the-x-y-options` + Detailed usage at + :gmt-docs:`GMT_Docs.html#plot-positioning-and-layout-the-x-y-options` Parameters ---------- diff --git a/pygmt/gridding.py b/pygmt/gridding.py index ed0da5b9c38..c5ad7fac0a3 100644 --- a/pygmt/gridding.py +++ b/pygmt/gridding.py @@ -23,12 +23,13 @@ def surface(x=None, y=None, z=None, data=None, **kwargs): """ Grids table data using adjustable tension continuous curvature splines. - Surface reads randomly-spaced (x,y,z) triples and produces gridded values z(x,y) - by solving: + Surface reads randomly-spaced (x,y,z) triples and produces gridded values + z(x,y) by solving: (1 - T) * L (L (z)) + T * L (z) = 0 - where T is a tension factor between 0 and 1, and L indicates the Laplacian operator. + where T is a tension factor between 0 and 1, and L indicates the Laplacian + operator. Takes a matrix, xyz triples, or a file name as input. diff --git a/pygmt/helpers/decorators.py b/pygmt/helpers/decorators.py index 4465045c489..32c41cf619e 100644 --- a/pygmt/helpers/decorators.py +++ b/pygmt/helpers/decorators.py @@ -221,7 +221,9 @@ def kwargs_to_strings(convert_bools=True, **conversions): Examples -------- - >>> @kwargs_to_strings(R='sequence', i='sequence_comma', files='sequence_space') + >>> @kwargs_to_strings( + ... R='sequence', i='sequence_comma', files='sequence_space' + ... ) ... def module(*args, **kwargs): ... "A module that prints the arguments it received" ... print('{', end='') diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index e753223f974..1a98d45682a 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -50,22 +50,6 @@ def data_kind(data, x=None, y=None, z=None): 'matrix' >>> data_kind(data='my-data-file.txt', x=None, y=None) 'file' - >>> data_kind(data=None, x=None, y=None) - Traceback (most recent call last): - ... - pygmt.exceptions.GMTInvalidInput: No input data provided. - >>> data_kind(data='data.txt', x=np.array([1, 2]), y=np.array([4, 5])) - Traceback (most recent call last): - ... - pygmt.exceptions.GMTInvalidInput: Too much data. Use either data or x and y. - >>> data_kind(data='data.txt', x=np.array([1, 2]), y=None) - Traceback (most recent call last): - ... - pygmt.exceptions.GMTInvalidInput: Too much data. Use either data or x and y. - >>> data_kind(data=None, x=np.array([1, 2]), y=None) - Traceback (most recent call last): - ... - pygmt.exceptions.GMTInvalidInput: Must provided both x and y. """ if data is None and x is None and y is None: diff --git a/pygmt/mathops.py b/pygmt/mathops.py index dab216a0cb0..5649ea1cfcb 100644 --- a/pygmt/mathops.py +++ b/pygmt/mathops.py @@ -18,39 +18,42 @@ def makecpt(**kwargs): Parameters ---------- cmap (C) : str - Selects the master color palette table (CPT) to use in the interpolation. - Full list of built-in color palette tables can be found at - :gmt-docs:`cookbook/cpts.html#built-in-color-palette-tables-cpt`. + Selects the master color palette table (CPT) to use in the + interpolation. Full list of built-in color palette tables can be found + at :gmt-docs:`cookbook/cpts.html#built-in-color-palette-tables-cpt`. series (T) : list or str - ``[min/max/inc[+b|l|n]|file|list]``. - Defines the range of the new CPT by giving the lowest and highest z-value (and - optionally an interval). If this is not given, the existing range in the master - CPT will be used intact. + ``[min/max/inc[+b|l|n]|file|list]``. Defines the range of the new CPT + by giving the lowest and highest z-value (and optionally an interval). + If this is not given, the existing range in the master CPT will be used + intact. truncate (G) : list or str - ``zlo/zhi``. - Truncate the incoming CPT so that the lowest and highest z-levels are to zlo and - zhi. If one of these equal NaN then we leave that end of the CPT alone. The - truncation takes place before any resampling. See also + ``zlo/zhi``. Truncate the incoming CPT so that the lowest and highest + z-levels are to zlo and zhi. If one of these equal NaN then we leave + that end of the CPT alone. The truncation takes place before any + resampling. See also :gmt-docs:`cookbook/features.html#manipulating-cpts`. output (H) : str - Optional. The file name with extension .cpt to store the generated CPT file. - If not given or False (default), saves the CPT as the session current CPT. + Optional. The file name with extension .cpt to store the generated CPT + file. If not given or False (default), saves the CPT as the session + current CPT. reverse (I) : str - Set this to True or c [Default] to reverse the sense of color progression in the - master CPT. Set this to z to reverse the sign of z-values in the color table. - Note that this change of z-direction happens before -G and -T values are used so - the latter must be compatible with the changed z-range. See also + Set this to True or c [Default] to reverse the sense of color + progression in the master CPT. Set this to z to reverse the sign of + z-values in the color table. Note that this change of z-direction + happens before -G and -T values are used so the latter must be + compatible with the changed z-range. See also :gmt-docs:`cookbook/features.html#manipulating-cpts`. continuous (Z) : bool - Creates a continuous CPT [Default is discontinuous, i.e., constant colors for - each interval]. This option has no effect when no -T is used, or when using - -Tz_min/z_max; in the first case the input CPT remains untouched, in the second - case it is only scaled to match the range z_min/z_max. + Creates a continuous CPT [Default is discontinuous, i.e., constant + colors for each interval]. This option has no effect when no -T is + used, or when using -Tz_min/z_max; in the first case the input CPT + remains untouched, in the second case it is only scaled to match the + range z_min/z_max. {aliases} """ diff --git a/pygmt/session_management.py b/pygmt/session_management.py index 82f48a5806e..cafd306e120 100644 --- a/pygmt/session_management.py +++ b/pygmt/session_management.py @@ -11,7 +11,6 @@ def begin(): Used in combination with :func:`pygmt.end`. Only meant to be used once for creating the global session. - """ prefix = "pygmt-session" with Session() as lib: @@ -22,11 +21,10 @@ def end(): """ Terminate GMT modern mode session and optionally produce the figure files. - Called after :func:`pygmt.begin` and all commands that you want included in a - session. Will finalize any PostScript plots that were made in the + Called after :func:`pygmt.begin` and all commands that you want included in + a session. Will finalize any PostScript plots that were made in the background, convert them to the desired format (specified in ``pygmt.begin``), and bring the figures to the working directory. - """ with Session() as lib: lib.call_module("end", "") diff --git a/pygmt/sphinx_gallery.py b/pygmt/sphinx_gallery.py index c1252298a2b..3de8300a0bd 100644 --- a/pygmt/sphinx_gallery.py +++ b/pygmt/sphinx_gallery.py @@ -15,13 +15,14 @@ class PyGMTScraper: # pylint: disable=too-few-public-methods Used by sphinx-gallery to generate the plots from the code in the examples. - Pass an instance of this class to ``sphinx_gallery_conf`` in your ``conf.py`` as the - ``"image_scrapers"`` argument. + Pass an instance of this class to ``sphinx_gallery_conf`` in your + ``conf.py`` as the ``"image_scrapers"`` argument. """ def __call__(self, block, block_vars, gallery_conf): """ - Called by sphinx-gallery to save the figures generated after running code. + Called by sphinx-gallery to save the figures generated after running + code. """ image_names = list() image_path_iterator = block_vars["image_path_iterator"] diff --git a/pygmt/tests/test_clib.py b/pygmt/tests/test_clib.py index e02d8ed5fd4..77a26de0a06 100644 --- a/pygmt/tests/test_clib.py +++ b/pygmt/tests/test_clib.py @@ -159,7 +159,7 @@ def test_create_session_fails(): with mock(ses, "GMT_Create_Session", returns=None): with pytest.raises(GMTCLibError): ses.create("test-session-name") - # Should also fail if trying to create a session before destroying the old one. + # Should fail if trying to create a session before destroying the old one. ses.create("test1") with pytest.raises(GMTCLibError): ses.create("test2") @@ -220,7 +220,7 @@ def test_call_module_error_message(): def test_method_no_session(): "Fails when not in a session" - # Create an instance of clib.Session without "with" so no session is created. + # Create an instance of Session without "with" so no session is created. lib = clib.Session() with pytest.raises(GMTCLibNoSessionError): lib.call_module("gmtdefaults", "") @@ -778,7 +778,7 @@ def test_dataarray_to_matrix_works(): def test_dataarray_to_matrix_negative_x_increment(): - "Check that dataarray_to_matrix returns correct output with flipped x dimensions" + "Check if dataarray_to_matrix returns correct output with flipped x" data = np.diag(v=np.arange(3)) x = np.linspace(start=4, stop=0, num=3) y = np.linspace(start=5, stop=9, num=3) @@ -791,7 +791,7 @@ def test_dataarray_to_matrix_negative_x_increment(): def test_dataarray_to_matrix_negative_y_increment(): - "Check that dataarray_to_matrix returns correct output with flipped y dimensions" + "Check that dataarray_to_matrix returns correct output with flipped y" data = np.diag(v=np.arange(3)) x = np.linspace(start=0, stop=4, num=3) y = np.linspace(start=9, stop=5, num=3) @@ -804,7 +804,7 @@ def test_dataarray_to_matrix_negative_y_increment(): def test_dataarray_to_matrix_negative_x_and_y_increment(): - "Check that dataarray_to_matrix returns correct output with flipped x/y dimensions" + "Check that dataarray_to_matrix returns correct output with flipped x/y" data = np.diag(v=np.arange(3)) x = np.linspace(start=4, stop=0, num=3) y = np.linspace(start=9, stop=5, num=3) diff --git a/pygmt/tests/test_colorbar.py b/pygmt/tests/test_colorbar.py index 5fea02100db..eb4f5155170 100644 --- a/pygmt/tests/test_colorbar.py +++ b/pygmt/tests/test_colorbar.py @@ -19,7 +19,7 @@ def test_colorbar_using_paper_coordinates(): @pytest.mark.mpl_image_compare def test_colorbar_using_paper_coordinates_horizontal(): """ - Create colorbar positioned at 0cm,0cm with length 2cm oriented horizontally. + Create colorbar positioned at 0cm,0cm with length 2cm oriented horizontally """ fig = Figure() fig.colorbar(cmap="rainbow", position="x0c/0c+w2c+h") @@ -40,7 +40,7 @@ def test_colorbar_positioned_using_map_coordinates(): @pytest.mark.mpl_image_compare def test_colorbar_positioned_using_justification_code(): """ - Create colorbar positioned at Top Center inside the map frame with length 2cm. + Create colorbar at Top Center inside the map frame with length 2cm. """ fig = Figure() fig.basemap(region=[2, 4, 6, 8], projection="t0/2c", frame=True) @@ -51,7 +51,7 @@ def test_colorbar_positioned_using_justification_code(): @pytest.mark.mpl_image_compare def test_colorbar_positioned_using_normalized_coords(): """ - Create colorbar positioned at normalized coordinates 0.75,0.25 with length 2cm. + Create colorbar at normalized coordinates 0.75,0.25 with length 2cm. """ fig = Figure() fig.basemap(region=[2, 4, 6, 8], projection="t0/2c", frame=True) @@ -92,7 +92,8 @@ def test_colorbar_box_with_fill(): @pytest.mark.mpl_image_compare def test_colorbar_box_with_clearance(): """ - Create colorbar with box that has an x-clearance of 0.8cm and y-clearance of 0.4cm. + Create colorbar with box that has an x-clearance of 0.8cm and y-clearance + of 0.4cm. """ fig = Figure() fig.colorbar(cmap="rainbow", box="+c0.8c/0.4c+porange", position="x0c/0c+w1c/0.5c") @@ -102,8 +103,8 @@ def test_colorbar_box_with_clearance(): @pytest.mark.mpl_image_compare def test_colorbar_box_with_secondary_border(): """ - Create colorbar with box that has a secondary, inner border in addition to the main - primary, outer border. + Create colorbar with box that has a secondary, inner border in addition to + the main primary, outer border. """ fig = Figure() fig.colorbar(cmap="rainbow", box="+porange+imagenta", position="x0c/0c+w1c/0.5c") diff --git a/pygmt/tests/test_helpers.py b/pygmt/tests/test_helpers.py index 3abaf7b456f..66b61456376 100644 --- a/pygmt/tests/test_helpers.py +++ b/pygmt/tests/test_helpers.py @@ -4,11 +4,29 @@ import os import pytest +import numpy as np -from ..helpers import kwargs_to_strings, GMTTempFile, unique_name +from ..helpers import kwargs_to_strings, GMTTempFile, unique_name, data_kind from ..exceptions import GMTInvalidInput +@pytest.mark.parametrize( + "data,x,y", + [ + (None, None, None), + ("data.txt", np.array([1, 2]), np.array([4, 5])), + ("data.txt", np.array([1, 2]), None), + ("data.txt", None, np.array([4, 5])), + (None, np.array([1, 2]), None), + (None, None, np.array([4, 5])), + ], +) +def test_data_kind_fails(data, x, y): + "Make sure data_kind raises exceptions when it should" + with pytest.raises(GMTInvalidInput): + data_kind(data=data, x=x, y=y) + + def test_unique_name(): "Make sure the names are really unique" names = [unique_name() for i in range(100)] diff --git a/pygmt/tests/test_makecpt.py b/pygmt/tests/test_makecpt.py index 7a557a79ace..48013f2b40e 100644 --- a/pygmt/tests/test_makecpt.py +++ b/pygmt/tests/test_makecpt.py @@ -66,7 +66,8 @@ def test_makecpt_to_plot_grid(grid): @pytest.mark.mpl_image_compare def test_makecpt_to_plot_grid_scaled_with_series(grid): """ - Use static color palette table scaled to a min/max series to change color of grid + Use static color palette table scaled to a min/max series to change color + of grid """ fig = Figure() makecpt(cmap="oleron", series="-4500/4500") @@ -157,7 +158,8 @@ def test_makecpt_reverse_zsign_only(grid): @pytest.mark.mpl_image_compare def test_makecpt_reverse_color_and_zsign(grid): """ - Use static color palette table with both its colors and z-value sign reversed + Use static color palette table with both its colors and z-value sign + reversed """ fig = Figure() makecpt(cmap="earth", reverse="cz") @@ -168,8 +170,8 @@ def test_makecpt_reverse_color_and_zsign(grid): @pytest.mark.mpl_image_compare def test_makecpt_continuous(grid): """ - Use static color palette table that is continuous from blue to white and scaled from - -4500 to 4500m. + Use static color palette table that is continuous from blue to white and + scaled from -4500 to 4500m. """ fig = Figure() makecpt(cmap="blue,white", continuous=True, series="-4500,4500") diff --git a/pygmt/tests/test_surface.py b/pygmt/tests/test_surface.py index 9af4f3f5bca..8cba271f7b5 100644 --- a/pygmt/tests/test_surface.py +++ b/pygmt/tests/test_surface.py @@ -99,7 +99,8 @@ def test_surface_with_outfile_param(): def test_surface_short_aliases(): """ - Run surface using short aliases -I for spacing, -R for region, -G for outfile + Run surface using short aliases -I for spacing, -R for region, -G for + outfile """ ship_data = load_sample_bathymetry() data = ship_data.values # convert pandas.DataFrame to numpy.ndarray diff --git a/pygmt/tests/test_text.py b/pygmt/tests/test_text.py index 4eb4c41ed4c..fb3f54d9789 100644 --- a/pygmt/tests/test_text.py +++ b/pygmt/tests/test_text.py @@ -158,8 +158,9 @@ def test_text_justify_bottom_right_and_top_left(region, projection): @pytest.mark.mpl_image_compare def test_text_justify_parsed_from_textfile(): """ - Print text justified based on a column from textfile, using justify=True boolean - operation. Loosely based on "All great-circle paths lead to Rome" gallery example at + Print text justified based on a column from textfile, using justify=True + boolean operation. Loosely based on "All great-circle paths lead to Rome" + gallery example at https://gmt.soest.hawaii.edu/doc/latest/gallery/ex23.html """ fig = Figure() diff --git a/setup.cfg b/setup.cfg index 9abe0a83abe..d607b9e76fd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,6 +8,10 @@ tag_prefix = '' [flake8] ignore = E203, E266, E501, W503, F401, E741 max-line-length = 88 +#max-complexity = 10 +max-doc-length = 79 +exclude = + pygmt/_version.py [tool:pytest] markers = From a93363ef4e1aa0fd2eefcecdfd55767ed3e045ef Mon Sep 17 00:00:00 2001 From: Leonardo Uieda Date: Thu, 28 Nov 2019 16:59:05 +0000 Subject: [PATCH 6/7] Use napoleon instead of numpydoc with sphinx (#383) The napoleon sphinx extension renders the numpy docstrings better than numpydoc and works with newer versions of sphinx. This way, we upgrade to a newer sphinx which works better with the readthedocs theme. Older sphinx is also a problem for Python 3.8 packages on conda-forge. --- doc/_templates/autosummary/class.rst | 12 ++++++++++++ doc/conf.py | 9 ++++++--- environment.yml | 8 ++++---- pygmt/base_plotting.py | 6 ++---- pygmt/gridding.py | 4 ++-- pygmt/mathops.py | 8 ++------ requirements-dev.txt | 5 ++--- 7 files changed, 30 insertions(+), 22 deletions(-) diff --git a/doc/_templates/autosummary/class.rst b/doc/_templates/autosummary/class.rst index 0a47561ea7c..a08a2657d08 100644 --- a/doc/_templates/autosummary/class.rst +++ b/doc/_templates/autosummary/class.rst @@ -4,6 +4,18 @@ .. autoclass:: {{ objname }} +.. rubric:: Methods Summary + +.. autosummary:: + {% for item in methods %} + {% if item != '__init__' %} + {{ objname }}.{{ item }} + {% endif %} + {% endfor %} + +.. include:: backreferences/{{ fullname }}.examples + .. raw:: html

+ diff --git a/doc/conf.py b/doc/conf.py index 8c8c0c8fa9b..d7a055a5e47 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -20,15 +20,18 @@ "sphinx.ext.viewcode", "sphinx.ext.extlinks", "sphinx.ext.intersphinx", - "numpydoc", + "sphinx.ext.napoleon", "nbsphinx", "sphinx_gallery.gen_gallery", ] # Autosummary pages will be generated by sphinx-autogen instead of sphinx-build -autosummary_generate = False +autosummary_generate = [] -numpydoc_class_members_toctree = False +# Make the list of returns arguments and attributes render the same as the +# parameters list +napoleon_use_rtype = False +napoleon_use_ivar = True # configure links to GMT docs extlinks = { diff --git a/environment.yml b/environment.yml index 223fba60f24..b0a2a85cb25 100644 --- a/environment.yml +++ b/environment.yml @@ -5,6 +5,7 @@ channels: dependencies: - python=3.7 - pip + - gmt=6.0.0 - numpy - pandas - xarray @@ -18,10 +19,9 @@ dependencies: - pytest-mpl - coverage - black - - pylint + - pylint=2.2.2 - flake8 - - sphinx<=1.8.5 - - sphinx_rtd_theme + - sphinx=2.2.1 + - sphinx_rtd_theme=0.4.3 - sphinx-gallery - nbsphinx - - numpydoc diff --git a/pygmt/base_plotting.py b/pygmt/base_plotting.py index 575880c43eb..a978b36d9bd 100644 --- a/pygmt/base_plotting.py +++ b/pygmt/base_plotting.py @@ -157,6 +157,8 @@ def colorbar(self, **kwargs): Full option list at :gmt-docs:`colorbar.html` + {aliases} + Parameters ---------- position (D) : str @@ -175,7 +177,6 @@ def colorbar(self, **kwargs): default, the anchor point on the scale is assumed to be the bottom left corner (BL), but this can be changed by appending +j followed by a 2-char justification code justify. - box (F) : bool or str ``[+cclearances][+gfill][+i[[gap/]pen]][+p[pen]][+r[radius]] [+s[[dx/dy/][shade]]]``. If set to True, draws a rectangular @@ -192,18 +193,15 @@ def colorbar(self, **kwargs): offset background shaded region. Here, dx/dy indicates the shift relative to the foreground frame [4p/-4p] and shade sets the fill style to use for shading [gray50]. - truncate (G) : list or str ``zlo/zhi`` Truncate the incoming CPT so that the lowest and highest z-levels are to zlo and zhi. If one of these equal NaN then we leave that end of the CPT alone. The truncation takes place before the plotting. - scale (W) : float Multiply all z-values in the CPT by the provided scale. By default the CPT is used as is. - {aliases} """ kwargs = self._preprocess(**kwargs) with Session() as lib: diff --git a/pygmt/gridding.py b/pygmt/gridding.py index c5ad7fac0a3..041d7ec4162 100644 --- a/pygmt/gridding.py +++ b/pygmt/gridding.py @@ -37,6 +37,8 @@ def surface(x=None, y=None, z=None, data=None, **kwargs): Full option list at :gmt-docs:`surface.html` + {aliases} + Parameters ---------- x, y, z : 1d arrays @@ -56,8 +58,6 @@ def surface(x=None, y=None, z=None, data=None, **kwargs): Optional. The file name for the output netcdf file with extension .nc to store the grid in. - {aliases} - Returns ------- ret: xarray.DataArray or None diff --git a/pygmt/mathops.py b/pygmt/mathops.py index 5649ea1cfcb..b2a904a25b7 100644 --- a/pygmt/mathops.py +++ b/pygmt/mathops.py @@ -15,31 +15,29 @@ def makecpt(**kwargs): Full option list at :gmt-docs:`makecpt.html` + {aliases} + Parameters ---------- cmap (C) : str Selects the master color palette table (CPT) to use in the interpolation. Full list of built-in color palette tables can be found at :gmt-docs:`cookbook/cpts.html#built-in-color-palette-tables-cpt`. - series (T) : list or str ``[min/max/inc[+b|l|n]|file|list]``. Defines the range of the new CPT by giving the lowest and highest z-value (and optionally an interval). If this is not given, the existing range in the master CPT will be used intact. - truncate (G) : list or str ``zlo/zhi``. Truncate the incoming CPT so that the lowest and highest z-levels are to zlo and zhi. If one of these equal NaN then we leave that end of the CPT alone. The truncation takes place before any resampling. See also :gmt-docs:`cookbook/features.html#manipulating-cpts`. - output (H) : str Optional. The file name with extension .cpt to store the generated CPT file. If not given or False (default), saves the CPT as the session current CPT. - reverse (I) : str Set this to True or c [Default] to reverse the sense of color progression in the master CPT. Set this to z to reverse the sign of @@ -47,7 +45,6 @@ def makecpt(**kwargs): happens before -G and -T values are used so the latter must be compatible with the changed z-range. See also :gmt-docs:`cookbook/features.html#manipulating-cpts`. - continuous (Z) : bool Creates a continuous CPT [Default is discontinuous, i.e., constant colors for each interval]. This option has no effect when no -T is @@ -55,7 +52,6 @@ def makecpt(**kwargs): remains untouched, in the second case it is only scaled to match the range z_min/z_max. - {aliases} """ with Session() as lib: if "H" not in kwargs.keys(): # if no output is set diff --git a/requirements-dev.txt b/requirements-dev.txt index 5c9c72a185f..76352e17224 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -9,8 +9,7 @@ coverage black pylint flake8 -sphinx<=1.8.5 -sphinx_rtd_theme +sphinx=2.2.1 +sphinx_rtd_theme=0.4.3 sphinx-gallery nbsphinx -numpydoc From fff0d5c904bd77c7ff243af6962e06dcfa8997d2 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 5 Dec 2019 16:13:14 -0500 Subject: [PATCH 7/7] Allow text accepting "frame" as an argument (#385) `fig.text()` should accept "frame" as an argument. --- pygmt/base_plotting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/base_plotting.py b/pygmt/base_plotting.py index a978b36d9bd..344ba9b9807 100644 --- a/pygmt/base_plotting.py +++ b/pygmt/base_plotting.py @@ -675,7 +675,7 @@ def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwarg lib.call_module("legend", arg_str) @fmt_docstring - @use_alias(R="region", J="projection") + @use_alias(R="region", J="projection", B="frame") @kwargs_to_strings( R="sequence", textfiles="sequence_space",