test_axes.py 322 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665
  1. import contextlib
  2. from collections import namedtuple, deque
  3. import datetime
  4. from decimal import Decimal
  5. from functools import partial
  6. import gc
  7. import inspect
  8. import io
  9. from itertools import product
  10. import platform
  11. import sys
  12. from types import SimpleNamespace
  13. import dateutil.tz
  14. import numpy as np
  15. from numpy import ma
  16. from cycler import cycler
  17. import pytest
  18. import matplotlib
  19. import matplotlib as mpl
  20. from matplotlib import rc_context, patheffects
  21. import matplotlib.colors as mcolors
  22. import matplotlib.dates as mdates
  23. from matplotlib.figure import Figure
  24. from matplotlib.axes import Axes
  25. from matplotlib.lines import Line2D
  26. from matplotlib.collections import PathCollection
  27. import matplotlib.font_manager as mfont_manager
  28. import matplotlib.markers as mmarkers
  29. import matplotlib.patches as mpatches
  30. import matplotlib.path as mpath
  31. from matplotlib.projections.geo import HammerAxes
  32. from matplotlib.projections.polar import PolarAxes
  33. import matplotlib.pyplot as plt
  34. import matplotlib.text as mtext
  35. import matplotlib.ticker as mticker
  36. import matplotlib.transforms as mtransforms
  37. import mpl_toolkits.axisartist as AA # type: ignore[import]
  38. from numpy.testing import (
  39. assert_allclose, assert_array_equal, assert_array_almost_equal)
  40. from matplotlib.testing.decorators import (
  41. image_comparison, check_figures_equal, remove_ticks_and_titles)
  42. from matplotlib.testing._markers import needs_usetex
  43. # Note: Some test cases are run twice: once normally and once with labeled data
  44. # These two must be defined in the same test function or need to have
  45. # different baseline images to prevent race conditions when pytest runs
  46. # the tests with multiple threads.
  47. @check_figures_equal(extensions=["png"])
  48. def test_invisible_axes(fig_test, fig_ref):
  49. ax = fig_test.subplots()
  50. ax.set_visible(False)
  51. def test_get_labels():
  52. fig, ax = plt.subplots()
  53. ax.set_xlabel('x label')
  54. ax.set_ylabel('y label')
  55. assert ax.get_xlabel() == 'x label'
  56. assert ax.get_ylabel() == 'y label'
  57. def test_repr():
  58. fig, ax = plt.subplots()
  59. ax.set_label('label')
  60. ax.set_title('title')
  61. ax.set_xlabel('x')
  62. ax.set_ylabel('y')
  63. assert repr(ax) == (
  64. "<Axes: "
  65. "label='label', title={'center': 'title'}, xlabel='x', ylabel='y'>")
  66. @check_figures_equal(extensions=['png'])
  67. def test_label_loc_vertical(fig_test, fig_ref):
  68. ax = fig_test.subplots()
  69. sc = ax.scatter([1, 2], [1, 2], c=[1, 2], label='scatter')
  70. ax.legend()
  71. ax.set_ylabel('Y Label', loc='top')
  72. ax.set_xlabel('X Label', loc='right')
  73. cbar = fig_test.colorbar(sc)
  74. cbar.set_label("Z Label", loc='top')
  75. ax = fig_ref.subplots()
  76. sc = ax.scatter([1, 2], [1, 2], c=[1, 2], label='scatter')
  77. ax.legend()
  78. ax.set_ylabel('Y Label', y=1, ha='right')
  79. ax.set_xlabel('X Label', x=1, ha='right')
  80. cbar = fig_ref.colorbar(sc)
  81. cbar.set_label("Z Label", y=1, ha='right')
  82. @check_figures_equal(extensions=['png'])
  83. def test_label_loc_horizontal(fig_test, fig_ref):
  84. ax = fig_test.subplots()
  85. sc = ax.scatter([1, 2], [1, 2], c=[1, 2], label='scatter')
  86. ax.legend()
  87. ax.set_ylabel('Y Label', loc='bottom')
  88. ax.set_xlabel('X Label', loc='left')
  89. cbar = fig_test.colorbar(sc, orientation='horizontal')
  90. cbar.set_label("Z Label", loc='left')
  91. ax = fig_ref.subplots()
  92. sc = ax.scatter([1, 2], [1, 2], c=[1, 2], label='scatter')
  93. ax.legend()
  94. ax.set_ylabel('Y Label', y=0, ha='left')
  95. ax.set_xlabel('X Label', x=0, ha='left')
  96. cbar = fig_ref.colorbar(sc, orientation='horizontal')
  97. cbar.set_label("Z Label", x=0, ha='left')
  98. @check_figures_equal(extensions=['png'])
  99. def test_label_loc_rc(fig_test, fig_ref):
  100. with matplotlib.rc_context({"xaxis.labellocation": "right",
  101. "yaxis.labellocation": "top"}):
  102. ax = fig_test.subplots()
  103. sc = ax.scatter([1, 2], [1, 2], c=[1, 2], label='scatter')
  104. ax.legend()
  105. ax.set_ylabel('Y Label')
  106. ax.set_xlabel('X Label')
  107. cbar = fig_test.colorbar(sc, orientation='horizontal')
  108. cbar.set_label("Z Label")
  109. ax = fig_ref.subplots()
  110. sc = ax.scatter([1, 2], [1, 2], c=[1, 2], label='scatter')
  111. ax.legend()
  112. ax.set_ylabel('Y Label', y=1, ha='right')
  113. ax.set_xlabel('X Label', x=1, ha='right')
  114. cbar = fig_ref.colorbar(sc, orientation='horizontal')
  115. cbar.set_label("Z Label", x=1, ha='right')
  116. def test_label_shift():
  117. fig, ax = plt.subplots()
  118. # Test label re-centering on x-axis
  119. ax.set_xlabel("Test label", loc="left")
  120. ax.set_xlabel("Test label", loc="center")
  121. assert ax.xaxis.label.get_horizontalalignment() == "center"
  122. ax.set_xlabel("Test label", loc="right")
  123. assert ax.xaxis.label.get_horizontalalignment() == "right"
  124. ax.set_xlabel("Test label", loc="center")
  125. assert ax.xaxis.label.get_horizontalalignment() == "center"
  126. # Test label re-centering on y-axis
  127. ax.set_ylabel("Test label", loc="top")
  128. ax.set_ylabel("Test label", loc="center")
  129. assert ax.yaxis.label.get_horizontalalignment() == "center"
  130. ax.set_ylabel("Test label", loc="bottom")
  131. assert ax.yaxis.label.get_horizontalalignment() == "left"
  132. ax.set_ylabel("Test label", loc="center")
  133. assert ax.yaxis.label.get_horizontalalignment() == "center"
  134. @check_figures_equal(extensions=["png"])
  135. def test_acorr(fig_test, fig_ref):
  136. np.random.seed(19680801)
  137. Nx = 512
  138. x = np.random.normal(0, 1, Nx).cumsum()
  139. maxlags = Nx-1
  140. ax_test = fig_test.subplots()
  141. ax_test.acorr(x, maxlags=maxlags)
  142. ax_ref = fig_ref.subplots()
  143. # Normalized autocorrelation
  144. norm_auto_corr = np.correlate(x, x, mode="full")/np.dot(x, x)
  145. lags = np.arange(-maxlags, maxlags+1)
  146. norm_auto_corr = norm_auto_corr[Nx-1-maxlags:Nx+maxlags]
  147. ax_ref.vlines(lags, [0], norm_auto_corr)
  148. ax_ref.axhline(y=0, xmin=0, xmax=1)
  149. @check_figures_equal(extensions=["png"])
  150. def test_acorr_integers(fig_test, fig_ref):
  151. np.random.seed(19680801)
  152. Nx = 51
  153. x = (np.random.rand(Nx) * 10).cumsum()
  154. x = (np.ceil(x)).astype(np.int64)
  155. maxlags = Nx-1
  156. ax_test = fig_test.subplots()
  157. ax_test.acorr(x, maxlags=maxlags)
  158. ax_ref = fig_ref.subplots()
  159. # Normalized autocorrelation
  160. norm_auto_corr = np.correlate(x, x, mode="full")/np.dot(x, x)
  161. lags = np.arange(-maxlags, maxlags+1)
  162. norm_auto_corr = norm_auto_corr[Nx-1-maxlags:Nx+maxlags]
  163. ax_ref.vlines(lags, [0], norm_auto_corr)
  164. ax_ref.axhline(y=0, xmin=0, xmax=1)
  165. @check_figures_equal(extensions=["png"])
  166. def test_spy(fig_test, fig_ref):
  167. np.random.seed(19680801)
  168. a = np.ones(32 * 32)
  169. a[:16 * 32] = 0
  170. np.random.shuffle(a)
  171. a = a.reshape((32, 32))
  172. axs_test = fig_test.subplots(2)
  173. axs_test[0].spy(a)
  174. axs_test[1].spy(a, marker=".", origin="lower")
  175. axs_ref = fig_ref.subplots(2)
  176. axs_ref[0].imshow(a, cmap="gray_r", interpolation="nearest")
  177. axs_ref[0].xaxis.tick_top()
  178. axs_ref[1].plot(*np.nonzero(a)[::-1], ".", markersize=10)
  179. axs_ref[1].set(
  180. aspect=1, xlim=axs_ref[0].get_xlim(), ylim=axs_ref[0].get_ylim()[::-1])
  181. for ax in axs_ref:
  182. ax.xaxis.set_ticks_position("both")
  183. def test_spy_invalid_kwargs():
  184. fig, ax = plt.subplots()
  185. for unsupported_kw in [{'interpolation': 'nearest'},
  186. {'marker': 'o', 'linestyle': 'solid'}]:
  187. with pytest.raises(TypeError):
  188. ax.spy(np.eye(3, 3), **unsupported_kw)
  189. @check_figures_equal(extensions=["png"])
  190. def test_matshow(fig_test, fig_ref):
  191. mpl.style.use("mpl20")
  192. a = np.random.rand(32, 32)
  193. fig_test.add_subplot().matshow(a)
  194. ax_ref = fig_ref.add_subplot()
  195. ax_ref.imshow(a)
  196. ax_ref.xaxis.tick_top()
  197. ax_ref.xaxis.set_ticks_position('both')
  198. @image_comparison([f'formatter_ticker_{i:03d}.png' for i in range(1, 6)],
  199. tol=0 if platform.machine() == 'x86_64' else 0.031)
  200. def test_formatter_ticker():
  201. import matplotlib.testing.jpl_units as units
  202. units.register()
  203. # This should affect the tick size. (Tests issue #543)
  204. matplotlib.rcParams['lines.markeredgewidth'] = 30
  205. # This essentially test to see if user specified labels get overwritten
  206. # by the auto labeler functionality of the axes.
  207. xdata = [x*units.sec for x in range(10)]
  208. ydata1 = [(1.5*y - 0.5)*units.km for y in range(10)]
  209. ydata2 = [(1.75*y - 1.0)*units.km for y in range(10)]
  210. ax = plt.figure().subplots()
  211. ax.set_xlabel("x-label 001")
  212. ax = plt.figure().subplots()
  213. ax.set_xlabel("x-label 001")
  214. ax.plot(xdata, ydata1, color='blue', xunits="sec")
  215. ax = plt.figure().subplots()
  216. ax.set_xlabel("x-label 001")
  217. ax.plot(xdata, ydata1, color='blue', xunits="sec")
  218. ax.set_xlabel("x-label 003")
  219. ax = plt.figure().subplots()
  220. ax.plot(xdata, ydata1, color='blue', xunits="sec")
  221. ax.plot(xdata, ydata2, color='green', xunits="hour")
  222. ax.set_xlabel("x-label 004")
  223. # See SF bug 2846058
  224. # https://sourceforge.net/tracker/?func=detail&aid=2846058&group_id=80706&atid=560720
  225. ax = plt.figure().subplots()
  226. ax.plot(xdata, ydata1, color='blue', xunits="sec")
  227. ax.plot(xdata, ydata2, color='green', xunits="hour")
  228. ax.set_xlabel("x-label 005")
  229. ax.autoscale_view()
  230. def test_funcformatter_auto_formatter():
  231. def _formfunc(x, pos):
  232. return ''
  233. ax = plt.figure().subplots()
  234. assert ax.xaxis.isDefault_majfmt
  235. assert ax.xaxis.isDefault_minfmt
  236. assert ax.yaxis.isDefault_majfmt
  237. assert ax.yaxis.isDefault_minfmt
  238. ax.xaxis.set_major_formatter(_formfunc)
  239. assert not ax.xaxis.isDefault_majfmt
  240. assert ax.xaxis.isDefault_minfmt
  241. assert ax.yaxis.isDefault_majfmt
  242. assert ax.yaxis.isDefault_minfmt
  243. targ_funcformatter = mticker.FuncFormatter(_formfunc)
  244. assert isinstance(ax.xaxis.get_major_formatter(),
  245. mticker.FuncFormatter)
  246. assert ax.xaxis.get_major_formatter().func == targ_funcformatter.func
  247. def test_strmethodformatter_auto_formatter():
  248. formstr = '{x}_{pos}'
  249. ax = plt.figure().subplots()
  250. assert ax.xaxis.isDefault_majfmt
  251. assert ax.xaxis.isDefault_minfmt
  252. assert ax.yaxis.isDefault_majfmt
  253. assert ax.yaxis.isDefault_minfmt
  254. ax.yaxis.set_minor_formatter(formstr)
  255. assert ax.xaxis.isDefault_majfmt
  256. assert ax.xaxis.isDefault_minfmt
  257. assert ax.yaxis.isDefault_majfmt
  258. assert not ax.yaxis.isDefault_minfmt
  259. targ_strformatter = mticker.StrMethodFormatter(formstr)
  260. assert isinstance(ax.yaxis.get_minor_formatter(),
  261. mticker.StrMethodFormatter)
  262. assert ax.yaxis.get_minor_formatter().fmt == targ_strformatter.fmt
  263. @image_comparison(["twin_axis_locators_formatters.png"])
  264. def test_twin_axis_locators_formatters():
  265. vals = np.linspace(0, 1, num=5, endpoint=True)
  266. locs = np.sin(np.pi * vals / 2.0)
  267. majl = plt.FixedLocator(locs)
  268. minl = plt.FixedLocator([0.1, 0.2, 0.3])
  269. fig = plt.figure()
  270. ax1 = fig.add_subplot(1, 1, 1)
  271. ax1.plot([0.1, 100], [0, 1])
  272. ax1.yaxis.set_major_locator(majl)
  273. ax1.yaxis.set_minor_locator(minl)
  274. ax1.yaxis.set_major_formatter(plt.FormatStrFormatter('%08.2lf'))
  275. ax1.yaxis.set_minor_formatter(plt.FixedFormatter(['tricks', 'mind',
  276. 'jedi']))
  277. ax1.xaxis.set_major_locator(plt.LinearLocator())
  278. ax1.xaxis.set_minor_locator(plt.FixedLocator([15, 35, 55, 75]))
  279. ax1.xaxis.set_major_formatter(plt.FormatStrFormatter('%05.2lf'))
  280. ax1.xaxis.set_minor_formatter(plt.FixedFormatter(['c', '3', 'p', 'o']))
  281. ax1.twiny()
  282. ax1.twinx()
  283. def test_twinx_cla():
  284. fig, ax = plt.subplots()
  285. ax2 = ax.twinx()
  286. ax3 = ax2.twiny()
  287. plt.draw()
  288. assert not ax2.xaxis.get_visible()
  289. assert not ax2.patch.get_visible()
  290. ax2.cla()
  291. ax3.cla()
  292. assert not ax2.xaxis.get_visible()
  293. assert not ax2.patch.get_visible()
  294. assert ax2.yaxis.get_visible()
  295. assert ax3.xaxis.get_visible()
  296. assert not ax3.patch.get_visible()
  297. assert not ax3.yaxis.get_visible()
  298. assert ax.xaxis.get_visible()
  299. assert ax.patch.get_visible()
  300. assert ax.yaxis.get_visible()
  301. @pytest.mark.parametrize('twin', ('x', 'y'))
  302. def test_twin_units(twin):
  303. axis_name = f'{twin}axis'
  304. twin_func = f'twin{twin}'
  305. a = ['0', '1']
  306. b = ['a', 'b']
  307. fig = Figure()
  308. ax1 = fig.subplots()
  309. ax1.plot(a, b)
  310. assert getattr(ax1, axis_name).units is not None
  311. ax2 = getattr(ax1, twin_func)()
  312. assert getattr(ax2, axis_name).units is not None
  313. assert getattr(ax2, axis_name).units is getattr(ax1, axis_name).units
  314. @pytest.mark.parametrize('twin', ('x', 'y'))
  315. @check_figures_equal(extensions=['png'], tol=0.19)
  316. def test_twin_logscale(fig_test, fig_ref, twin):
  317. twin_func = f'twin{twin}' # test twinx or twiny
  318. set_scale = f'set_{twin}scale'
  319. x = np.arange(1, 100)
  320. # Change scale after twinning.
  321. ax_test = fig_test.add_subplot(2, 1, 1)
  322. ax_twin = getattr(ax_test, twin_func)()
  323. getattr(ax_test, set_scale)('log')
  324. ax_twin.plot(x, x)
  325. # Twin after changing scale.
  326. ax_test = fig_test.add_subplot(2, 1, 2)
  327. getattr(ax_test, set_scale)('log')
  328. ax_twin = getattr(ax_test, twin_func)()
  329. ax_twin.plot(x, x)
  330. for i in [1, 2]:
  331. ax_ref = fig_ref.add_subplot(2, 1, i)
  332. getattr(ax_ref, set_scale)('log')
  333. ax_ref.plot(x, x)
  334. # This is a hack because twinned Axes double-draw the frame.
  335. # Remove this when that is fixed.
  336. Path = matplotlib.path.Path
  337. fig_ref.add_artist(
  338. matplotlib.patches.PathPatch(
  339. Path([[0, 0], [0, 1],
  340. [0, 1], [1, 1],
  341. [1, 1], [1, 0],
  342. [1, 0], [0, 0]],
  343. [Path.MOVETO, Path.LINETO] * 4),
  344. transform=ax_ref.transAxes,
  345. facecolor='none',
  346. edgecolor=mpl.rcParams['axes.edgecolor'],
  347. linewidth=mpl.rcParams['axes.linewidth'],
  348. capstyle='projecting'))
  349. remove_ticks_and_titles(fig_test)
  350. remove_ticks_and_titles(fig_ref)
  351. @image_comparison(['twin_autoscale.png'],
  352. tol=0 if platform.machine() == 'x86_64' else 0.009)
  353. def test_twinx_axis_scales():
  354. x = np.array([0, 0.5, 1])
  355. y = 0.5 * x
  356. x2 = np.array([0, 1, 2])
  357. y2 = 2 * x2
  358. fig = plt.figure()
  359. ax = fig.add_axes((0, 0, 1, 1), autoscalex_on=False, autoscaley_on=False)
  360. ax.plot(x, y, color='blue', lw=10)
  361. ax2 = plt.twinx(ax)
  362. ax2.plot(x2, y2, 'r--', lw=5)
  363. ax.margins(0, 0)
  364. ax2.margins(0, 0)
  365. def test_twin_inherit_autoscale_setting():
  366. fig, ax = plt.subplots()
  367. ax_x_on = ax.twinx()
  368. ax.set_autoscalex_on(False)
  369. ax_x_off = ax.twinx()
  370. assert ax_x_on.get_autoscalex_on()
  371. assert not ax_x_off.get_autoscalex_on()
  372. ax_y_on = ax.twiny()
  373. ax.set_autoscaley_on(False)
  374. ax_y_off = ax.twiny()
  375. assert ax_y_on.get_autoscaley_on()
  376. assert not ax_y_off.get_autoscaley_on()
  377. def test_inverted_cla():
  378. # GitHub PR #5450. Setting autoscale should reset
  379. # axes to be non-inverted.
  380. # plotting an image, then 1d graph, axis is now down
  381. fig = plt.figure(0)
  382. ax = fig.gca()
  383. # 1. test that a new axis is not inverted per default
  384. assert not ax.xaxis_inverted()
  385. assert not ax.yaxis_inverted()
  386. img = np.random.random((100, 100))
  387. ax.imshow(img)
  388. # 2. test that a image axis is inverted
  389. assert not ax.xaxis_inverted()
  390. assert ax.yaxis_inverted()
  391. # 3. test that clearing and plotting a line, axes are
  392. # not inverted
  393. ax.cla()
  394. x = np.linspace(0, 2*np.pi, 100)
  395. ax.plot(x, np.cos(x))
  396. assert not ax.xaxis_inverted()
  397. assert not ax.yaxis_inverted()
  398. # 4. autoscaling should not bring back axes to normal
  399. ax.cla()
  400. ax.imshow(img)
  401. plt.autoscale()
  402. assert not ax.xaxis_inverted()
  403. assert ax.yaxis_inverted()
  404. for ax in fig.axes:
  405. ax.remove()
  406. # 5. two shared axes. Inverting the leader axis should invert the shared
  407. # axes; clearing the leader axis should bring axes in shared
  408. # axes back to normal.
  409. ax0 = plt.subplot(211)
  410. ax1 = plt.subplot(212, sharey=ax0)
  411. ax0.yaxis.set_inverted(True)
  412. assert ax1.yaxis_inverted()
  413. ax1.plot(x, np.cos(x))
  414. ax0.cla()
  415. assert not ax1.yaxis_inverted()
  416. ax1.cla()
  417. # 6. clearing the follower should not touch limits
  418. ax0.imshow(img)
  419. ax1.plot(x, np.cos(x))
  420. ax1.cla()
  421. assert ax.yaxis_inverted()
  422. # clean up
  423. plt.close(fig)
  424. def test_subclass_clear_cla():
  425. # Ensure that subclasses of Axes call cla/clear correctly.
  426. # Note, we cannot use mocking here as we want to be sure that the
  427. # superclass fallback does not recurse.
  428. with pytest.warns(PendingDeprecationWarning,
  429. match='Overriding `Axes.cla`'):
  430. class ClaAxes(Axes):
  431. def cla(self):
  432. nonlocal called
  433. called = True
  434. with pytest.warns(PendingDeprecationWarning,
  435. match='Overriding `Axes.cla`'):
  436. class ClaSuperAxes(Axes):
  437. def cla(self):
  438. nonlocal called
  439. called = True
  440. super().cla()
  441. class SubClaAxes(ClaAxes):
  442. pass
  443. class ClearAxes(Axes):
  444. def clear(self):
  445. nonlocal called
  446. called = True
  447. class ClearSuperAxes(Axes):
  448. def clear(self):
  449. nonlocal called
  450. called = True
  451. super().clear()
  452. class SubClearAxes(ClearAxes):
  453. pass
  454. fig = Figure()
  455. for axes_class in [ClaAxes, ClaSuperAxes, SubClaAxes,
  456. ClearAxes, ClearSuperAxes, SubClearAxes]:
  457. called = False
  458. ax = axes_class(fig, [0, 0, 1, 1])
  459. # Axes.__init__ has already called clear (which aliases to cla or is in
  460. # the subclass).
  461. assert called
  462. called = False
  463. ax.cla()
  464. assert called
  465. def test_cla_not_redefined_internally():
  466. for klass in Axes.__subclasses__():
  467. # Check that cla does not get redefined in our Axes subclasses, except
  468. # for in the above test function.
  469. if 'test_subclass_clear_cla' not in klass.__qualname__:
  470. assert 'cla' not in klass.__dict__
  471. @check_figures_equal(extensions=["png"])
  472. def test_minorticks_on_rcParams_both(fig_test, fig_ref):
  473. with matplotlib.rc_context({"xtick.minor.visible": True,
  474. "ytick.minor.visible": True}):
  475. ax_test = fig_test.subplots()
  476. ax_test.plot([0, 1], [0, 1])
  477. ax_ref = fig_ref.subplots()
  478. ax_ref.plot([0, 1], [0, 1])
  479. ax_ref.minorticks_on()
  480. @image_comparison(["autoscale_tiny_range.png"], remove_text=True)
  481. def test_autoscale_tiny_range():
  482. # github pull #904
  483. fig, axs = plt.subplots(2, 2)
  484. for i, ax in enumerate(axs.flat):
  485. y1 = 10**(-11 - i)
  486. ax.plot([0, 1], [1, 1 + y1])
  487. @mpl.style.context('default')
  488. def test_autoscale_tight():
  489. fig, ax = plt.subplots(1, 1)
  490. ax.plot([1, 2, 3, 4])
  491. ax.autoscale(enable=True, axis='x', tight=False)
  492. ax.autoscale(enable=True, axis='y', tight=True)
  493. assert_allclose(ax.get_xlim(), (-0.15, 3.15))
  494. assert_allclose(ax.get_ylim(), (1.0, 4.0))
  495. # Check that autoscale is on
  496. assert ax.get_autoscalex_on()
  497. assert ax.get_autoscaley_on()
  498. assert ax.get_autoscale_on()
  499. # Set enable to None
  500. ax.autoscale(enable=None)
  501. # Same limits
  502. assert_allclose(ax.get_xlim(), (-0.15, 3.15))
  503. assert_allclose(ax.get_ylim(), (1.0, 4.0))
  504. # autoscale still on
  505. assert ax.get_autoscalex_on()
  506. assert ax.get_autoscaley_on()
  507. assert ax.get_autoscale_on()
  508. @mpl.style.context('default')
  509. def test_autoscale_log_shared():
  510. # related to github #7587
  511. # array starts at zero to trigger _minpos handling
  512. x = np.arange(100, dtype=float)
  513. fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)
  514. ax1.loglog(x, x)
  515. ax2.semilogx(x, x)
  516. ax1.autoscale(tight=True)
  517. ax2.autoscale(tight=True)
  518. plt.draw()
  519. lims = (x[1], x[-1])
  520. assert_allclose(ax1.get_xlim(), lims)
  521. assert_allclose(ax1.get_ylim(), lims)
  522. assert_allclose(ax2.get_xlim(), lims)
  523. assert_allclose(ax2.get_ylim(), (x[0], x[-1]))
  524. @mpl.style.context('default')
  525. def test_use_sticky_edges():
  526. fig, ax = plt.subplots()
  527. ax.imshow([[0, 1], [2, 3]], origin='lower')
  528. assert_allclose(ax.get_xlim(), (-0.5, 1.5))
  529. assert_allclose(ax.get_ylim(), (-0.5, 1.5))
  530. ax.use_sticky_edges = False
  531. ax.autoscale()
  532. xlim = (-0.5 - 2 * ax._xmargin, 1.5 + 2 * ax._xmargin)
  533. ylim = (-0.5 - 2 * ax._ymargin, 1.5 + 2 * ax._ymargin)
  534. assert_allclose(ax.get_xlim(), xlim)
  535. assert_allclose(ax.get_ylim(), ylim)
  536. # Make sure it is reversible:
  537. ax.use_sticky_edges = True
  538. ax.autoscale()
  539. assert_allclose(ax.get_xlim(), (-0.5, 1.5))
  540. assert_allclose(ax.get_ylim(), (-0.5, 1.5))
  541. @check_figures_equal(extensions=["png"])
  542. def test_sticky_shared_axes(fig_test, fig_ref):
  543. # Check that sticky edges work whether they are set in an Axes that is a
  544. # "leader" in a share, or an Axes that is a "follower".
  545. Z = np.arange(15).reshape(3, 5)
  546. ax0 = fig_test.add_subplot(211)
  547. ax1 = fig_test.add_subplot(212, sharex=ax0)
  548. ax1.pcolormesh(Z)
  549. ax0 = fig_ref.add_subplot(212)
  550. ax1 = fig_ref.add_subplot(211, sharex=ax0)
  551. ax0.pcolormesh(Z)
  552. @image_comparison(['sticky_tolerance.png'], remove_text=True, style="mpl20")
  553. def test_sticky_tolerance():
  554. fig, axs = plt.subplots(2, 2)
  555. width = .1
  556. axs.flat[0].bar(x=0, height=width, bottom=20000.6)
  557. axs.flat[0].bar(x=1, height=width, bottom=20000.1)
  558. axs.flat[1].bar(x=0, height=-width, bottom=20000.6)
  559. axs.flat[1].bar(x=1, height=-width, bottom=20000.1)
  560. axs.flat[2].barh(y=0, width=-width, left=-20000.6)
  561. axs.flat[2].barh(y=1, width=-width, left=-20000.1)
  562. axs.flat[3].barh(y=0, width=width, left=-20000.6)
  563. axs.flat[3].barh(y=1, width=width, left=-20000.1)
  564. @image_comparison(['sticky_tolerance_cf.png'], remove_text=True, style="mpl20")
  565. def test_sticky_tolerance_contourf():
  566. fig, ax = plt.subplots()
  567. x = y = [14496.71, 14496.75]
  568. data = [[0, 1], [2, 3]]
  569. ax.contourf(x, y, data)
  570. def test_nargs_stem():
  571. with pytest.raises(TypeError, match='0 were given'):
  572. # stem() takes 1-3 arguments.
  573. plt.stem()
  574. def test_nargs_legend():
  575. with pytest.raises(TypeError, match='3 were given'):
  576. ax = plt.subplot()
  577. # legend() takes 0-2 arguments.
  578. ax.legend(['First'], ['Second'], 3)
  579. def test_nargs_pcolorfast():
  580. with pytest.raises(TypeError, match='2 were given'):
  581. ax = plt.subplot()
  582. # pcolorfast() takes 1 or 3 arguments,
  583. # not passing any arguments fails at C = args[-1]
  584. # before nargs_err is raised.
  585. ax.pcolorfast([(0, 1), (0, 2)], [[1, 2, 3], [1, 2, 3]])
  586. @image_comparison(['offset_points'], remove_text=True)
  587. def test_basic_annotate():
  588. # Setup some data
  589. t = np.arange(0.0, 5.0, 0.01)
  590. s = np.cos(2.0*np.pi * t)
  591. # Offset Points
  592. fig = plt.figure()
  593. ax = fig.add_subplot(autoscale_on=False, xlim=(-1, 5), ylim=(-3, 5))
  594. line, = ax.plot(t, s, lw=3, color='purple')
  595. ax.annotate('local max', xy=(3, 1), xycoords='data',
  596. xytext=(3, 3), textcoords='offset points')
  597. @image_comparison(['arrow_simple.png'], remove_text=True)
  598. def test_arrow_simple():
  599. # Simple image test for ax.arrow
  600. # kwargs that take discrete values
  601. length_includes_head = (True, False)
  602. shape = ('full', 'left', 'right')
  603. head_starts_at_zero = (True, False)
  604. # Create outer product of values
  605. kwargs = product(length_includes_head, shape, head_starts_at_zero)
  606. fig, axs = plt.subplots(3, 4)
  607. for i, (ax, kwarg) in enumerate(zip(axs.flat, kwargs)):
  608. ax.set_xlim(-2, 2)
  609. ax.set_ylim(-2, 2)
  610. # Unpack kwargs
  611. (length_includes_head, shape, head_starts_at_zero) = kwarg
  612. theta = 2 * np.pi * i / 12
  613. # Draw arrow
  614. ax.arrow(0, 0, np.sin(theta), np.cos(theta),
  615. width=theta/100,
  616. length_includes_head=length_includes_head,
  617. shape=shape,
  618. head_starts_at_zero=head_starts_at_zero,
  619. head_width=theta / 10,
  620. head_length=theta / 10)
  621. def test_arrow_empty():
  622. _, ax = plt.subplots()
  623. # Create an empty FancyArrow
  624. ax.arrow(0, 0, 0, 0, head_length=0)
  625. def test_arrow_in_view():
  626. _, ax = plt.subplots()
  627. ax.arrow(1, 1, 1, 1)
  628. assert ax.get_xlim() == (0.8, 2.2)
  629. assert ax.get_ylim() == (0.8, 2.2)
  630. def test_annotate_default_arrow():
  631. # Check that we can make an annotation arrow with only default properties.
  632. fig, ax = plt.subplots()
  633. ann = ax.annotate("foo", (0, 1), xytext=(2, 3))
  634. assert ann.arrow_patch is None
  635. ann = ax.annotate("foo", (0, 1), xytext=(2, 3), arrowprops={})
  636. assert ann.arrow_patch is not None
  637. def test_annotate_signature():
  638. """Check that the signature of Axes.annotate() matches Annotation."""
  639. fig, ax = plt.subplots()
  640. annotate_params = inspect.signature(ax.annotate).parameters
  641. annotation_params = inspect.signature(mtext.Annotation).parameters
  642. assert list(annotate_params.keys()) == list(annotation_params.keys())
  643. for p1, p2 in zip(annotate_params.values(), annotation_params.values()):
  644. assert p1 == p2
  645. @image_comparison(['fill_units.png'], savefig_kwarg={'dpi': 60})
  646. def test_fill_units():
  647. import matplotlib.testing.jpl_units as units
  648. units.register()
  649. # generate some data
  650. t = units.Epoch("ET", dt=datetime.datetime(2009, 4, 27))
  651. value = 10.0 * units.deg
  652. day = units.Duration("ET", 24.0 * 60.0 * 60.0)
  653. dt = np.arange('2009-04-27', '2009-04-29', dtype='datetime64[D]')
  654. dtn = mdates.date2num(dt)
  655. fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
  656. ax1.plot([t], [value], yunits='deg', color='red')
  657. ind = [0, 0, 1, 1]
  658. ax1.fill(dtn[ind], [0.0, 0.0, 90.0, 0.0], 'b')
  659. ax2.plot([t], [value], yunits='deg', color='red')
  660. ax2.fill([t, t, t + day, t + day],
  661. [0.0, 0.0, 90.0, 0.0], 'b')
  662. ax3.plot([t], [value], yunits='deg', color='red')
  663. ax3.fill(dtn[ind],
  664. [0 * units.deg, 0 * units.deg, 90 * units.deg, 0 * units.deg],
  665. 'b')
  666. ax4.plot([t], [value], yunits='deg', color='red')
  667. ax4.fill([t, t, t + day, t + day],
  668. [0 * units.deg, 0 * units.deg, 90 * units.deg, 0 * units.deg],
  669. facecolor="blue")
  670. fig.autofmt_xdate()
  671. def test_plot_format_kwarg_redundant():
  672. with pytest.warns(UserWarning, match="marker .* redundantly defined"):
  673. plt.plot([0], [0], 'o', marker='x')
  674. with pytest.warns(UserWarning, match="linestyle .* redundantly defined"):
  675. plt.plot([0], [0], '-', linestyle='--')
  676. with pytest.warns(UserWarning, match="color .* redundantly defined"):
  677. plt.plot([0], [0], 'r', color='blue')
  678. # smoke-test: should not warn
  679. plt.errorbar([0], [0], fmt='none', color='blue')
  680. @check_figures_equal(extensions=["png"])
  681. def test_errorbar_dashes(fig_test, fig_ref):
  682. x = [1, 2, 3, 4]
  683. y = np.sin(x)
  684. ax_ref = fig_ref.gca()
  685. ax_test = fig_test.gca()
  686. line, *_ = ax_ref.errorbar(x, y, xerr=np.abs(y), yerr=np.abs(y))
  687. line.set_dashes([2, 2])
  688. ax_test.errorbar(x, y, xerr=np.abs(y), yerr=np.abs(y), dashes=[2, 2])
  689. def test_errorbar_mapview_kwarg():
  690. D = {ii: ii for ii in range(10)}
  691. fig, ax = plt.subplots()
  692. ax.errorbar(x=D.keys(), y=D.values(), xerr=D.values())
  693. @image_comparison(['single_point', 'single_point'])
  694. def test_single_point():
  695. # Issue #1796: don't let lines.marker affect the grid
  696. matplotlib.rcParams['lines.marker'] = 'o'
  697. matplotlib.rcParams['axes.grid'] = True
  698. fig, (ax1, ax2) = plt.subplots(2)
  699. ax1.plot([0], [0], 'o')
  700. ax2.plot([1], [1], 'o')
  701. # Reuse testcase from above for a labeled data test
  702. data = {'a': [0], 'b': [1]}
  703. fig, (ax1, ax2) = plt.subplots(2)
  704. ax1.plot('a', 'a', 'o', data=data)
  705. ax2.plot('b', 'b', 'o', data=data)
  706. @image_comparison(['single_date.png'], style='mpl20')
  707. def test_single_date():
  708. # use former defaults to match existing baseline image
  709. plt.rcParams['axes.formatter.limits'] = -7, 7
  710. dt = mdates.date2num(np.datetime64('0000-12-31'))
  711. time1 = [721964.0]
  712. data1 = [-65.54]
  713. fig, ax = plt.subplots(2, 1)
  714. with pytest.warns(mpl.MatplotlibDeprecationWarning):
  715. ax[0].plot_date(time1 + dt, data1, 'o', color='r')
  716. ax[1].plot(time1, data1, 'o', color='r')
  717. @check_figures_equal(extensions=["png"])
  718. def test_shaped_data(fig_test, fig_ref):
  719. row = np.arange(10).reshape((1, -1))
  720. col = np.arange(0, 100, 10).reshape((-1, 1))
  721. axs = fig_test.subplots(2)
  722. axs[0].plot(row) # Actually plots nothing (columns are single points).
  723. axs[1].plot(col) # Same as plotting 1d.
  724. axs = fig_ref.subplots(2)
  725. # xlim from the implicit "x=0", ylim from the row datalim.
  726. axs[0].set(xlim=(-.06, .06), ylim=(0, 9))
  727. axs[1].plot(col.ravel())
  728. def test_structured_data():
  729. # support for structured data
  730. pts = np.array([(1, 1), (2, 2)], dtype=[("ones", float), ("twos", float)])
  731. # this should not read second name as a format and raise ValueError
  732. axs = plt.figure().subplots(2)
  733. axs[0].plot("ones", "twos", data=pts)
  734. axs[1].plot("ones", "twos", "r", data=pts)
  735. @image_comparison(['aitoff_proj'], extensions=["png"],
  736. remove_text=True, style='mpl20')
  737. def test_aitoff_proj():
  738. """
  739. Test aitoff projection ref.:
  740. https://github.com/matplotlib/matplotlib/pull/14451
  741. """
  742. x = np.linspace(-np.pi, np.pi, 20)
  743. y = np.linspace(-np.pi / 2, np.pi / 2, 20)
  744. X, Y = np.meshgrid(x, y)
  745. fig, ax = plt.subplots(figsize=(8, 4.2),
  746. subplot_kw=dict(projection="aitoff"))
  747. ax.grid()
  748. ax.plot(X.flat, Y.flat, 'o', markersize=4)
  749. @image_comparison(['axvspan_epoch.png'])
  750. def test_axvspan_epoch():
  751. import matplotlib.testing.jpl_units as units
  752. units.register()
  753. # generate some data
  754. t0 = units.Epoch("ET", dt=datetime.datetime(2009, 1, 21))
  755. tf = units.Epoch("ET", dt=datetime.datetime(2009, 1, 22))
  756. dt = units.Duration("ET", units.day.convert("sec"))
  757. ax = plt.gca()
  758. ax.axvspan(t0, tf, facecolor="blue", alpha=0.25)
  759. ax.set_xlim(t0 - 5.0*dt, tf + 5.0*dt)
  760. @image_comparison(['axhspan_epoch.png'], tol=0.02)
  761. def test_axhspan_epoch():
  762. import matplotlib.testing.jpl_units as units
  763. units.register()
  764. # generate some data
  765. t0 = units.Epoch("ET", dt=datetime.datetime(2009, 1, 21))
  766. tf = units.Epoch("ET", dt=datetime.datetime(2009, 1, 22))
  767. dt = units.Duration("ET", units.day.convert("sec"))
  768. ax = plt.gca()
  769. ax.axhspan(t0, tf, facecolor="blue", alpha=0.25)
  770. ax.set_ylim(t0 - 5.0*dt, tf + 5.0*dt)
  771. @image_comparison(['hexbin_extent.png', 'hexbin_extent.png'], remove_text=True)
  772. def test_hexbin_extent():
  773. # this test exposes sf bug 2856228
  774. fig, ax = plt.subplots()
  775. data = (np.arange(2000) / 2000).reshape((2, 1000))
  776. x, y = data
  777. ax.hexbin(x, y, extent=[.1, .3, .6, .7])
  778. # Reuse testcase from above for a labeled data test
  779. data = {"x": x, "y": y}
  780. fig, ax = plt.subplots()
  781. ax.hexbin("x", "y", extent=[.1, .3, .6, .7], data=data)
  782. def test_hexbin_bad_extents():
  783. fig, ax = plt.subplots()
  784. data = (np.arange(20) / 20).reshape((2, 10))
  785. x, y = data
  786. with pytest.raises(ValueError, match="In extent, xmax must be greater than xmin"):
  787. ax.hexbin(x, y, extent=(1, 0, 0, 1))
  788. with pytest.raises(ValueError, match="In extent, ymax must be greater than ymin"):
  789. ax.hexbin(x, y, extent=(0, 1, 1, 0))
  790. def test_hexbin_string_norm():
  791. fig, ax = plt.subplots()
  792. hex = ax.hexbin(np.random.rand(10), np.random.rand(10), norm="log", vmin=2, vmax=5)
  793. assert isinstance(hex, matplotlib.collections.PolyCollection)
  794. assert isinstance(hex.norm, matplotlib.colors.LogNorm)
  795. assert hex.norm.vmin == 2
  796. assert hex.norm.vmax == 5
  797. @image_comparison(['hexbin_empty.png'], remove_text=True)
  798. def test_hexbin_empty():
  799. # From #3886: creating hexbin from empty dataset raises ValueError
  800. fig, ax = plt.subplots()
  801. ax.hexbin([], [])
  802. # From #23922: creating hexbin with log scaling from empty
  803. # dataset raises ValueError
  804. ax.hexbin([], [], bins='log')
  805. # From #27103: np.max errors when handed empty data
  806. ax.hexbin([], [], C=[], reduce_C_function=np.max)
  807. # No string-comparison warning from NumPy.
  808. ax.hexbin([], [], bins=np.arange(10))
  809. def test_hexbin_pickable():
  810. # From #1973: Test that picking a hexbin collection works
  811. fig, ax = plt.subplots()
  812. data = (np.arange(200) / 200).reshape((2, 100))
  813. x, y = data
  814. hb = ax.hexbin(x, y, extent=[.1, .3, .6, .7], picker=-1)
  815. mouse_event = SimpleNamespace(x=400, y=300)
  816. assert hb.contains(mouse_event)[0]
  817. @image_comparison(['hexbin_log.png'], style='mpl20')
  818. def test_hexbin_log():
  819. # Issue #1636 (and also test log scaled colorbar)
  820. # Remove this line when this test image is regenerated.
  821. plt.rcParams['pcolormesh.snap'] = False
  822. np.random.seed(19680801)
  823. n = 100000
  824. x = np.random.standard_normal(n)
  825. y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
  826. y = np.power(2, y * 0.5)
  827. fig, ax = plt.subplots()
  828. h = ax.hexbin(x, y, yscale='log', bins='log',
  829. marginals=True, reduce_C_function=np.sum)
  830. plt.colorbar(h)
  831. # Make sure offsets are set
  832. assert h.get_offsets().shape == (11558, 2)
  833. def test_hexbin_log_offsets():
  834. x = np.geomspace(1, 100, 500)
  835. fig, ax = plt.subplots()
  836. h = ax.hexbin(x, x, xscale='log', yscale='log', gridsize=2)
  837. np.testing.assert_almost_equal(
  838. h.get_offsets(),
  839. np.array(
  840. [[0, 0],
  841. [0, 2],
  842. [1, 0],
  843. [1, 2],
  844. [2, 0],
  845. [2, 2],
  846. [0.5, 1],
  847. [1.5, 1]]))
  848. @image_comparison(["hexbin_linear.png"], style="mpl20", remove_text=True)
  849. def test_hexbin_linear():
  850. # Issue #21165
  851. np.random.seed(19680801)
  852. n = 100000
  853. x = np.random.standard_normal(n)
  854. y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
  855. fig, ax = plt.subplots()
  856. ax.hexbin(x, y, gridsize=(10, 5), marginals=True,
  857. reduce_C_function=np.sum)
  858. def test_hexbin_log_clim():
  859. x, y = np.arange(200).reshape((2, 100))
  860. fig, ax = plt.subplots()
  861. h = ax.hexbin(x, y, bins='log', vmin=2, vmax=100)
  862. assert h.get_clim() == (2, 100)
  863. @check_figures_equal(extensions=['png'])
  864. def test_hexbin_mincnt_behavior_upon_C_parameter(fig_test, fig_ref):
  865. # see: gh:12926
  866. datapoints = [
  867. # list of (x, y)
  868. (0, 0),
  869. (0, 0),
  870. (6, 0),
  871. (0, 6),
  872. ]
  873. X, Y = zip(*datapoints)
  874. C = [1] * len(X)
  875. extent = [-10., 10, -10., 10]
  876. gridsize = (7, 7)
  877. ax_test = fig_test.subplots()
  878. ax_ref = fig_ref.subplots()
  879. # without C parameter
  880. ax_ref.hexbin(
  881. X, Y,
  882. extent=extent,
  883. gridsize=gridsize,
  884. mincnt=1,
  885. )
  886. ax_ref.set_facecolor("green") # for contrast of background
  887. # with C parameter
  888. ax_test.hexbin(
  889. X, Y,
  890. C=[1] * len(X),
  891. reduce_C_function=lambda v: sum(v),
  892. mincnt=1,
  893. extent=extent,
  894. gridsize=gridsize,
  895. )
  896. ax_test.set_facecolor("green")
  897. def test_inverted_limits():
  898. # Test gh:1553
  899. # Calling invert_xaxis prior to plotting should not disable autoscaling
  900. # while still maintaining the inverted direction
  901. fig, ax = plt.subplots()
  902. ax.invert_xaxis()
  903. ax.plot([-5, -3, 2, 4], [1, 2, -3, 5])
  904. assert ax.get_xlim() == (4, -5)
  905. assert ax.get_ylim() == (-3, 5)
  906. plt.close()
  907. fig, ax = plt.subplots()
  908. ax.invert_yaxis()
  909. ax.plot([-5, -3, 2, 4], [1, 2, -3, 5])
  910. assert ax.get_xlim() == (-5, 4)
  911. assert ax.get_ylim() == (5, -3)
  912. # Test inverting nonlinear axes.
  913. fig, ax = plt.subplots()
  914. ax.set_yscale("log")
  915. ax.set_ylim(10, 1)
  916. assert ax.get_ylim() == (10, 1)
  917. @image_comparison(['nonfinite_limits'])
  918. def test_nonfinite_limits():
  919. x = np.arange(0., np.e, 0.01)
  920. # silence divide by zero warning from log(0)
  921. with np.errstate(divide='ignore'):
  922. y = np.log(x)
  923. x[len(x)//2] = np.nan
  924. fig, ax = plt.subplots()
  925. ax.plot(x, y)
  926. @mpl.style.context('default')
  927. @pytest.mark.parametrize('plot_fun',
  928. ['scatter', 'plot', 'fill_between'])
  929. @check_figures_equal(extensions=["png"])
  930. def test_limits_empty_data(plot_fun, fig_test, fig_ref):
  931. # Check that plotting empty data doesn't change autoscaling of dates
  932. x = np.arange("2010-01-01", "2011-01-01", dtype="datetime64[D]")
  933. ax_test = fig_test.subplots()
  934. ax_ref = fig_ref.subplots()
  935. getattr(ax_test, plot_fun)([], [])
  936. for ax in [ax_test, ax_ref]:
  937. getattr(ax, plot_fun)(x, range(len(x)), color='C0')
  938. @image_comparison(['imshow', 'imshow'], remove_text=True, style='mpl20')
  939. def test_imshow():
  940. # use former defaults to match existing baseline image
  941. matplotlib.rcParams['image.interpolation'] = 'nearest'
  942. # Create a NxN image
  943. N = 100
  944. (x, y) = np.indices((N, N))
  945. x -= N//2
  946. y -= N//2
  947. r = np.sqrt(x**2+y**2-x*y)
  948. # Create a contour plot at N/4 and extract both the clip path and transform
  949. fig, ax = plt.subplots()
  950. ax.imshow(r)
  951. # Reuse testcase from above for a labeled data test
  952. data = {"r": r}
  953. fig, ax = plt.subplots()
  954. ax.imshow("r", data=data)
  955. @image_comparison(['imshow_clip'], style='mpl20',
  956. tol=0 if platform.machine() == 'x86_64' else 1.24)
  957. def test_imshow_clip():
  958. # As originally reported by Gellule Xg <gellule.xg@free.fr>
  959. # use former defaults to match existing baseline image
  960. matplotlib.rcParams['image.interpolation'] = 'nearest'
  961. # Create a NxN image
  962. N = 100
  963. (x, y) = np.indices((N, N))
  964. x -= N//2
  965. y -= N//2
  966. r = np.sqrt(x**2+y**2-x*y)
  967. # Create a contour plot at N/4 and extract both the clip path and transform
  968. fig, ax = plt.subplots()
  969. c = ax.contour(r, [N/4])
  970. clip_path = mtransforms.TransformedPath(c.get_paths()[0], c.get_transform())
  971. # Plot the image clipped by the contour
  972. ax.imshow(r, clip_path=clip_path)
  973. def test_imshow_norm_vminvmax():
  974. """Parameters vmin, vmax should error if norm is given."""
  975. a = [[1, 2], [3, 4]]
  976. ax = plt.axes()
  977. with pytest.raises(ValueError,
  978. match="Passing a Normalize instance simultaneously "
  979. "with vmin/vmax is not supported."):
  980. ax.imshow(a, norm=mcolors.Normalize(-10, 10), vmin=0, vmax=5)
  981. @image_comparison(['polycollection_joinstyle'], remove_text=True)
  982. def test_polycollection_joinstyle():
  983. # Bug #2890979 reported by Matthew West
  984. fig, ax = plt.subplots()
  985. verts = np.array([[1, 1], [1, 2], [2, 2], [2, 1]])
  986. c = mpl.collections.PolyCollection([verts], linewidths=40)
  987. ax.add_collection(c)
  988. ax.set_xbound(0, 3)
  989. ax.set_ybound(0, 3)
  990. @pytest.mark.parametrize(
  991. 'x, y1, y2', [
  992. (np.zeros((2, 2)), 3, 3),
  993. (np.arange(0.0, 2, 0.02), np.zeros((2, 2)), 3),
  994. (np.arange(0.0, 2, 0.02), 3, np.zeros((2, 2)))
  995. ], ids=[
  996. '2d_x_input',
  997. '2d_y1_input',
  998. '2d_y2_input'
  999. ]
  1000. )
  1001. def test_fill_between_input(x, y1, y2):
  1002. fig, ax = plt.subplots()
  1003. with pytest.raises(ValueError):
  1004. ax.fill_between(x, y1, y2)
  1005. @pytest.mark.parametrize(
  1006. 'y, x1, x2', [
  1007. (np.zeros((2, 2)), 3, 3),
  1008. (np.arange(0.0, 2, 0.02), np.zeros((2, 2)), 3),
  1009. (np.arange(0.0, 2, 0.02), 3, np.zeros((2, 2)))
  1010. ], ids=[
  1011. '2d_y_input',
  1012. '2d_x1_input',
  1013. '2d_x2_input'
  1014. ]
  1015. )
  1016. def test_fill_betweenx_input(y, x1, x2):
  1017. fig, ax = plt.subplots()
  1018. with pytest.raises(ValueError):
  1019. ax.fill_betweenx(y, x1, x2)
  1020. @image_comparison(['fill_between_interpolate.png'], remove_text=True,
  1021. tol=0 if platform.machine() == 'x86_64' else 0.012)
  1022. def test_fill_between_interpolate():
  1023. x = np.arange(0.0, 2, 0.02)
  1024. y1 = np.sin(2*np.pi*x)
  1025. y2 = 1.2*np.sin(4*np.pi*x)
  1026. fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)
  1027. ax1.plot(x, y1, x, y2, color='black')
  1028. ax1.fill_between(x, y1, y2, where=y2 >= y1, facecolor='white', hatch='/',
  1029. interpolate=True)
  1030. ax1.fill_between(x, y1, y2, where=y2 <= y1, facecolor='red',
  1031. interpolate=True)
  1032. # Test support for masked arrays.
  1033. y2 = np.ma.masked_greater(y2, 1.0)
  1034. # Test that plotting works for masked arrays with the first element masked
  1035. y2[0] = np.ma.masked
  1036. ax2.plot(x, y1, x, y2, color='black')
  1037. ax2.fill_between(x, y1, y2, where=y2 >= y1, facecolor='green',
  1038. interpolate=True)
  1039. ax2.fill_between(x, y1, y2, where=y2 <= y1, facecolor='red',
  1040. interpolate=True)
  1041. @image_comparison(['fill_between_interpolate_decreasing.png'],
  1042. style='mpl20', remove_text=True)
  1043. def test_fill_between_interpolate_decreasing():
  1044. p = np.array([724.3, 700, 655])
  1045. t = np.array([9.4, 7, 2.2])
  1046. prof = np.array([7.9, 6.6, 3.8])
  1047. fig, ax = plt.subplots(figsize=(9, 9))
  1048. ax.plot(t, p, 'tab:red')
  1049. ax.plot(prof, p, 'k')
  1050. ax.fill_betweenx(p, t, prof, where=prof < t,
  1051. facecolor='blue', interpolate=True, alpha=0.4)
  1052. ax.fill_betweenx(p, t, prof, where=prof > t,
  1053. facecolor='red', interpolate=True, alpha=0.4)
  1054. ax.set_xlim(0, 30)
  1055. ax.set_ylim(800, 600)
  1056. @image_comparison(['fill_between_interpolate_nan.png'], remove_text=True)
  1057. def test_fill_between_interpolate_nan():
  1058. # Tests fix for issue #18986.
  1059. x = np.arange(10)
  1060. y1 = np.asarray([8, 18, np.nan, 18, 8, 18, 24, 18, 8, 18])
  1061. y2 = np.asarray([18, 11, 8, 11, 18, 26, 32, 30, np.nan, np.nan])
  1062. fig, ax = plt.subplots()
  1063. ax.plot(x, y1, c='k')
  1064. ax.plot(x, y2, c='b')
  1065. ax.fill_between(x, y1, y2, where=y2 >= y1, facecolor="green",
  1066. interpolate=True, alpha=0.5)
  1067. ax.fill_between(x, y1, y2, where=y1 >= y2, facecolor="red",
  1068. interpolate=True, alpha=0.5)
  1069. # test_symlog and test_symlog2 used to have baseline images in all three
  1070. # formats, but the png and svg baselines got invalidated by the removal of
  1071. # minor tick overstriking.
  1072. @image_comparison(['symlog.pdf'])
  1073. def test_symlog():
  1074. x = np.array([0, 1, 2, 4, 6, 9, 12, 24])
  1075. y = np.array([1000000, 500000, 100000, 100, 5, 0, 0, 0])
  1076. fig, ax = plt.subplots()
  1077. ax.plot(x, y)
  1078. ax.set_yscale('symlog')
  1079. ax.set_xscale('linear')
  1080. ax.set_ylim(-1, 10000000)
  1081. @image_comparison(['symlog2.pdf'], remove_text=True)
  1082. def test_symlog2():
  1083. # Numbers from -50 to 50, with 0.1 as step
  1084. x = np.arange(-50, 50, 0.001)
  1085. fig, axs = plt.subplots(5, 1)
  1086. for ax, linthresh in zip(axs, [20., 2., 1., 0.1, 0.01]):
  1087. ax.plot(x, x)
  1088. ax.set_xscale('symlog', linthresh=linthresh)
  1089. ax.grid(True)
  1090. axs[-1].set_ylim(-0.1, 0.1)
  1091. def test_pcolorargs_5205():
  1092. # Smoketest to catch issue found in gh:5205
  1093. x = [-1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5]
  1094. y = [-1.5, -1.25, -1.0, -0.75, -0.5, -0.25, 0,
  1095. 0.25, 0.5, 0.75, 1.0, 1.25, 1.5]
  1096. X, Y = np.meshgrid(x, y)
  1097. Z = np.hypot(X, Y)
  1098. plt.pcolor(Z)
  1099. plt.pcolor(list(Z))
  1100. plt.pcolor(x, y, Z[:-1, :-1])
  1101. plt.pcolor(X, Y, list(Z[:-1, :-1]))
  1102. @image_comparison(['pcolormesh'], remove_text=True)
  1103. def test_pcolormesh():
  1104. # Remove this line when this test image is regenerated.
  1105. plt.rcParams['pcolormesh.snap'] = False
  1106. n = 12
  1107. x = np.linspace(-1.5, 1.5, n)
  1108. y = np.linspace(-1.5, 1.5, n*2)
  1109. X, Y = np.meshgrid(x, y)
  1110. Qx = np.cos(Y) - np.cos(X)
  1111. Qz = np.sin(Y) + np.sin(X)
  1112. Qx = (Qx + 1.1)
  1113. Z = np.hypot(X, Y) / 5
  1114. Z = (Z - Z.min()) / np.ptp(Z)
  1115. # The color array can include masked values:
  1116. Zm = ma.masked_where(np.abs(Qz) < 0.5 * np.max(Qz), Z)
  1117. _, (ax1, ax2, ax3) = plt.subplots(1, 3)
  1118. ax1.pcolormesh(Qx, Qz, Zm[:-1, :-1], lw=0.5, edgecolors='k')
  1119. ax2.pcolormesh(Qx, Qz, Zm[:-1, :-1], lw=2, edgecolors=['b', 'w'])
  1120. ax3.pcolormesh(Qx, Qz, Zm, shading="gouraud")
  1121. @image_comparison(['pcolormesh_small'], extensions=["eps"])
  1122. def test_pcolormesh_small():
  1123. n = 3
  1124. x = np.linspace(-1.5, 1.5, n)
  1125. y = np.linspace(-1.5, 1.5, n*2)
  1126. X, Y = np.meshgrid(x, y)
  1127. Qx = np.cos(Y) - np.cos(X)
  1128. Qz = np.sin(Y) + np.sin(X)
  1129. Qx = (Qx + 1.1)
  1130. Z = np.hypot(X, Y) / 5
  1131. Z = (Z - Z.min()) / np.ptp(Z)
  1132. Zm = ma.masked_where(np.abs(Qz) < 0.5 * np.max(Qz), Z)
  1133. Zm2 = ma.masked_where(Qz < -0.5 * np.max(Qz), Z)
  1134. fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
  1135. ax1.pcolormesh(Qx, Qz, Zm[:-1, :-1], lw=0.5, edgecolors='k')
  1136. ax2.pcolormesh(Qx, Qz, Zm[:-1, :-1], lw=2, edgecolors=['b', 'w'])
  1137. # gouraud with Zm yields a blank plot; there are no unmasked triangles.
  1138. ax3.pcolormesh(Qx, Qz, Zm, shading="gouraud")
  1139. # Reduce the masking to get a plot.
  1140. ax4.pcolormesh(Qx, Qz, Zm2, shading="gouraud")
  1141. for ax in fig.axes:
  1142. ax.set_axis_off()
  1143. @image_comparison(['pcolormesh_alpha'], extensions=["png", "pdf"],
  1144. remove_text=True)
  1145. def test_pcolormesh_alpha():
  1146. # Remove this line when this test image is regenerated.
  1147. plt.rcParams['pcolormesh.snap'] = False
  1148. n = 12
  1149. X, Y = np.meshgrid(
  1150. np.linspace(-1.5, 1.5, n),
  1151. np.linspace(-1.5, 1.5, n*2)
  1152. )
  1153. Qx = X
  1154. Qy = Y + np.sin(X)
  1155. Z = np.hypot(X, Y) / 5
  1156. Z = (Z - Z.min()) / np.ptp(Z)
  1157. vir = mpl.colormaps["viridis"].resampled(16)
  1158. # make another colormap with varying alpha
  1159. colors = vir(np.arange(16))
  1160. colors[:, 3] = 0.5 + 0.5*np.sin(np.arange(16))
  1161. cmap = mcolors.ListedColormap(colors)
  1162. fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
  1163. for ax in ax1, ax2, ax3, ax4:
  1164. ax.add_patch(mpatches.Rectangle(
  1165. (0, -1.5), 1.5, 3, facecolor=[.7, .1, .1, .5], zorder=0
  1166. ))
  1167. # ax1, ax2: constant alpha
  1168. ax1.pcolormesh(Qx, Qy, Z[:-1, :-1], cmap=vir, alpha=0.4,
  1169. shading='flat', zorder=1)
  1170. ax2.pcolormesh(Qx, Qy, Z, cmap=vir, alpha=0.4, shading='gouraud', zorder=1)
  1171. # ax3, ax4: alpha from colormap
  1172. ax3.pcolormesh(Qx, Qy, Z[:-1, :-1], cmap=cmap, shading='flat', zorder=1)
  1173. ax4.pcolormesh(Qx, Qy, Z, cmap=cmap, shading='gouraud', zorder=1)
  1174. @pytest.mark.parametrize("dims,alpha", [(3, 1), (4, 0.5)])
  1175. @check_figures_equal(extensions=["png"])
  1176. def test_pcolormesh_rgba(fig_test, fig_ref, dims, alpha):
  1177. ax = fig_test.subplots()
  1178. c = np.ones((5, 6, dims), dtype=float) / 2
  1179. ax.pcolormesh(c)
  1180. ax = fig_ref.subplots()
  1181. ax.pcolormesh(c[..., 0], cmap="gray", vmin=0, vmax=1, alpha=alpha)
  1182. @check_figures_equal(extensions=["png"])
  1183. def test_pcolormesh_nearest_noargs(fig_test, fig_ref):
  1184. x = np.arange(4)
  1185. y = np.arange(7)
  1186. X, Y = np.meshgrid(x, y)
  1187. C = X + Y
  1188. ax = fig_test.subplots()
  1189. ax.pcolormesh(C, shading="nearest")
  1190. ax = fig_ref.subplots()
  1191. ax.pcolormesh(x, y, C, shading="nearest")
  1192. @image_comparison(['pcolormesh_datetime_axis.png'], style='mpl20')
  1193. def test_pcolormesh_datetime_axis():
  1194. # Remove this line when this test image is regenerated.
  1195. plt.rcParams['pcolormesh.snap'] = False
  1196. fig = plt.figure()
  1197. fig.subplots_adjust(hspace=0.4, top=0.98, bottom=.15)
  1198. base = datetime.datetime(2013, 1, 1)
  1199. x = np.array([base + datetime.timedelta(days=d) for d in range(21)])
  1200. y = np.arange(21)
  1201. z1, z2 = np.meshgrid(np.arange(20), np.arange(20))
  1202. z = z1 * z2
  1203. plt.subplot(221)
  1204. plt.pcolormesh(x[:-1], y[:-1], z[:-1, :-1])
  1205. plt.subplot(222)
  1206. plt.pcolormesh(x, y, z)
  1207. x = np.repeat(x[np.newaxis], 21, axis=0)
  1208. y = np.repeat(y[:, np.newaxis], 21, axis=1)
  1209. plt.subplot(223)
  1210. plt.pcolormesh(x[:-1, :-1], y[:-1, :-1], z[:-1, :-1])
  1211. plt.subplot(224)
  1212. plt.pcolormesh(x, y, z)
  1213. for ax in fig.get_axes():
  1214. for label in ax.get_xticklabels():
  1215. label.set_ha('right')
  1216. label.set_rotation(30)
  1217. @image_comparison(['pcolor_datetime_axis.png'], style='mpl20')
  1218. def test_pcolor_datetime_axis():
  1219. fig = plt.figure()
  1220. fig.subplots_adjust(hspace=0.4, top=0.98, bottom=.15)
  1221. base = datetime.datetime(2013, 1, 1)
  1222. x = np.array([base + datetime.timedelta(days=d) for d in range(21)])
  1223. y = np.arange(21)
  1224. z1, z2 = np.meshgrid(np.arange(20), np.arange(20))
  1225. z = z1 * z2
  1226. plt.subplot(221)
  1227. plt.pcolor(x[:-1], y[:-1], z[:-1, :-1])
  1228. plt.subplot(222)
  1229. plt.pcolor(x, y, z)
  1230. x = np.repeat(x[np.newaxis], 21, axis=0)
  1231. y = np.repeat(y[:, np.newaxis], 21, axis=1)
  1232. plt.subplot(223)
  1233. plt.pcolor(x[:-1, :-1], y[:-1, :-1], z[:-1, :-1])
  1234. plt.subplot(224)
  1235. plt.pcolor(x, y, z)
  1236. for ax in fig.get_axes():
  1237. for label in ax.get_xticklabels():
  1238. label.set_ha('right')
  1239. label.set_rotation(30)
  1240. def test_pcolorargs():
  1241. n = 12
  1242. x = np.linspace(-1.5, 1.5, n)
  1243. y = np.linspace(-1.5, 1.5, n*2)
  1244. X, Y = np.meshgrid(x, y)
  1245. Z = np.hypot(X, Y) / 5
  1246. _, ax = plt.subplots()
  1247. with pytest.raises(TypeError):
  1248. ax.pcolormesh(y, x, Z)
  1249. with pytest.raises(TypeError):
  1250. ax.pcolormesh(X, Y, Z.T)
  1251. with pytest.raises(TypeError):
  1252. ax.pcolormesh(x, y, Z[:-1, :-1], shading="gouraud")
  1253. with pytest.raises(TypeError):
  1254. ax.pcolormesh(X, Y, Z[:-1, :-1], shading="gouraud")
  1255. x[0] = np.nan
  1256. with pytest.raises(ValueError):
  1257. ax.pcolormesh(x, y, Z[:-1, :-1])
  1258. with np.errstate(invalid='ignore'):
  1259. x = np.ma.array(x, mask=(x < 0))
  1260. with pytest.raises(ValueError):
  1261. ax.pcolormesh(x, y, Z[:-1, :-1])
  1262. # If the X or Y coords do not possess monotonicity in their respective
  1263. # directions, a warning indicating a bad grid will be triggered.
  1264. # The case of specifying coordinates by inputting 1D arrays.
  1265. x = [359, 0, 1]
  1266. y = [-10, 10]
  1267. X, Y = np.meshgrid(x, y)
  1268. Z = np.zeros(X.shape)
  1269. with pytest.warns(UserWarning,
  1270. match='are not monotonically increasing or decreasing'):
  1271. ax.pcolormesh(X, Y, Z, shading='auto')
  1272. # The case of specifying coordinates by inputting 2D arrays.
  1273. x = np.linspace(-1, 1, 3)
  1274. y = np.linspace(-1, 1, 3)
  1275. X, Y = np.meshgrid(x, y)
  1276. Z = np.zeros(X.shape)
  1277. np.random.seed(19680801)
  1278. noise_X = np.random.random(X.shape)
  1279. noise_Y = np.random.random(Y.shape)
  1280. with pytest.warns(UserWarning,
  1281. match='are not monotonically increasing or '
  1282. 'decreasing') as record:
  1283. # Small perturbations in coordinates will not disrupt the monotonicity
  1284. # of the X-coords and Y-coords in their respective directions.
  1285. # Therefore, no warnings will be triggered.
  1286. ax.pcolormesh(X+noise_X, Y+noise_Y, Z, shading='auto')
  1287. assert len(record) == 0
  1288. # Large perturbations have disrupted the monotonicity of the X-coords
  1289. # and Y-coords in their respective directions, thus resulting in two
  1290. # bad grid warnings.
  1291. ax.pcolormesh(X+10*noise_X, Y+10*noise_Y, Z, shading='auto')
  1292. assert len(record) == 2
  1293. def test_pcolormesh_underflow_error():
  1294. """
  1295. Test that underflow errors don't crop up in pcolormesh. Probably
  1296. a numpy bug (https://github.com/numpy/numpy/issues/25810).
  1297. """
  1298. with np.errstate(under="raise"):
  1299. x = np.arange(0, 3, 0.1)
  1300. y = np.arange(0, 6, 0.1)
  1301. z = np.random.randn(len(y), len(x))
  1302. fig, ax = plt.subplots()
  1303. ax.pcolormesh(x, y, z)
  1304. def test_pcolorargs_with_read_only():
  1305. x = np.arange(6).reshape(2, 3)
  1306. xmask = np.broadcast_to([False, True, False], x.shape) # read-only array
  1307. assert xmask.flags.writeable is False
  1308. masked_x = np.ma.array(x, mask=xmask)
  1309. plt.pcolormesh(masked_x)
  1310. x = np.linspace(0, 1, 10)
  1311. y = np.linspace(0, 1, 10)
  1312. X, Y = np.meshgrid(x, y)
  1313. Z = np.sin(2 * np.pi * X) * np.cos(2 * np.pi * Y)
  1314. mask = np.zeros(10, dtype=bool)
  1315. mask[-1] = True
  1316. mask = np.broadcast_to(mask, Z.shape)
  1317. assert mask.flags.writeable is False
  1318. masked_Z = np.ma.array(Z, mask=mask)
  1319. plt.pcolormesh(X, Y, masked_Z)
  1320. masked_X = np.ma.array(X, mask=mask)
  1321. masked_Y = np.ma.array(Y, mask=mask)
  1322. plt.pcolor(masked_X, masked_Y, masked_Z)
  1323. @check_figures_equal(extensions=["png"])
  1324. def test_pcolornearest(fig_test, fig_ref):
  1325. ax = fig_test.subplots()
  1326. x = np.arange(0, 10)
  1327. y = np.arange(0, 3)
  1328. np.random.seed(19680801)
  1329. Z = np.random.randn(2, 9)
  1330. ax.pcolormesh(x, y, Z, shading='flat')
  1331. ax = fig_ref.subplots()
  1332. # specify the centers
  1333. x2 = x[:-1] + np.diff(x) / 2
  1334. y2 = y[:-1] + np.diff(y) / 2
  1335. ax.pcolormesh(x2, y2, Z, shading='nearest')
  1336. @check_figures_equal(extensions=["png"])
  1337. def test_pcolornearestunits(fig_test, fig_ref):
  1338. ax = fig_test.subplots()
  1339. x = [datetime.datetime.fromtimestamp(x * 3600) for x in range(10)]
  1340. y = np.arange(0, 3)
  1341. np.random.seed(19680801)
  1342. Z = np.random.randn(2, 9)
  1343. ax.pcolormesh(x, y, Z, shading='flat')
  1344. ax = fig_ref.subplots()
  1345. # specify the centers
  1346. x2 = [datetime.datetime.fromtimestamp((x + 0.5) * 3600) for x in range(9)]
  1347. y2 = y[:-1] + np.diff(y) / 2
  1348. ax.pcolormesh(x2, y2, Z, shading='nearest')
  1349. def test_pcolorflaterror():
  1350. fig, ax = plt.subplots()
  1351. x = np.arange(0, 9)
  1352. y = np.arange(0, 3)
  1353. np.random.seed(19680801)
  1354. Z = np.random.randn(3, 9)
  1355. with pytest.raises(TypeError, match='Dimensions of C'):
  1356. ax.pcolormesh(x, y, Z, shading='flat')
  1357. def test_samesizepcolorflaterror():
  1358. fig, ax = plt.subplots()
  1359. x, y = np.meshgrid(np.arange(5), np.arange(3))
  1360. Z = x + y
  1361. with pytest.raises(TypeError, match=r".*one smaller than X"):
  1362. ax.pcolormesh(x, y, Z, shading='flat')
  1363. @pytest.mark.parametrize('snap', [False, True])
  1364. @check_figures_equal(extensions=["png"])
  1365. def test_pcolorauto(fig_test, fig_ref, snap):
  1366. ax = fig_test.subplots()
  1367. x = np.arange(0, 10)
  1368. y = np.arange(0, 4)
  1369. np.random.seed(19680801)
  1370. Z = np.random.randn(3, 9)
  1371. # this is the same as flat; note that auto is default
  1372. ax.pcolormesh(x, y, Z, snap=snap)
  1373. ax = fig_ref.subplots()
  1374. # specify the centers
  1375. x2 = x[:-1] + np.diff(x) / 2
  1376. y2 = y[:-1] + np.diff(y) / 2
  1377. # this is same as nearest:
  1378. ax.pcolormesh(x2, y2, Z, snap=snap)
  1379. @image_comparison(['canonical'],
  1380. tol=0 if platform.machine() == 'x86_64' else 0.02)
  1381. def test_canonical():
  1382. fig, ax = plt.subplots()
  1383. ax.plot([1, 2, 3])
  1384. @image_comparison(['arc_angles.png'], remove_text=True, style='default')
  1385. def test_arc_angles():
  1386. # Ellipse parameters
  1387. w = 2
  1388. h = 1
  1389. centre = (0.2, 0.5)
  1390. scale = 2
  1391. fig, axs = plt.subplots(3, 3)
  1392. for i, ax in enumerate(axs.flat):
  1393. theta2 = i * 360 / 9
  1394. theta1 = theta2 - 45
  1395. ax.add_patch(mpatches.Ellipse(centre, w, h, alpha=0.3))
  1396. ax.add_patch(mpatches.Arc(centre, w, h, theta1=theta1, theta2=theta2))
  1397. # Straight lines intersecting start and end of arc
  1398. ax.plot([scale * np.cos(np.deg2rad(theta1)) + centre[0],
  1399. centre[0],
  1400. scale * np.cos(np.deg2rad(theta2)) + centre[0]],
  1401. [scale * np.sin(np.deg2rad(theta1)) + centre[1],
  1402. centre[1],
  1403. scale * np.sin(np.deg2rad(theta2)) + centre[1]])
  1404. ax.set_xlim(-scale, scale)
  1405. ax.set_ylim(-scale, scale)
  1406. # This looks the same, but it triggers a different code path when it
  1407. # gets large enough.
  1408. w *= 10
  1409. h *= 10
  1410. centre = (centre[0] * 10, centre[1] * 10)
  1411. scale *= 10
  1412. @image_comparison(['arc_ellipse'], remove_text=True)
  1413. def test_arc_ellipse():
  1414. xcenter, ycenter = 0.38, 0.52
  1415. width, height = 1e-1, 3e-1
  1416. angle = -30
  1417. theta = np.deg2rad(np.arange(360))
  1418. x = width / 2. * np.cos(theta)
  1419. y = height / 2. * np.sin(theta)
  1420. rtheta = np.deg2rad(angle)
  1421. R = np.array([
  1422. [np.cos(rtheta), -np.sin(rtheta)],
  1423. [np.sin(rtheta), np.cos(rtheta)]])
  1424. x, y = np.dot(R, [x, y])
  1425. x += xcenter
  1426. y += ycenter
  1427. fig = plt.figure()
  1428. ax = fig.add_subplot(211, aspect='auto')
  1429. ax.fill(x, y, alpha=0.2, facecolor='yellow', edgecolor='yellow',
  1430. linewidth=1, zorder=1)
  1431. e1 = mpatches.Arc((xcenter, ycenter), width, height,
  1432. angle=angle, linewidth=2, fill=False, zorder=2)
  1433. ax.add_patch(e1)
  1434. ax = fig.add_subplot(212, aspect='equal')
  1435. ax.fill(x, y, alpha=0.2, facecolor='green', edgecolor='green', zorder=1)
  1436. e2 = mpatches.Arc((xcenter, ycenter), width, height,
  1437. angle=angle, linewidth=2, fill=False, zorder=2)
  1438. ax.add_patch(e2)
  1439. def test_marker_as_markerstyle():
  1440. fix, ax = plt.subplots()
  1441. m = mmarkers.MarkerStyle('o')
  1442. ax.plot([1, 2, 3], [3, 2, 1], marker=m)
  1443. ax.scatter([1, 2, 3], [4, 3, 2], marker=m)
  1444. ax.errorbar([1, 2, 3], [5, 4, 3], marker=m)
  1445. @image_comparison(['markevery.png'], remove_text=True)
  1446. def test_markevery():
  1447. x = np.linspace(0, 10, 100)
  1448. y = np.sin(x) * np.sqrt(x/10 + 0.5)
  1449. # check marker only plot
  1450. fig, ax = plt.subplots()
  1451. ax.plot(x, y, 'o', label='default')
  1452. ax.plot(x, y, 'd', markevery=None, label='mark all')
  1453. ax.plot(x, y, 's', markevery=10, label='mark every 10')
  1454. ax.plot(x, y, '+', markevery=(5, 20), label='mark every 5 starting at 10')
  1455. ax.legend()
  1456. @image_comparison(['markevery_line.png'], remove_text=True, tol=0.005)
  1457. def test_markevery_line():
  1458. # TODO: a slight change in rendering between Inkscape versions may explain
  1459. # why one had to introduce a small non-zero tolerance for the SVG test
  1460. # to pass. One may try to remove this hack once Travis' Inkscape version
  1461. # is modern enough. FWIW, no failure with 0.92.3 on my computer (#11358).
  1462. x = np.linspace(0, 10, 100)
  1463. y = np.sin(x) * np.sqrt(x/10 + 0.5)
  1464. # check line/marker combos
  1465. fig, ax = plt.subplots()
  1466. ax.plot(x, y, '-o', label='default')
  1467. ax.plot(x, y, '-d', markevery=None, label='mark all')
  1468. ax.plot(x, y, '-s', markevery=10, label='mark every 10')
  1469. ax.plot(x, y, '-+', markevery=(5, 20), label='mark every 5 starting at 10')
  1470. ax.legend()
  1471. @image_comparison(['markevery_linear_scales.png'], remove_text=True, tol=0.001)
  1472. def test_markevery_linear_scales():
  1473. cases = [None,
  1474. 8,
  1475. (30, 8),
  1476. [16, 24, 30], [0, -1],
  1477. slice(100, 200, 3),
  1478. 0.1, 0.3, 1.5,
  1479. (0.0, 0.1), (0.45, 0.1)]
  1480. cols = 3
  1481. gs = matplotlib.gridspec.GridSpec(len(cases) // cols + 1, cols)
  1482. delta = 0.11
  1483. x = np.linspace(0, 10 - 2 * delta, 200) + delta
  1484. y = np.sin(x) + 1.0 + delta
  1485. for i, case in enumerate(cases):
  1486. row = (i // cols)
  1487. col = i % cols
  1488. plt.subplot(gs[row, col])
  1489. plt.title('markevery=%s' % str(case))
  1490. plt.plot(x, y, 'o', ls='-', ms=4, markevery=case)
  1491. @image_comparison(['markevery_linear_scales_zoomed.png'], remove_text=True)
  1492. def test_markevery_linear_scales_zoomed():
  1493. cases = [None,
  1494. 8,
  1495. (30, 8),
  1496. [16, 24, 30], [0, -1],
  1497. slice(100, 200, 3),
  1498. 0.1, 0.3, 1.5,
  1499. (0.0, 0.1), (0.45, 0.1)]
  1500. cols = 3
  1501. gs = matplotlib.gridspec.GridSpec(len(cases) // cols + 1, cols)
  1502. delta = 0.11
  1503. x = np.linspace(0, 10 - 2 * delta, 200) + delta
  1504. y = np.sin(x) + 1.0 + delta
  1505. for i, case in enumerate(cases):
  1506. row = (i // cols)
  1507. col = i % cols
  1508. plt.subplot(gs[row, col])
  1509. plt.title('markevery=%s' % str(case))
  1510. plt.plot(x, y, 'o', ls='-', ms=4, markevery=case)
  1511. plt.xlim((6, 6.7))
  1512. plt.ylim((1.1, 1.7))
  1513. @image_comparison(['markevery_log_scales.png'], remove_text=True)
  1514. def test_markevery_log_scales():
  1515. cases = [None,
  1516. 8,
  1517. (30, 8),
  1518. [16, 24, 30], [0, -1],
  1519. slice(100, 200, 3),
  1520. 0.1, 0.3, 1.5,
  1521. (0.0, 0.1), (0.45, 0.1)]
  1522. cols = 3
  1523. gs = matplotlib.gridspec.GridSpec(len(cases) // cols + 1, cols)
  1524. delta = 0.11
  1525. x = np.linspace(0, 10 - 2 * delta, 200) + delta
  1526. y = np.sin(x) + 1.0 + delta
  1527. for i, case in enumerate(cases):
  1528. row = (i // cols)
  1529. col = i % cols
  1530. plt.subplot(gs[row, col])
  1531. plt.title('markevery=%s' % str(case))
  1532. plt.xscale('log')
  1533. plt.yscale('log')
  1534. plt.plot(x, y, 'o', ls='-', ms=4, markevery=case)
  1535. @image_comparison(['markevery_polar.png'], style='default', remove_text=True)
  1536. def test_markevery_polar():
  1537. cases = [None,
  1538. 8,
  1539. (30, 8),
  1540. [16, 24, 30], [0, -1],
  1541. slice(100, 200, 3),
  1542. 0.1, 0.3, 1.5,
  1543. (0.0, 0.1), (0.45, 0.1)]
  1544. cols = 3
  1545. gs = matplotlib.gridspec.GridSpec(len(cases) // cols + 1, cols)
  1546. r = np.linspace(0, 3.0, 200)
  1547. theta = 2 * np.pi * r
  1548. for i, case in enumerate(cases):
  1549. row = (i // cols)
  1550. col = i % cols
  1551. plt.subplot(gs[row, col], polar=True)
  1552. plt.title('markevery=%s' % str(case))
  1553. plt.plot(theta, r, 'o', ls='-', ms=4, markevery=case)
  1554. @image_comparison(['markevery_linear_scales_nans.png'], remove_text=True)
  1555. def test_markevery_linear_scales_nans():
  1556. cases = [None,
  1557. 8,
  1558. (30, 8),
  1559. [16, 24, 30], [0, -1],
  1560. slice(100, 200, 3),
  1561. 0.1, 0.3, 1.5,
  1562. (0.0, 0.1), (0.45, 0.1)]
  1563. cols = 3
  1564. gs = matplotlib.gridspec.GridSpec(len(cases) // cols + 1, cols)
  1565. delta = 0.11
  1566. x = np.linspace(0, 10 - 2 * delta, 200) + delta
  1567. y = np.sin(x) + 1.0 + delta
  1568. y[:10] = y[-20:] = y[50:70] = np.nan
  1569. for i, case in enumerate(cases):
  1570. row = (i // cols)
  1571. col = i % cols
  1572. plt.subplot(gs[row, col])
  1573. plt.title('markevery=%s' % str(case))
  1574. plt.plot(x, y, 'o', ls='-', ms=4, markevery=case)
  1575. @image_comparison(['marker_edges'], remove_text=True)
  1576. def test_marker_edges():
  1577. x = np.linspace(0, 1, 10)
  1578. fig, ax = plt.subplots()
  1579. ax.plot(x, np.sin(x), 'y.', ms=30.0, mew=0, mec='r')
  1580. ax.plot(x+0.1, np.sin(x), 'y.', ms=30.0, mew=1, mec='r')
  1581. ax.plot(x+0.2, np.sin(x), 'y.', ms=30.0, mew=2, mec='b')
  1582. @image_comparison(['bar_tick_label_single.png', 'bar_tick_label_single.png'])
  1583. def test_bar_tick_label_single():
  1584. # From 2516: plot bar with array of string labels for x axis
  1585. ax = plt.gca()
  1586. ax.bar(0, 1, align='edge', tick_label='0')
  1587. # Reuse testcase from above for a labeled data test
  1588. data = {"a": 0, "b": 1}
  1589. fig, ax = plt.subplots()
  1590. ax = plt.gca()
  1591. ax.bar("a", "b", align='edge', tick_label='0', data=data)
  1592. def test_nan_bar_values():
  1593. fig, ax = plt.subplots()
  1594. ax.bar([0, 1], [np.nan, 4])
  1595. def test_bar_ticklabel_fail():
  1596. fig, ax = plt.subplots()
  1597. ax.bar([], [])
  1598. @image_comparison(['bar_tick_label_multiple.png'])
  1599. def test_bar_tick_label_multiple():
  1600. # From 2516: plot bar with array of string labels for x axis
  1601. ax = plt.gca()
  1602. ax.bar([1, 2.5], [1, 2], width=[0.2, 0.5], tick_label=['a', 'b'],
  1603. align='center')
  1604. @image_comparison(['bar_tick_label_multiple_old_label_alignment.png'])
  1605. def test_bar_tick_label_multiple_old_alignment():
  1606. # Test that the alignment for class is backward compatible
  1607. matplotlib.rcParams["ytick.alignment"] = "center"
  1608. ax = plt.gca()
  1609. ax.bar([1, 2.5], [1, 2], width=[0.2, 0.5], tick_label=['a', 'b'],
  1610. align='center')
  1611. @check_figures_equal(extensions=["png"])
  1612. def test_bar_decimal_center(fig_test, fig_ref):
  1613. ax = fig_test.subplots()
  1614. x0 = [1.5, 8.4, 5.3, 4.2]
  1615. y0 = [1.1, 2.2, 3.3, 4.4]
  1616. x = [Decimal(x) for x in x0]
  1617. y = [Decimal(y) for y in y0]
  1618. # Test image - vertical, align-center bar chart with Decimal() input
  1619. ax.bar(x, y, align='center')
  1620. # Reference image
  1621. ax = fig_ref.subplots()
  1622. ax.bar(x0, y0, align='center')
  1623. @check_figures_equal(extensions=["png"])
  1624. def test_barh_decimal_center(fig_test, fig_ref):
  1625. ax = fig_test.subplots()
  1626. x0 = [1.5, 8.4, 5.3, 4.2]
  1627. y0 = [1.1, 2.2, 3.3, 4.4]
  1628. x = [Decimal(x) for x in x0]
  1629. y = [Decimal(y) for y in y0]
  1630. # Test image - horizontal, align-center bar chart with Decimal() input
  1631. ax.barh(x, y, height=[0.5, 0.5, 1, 1], align='center')
  1632. # Reference image
  1633. ax = fig_ref.subplots()
  1634. ax.barh(x0, y0, height=[0.5, 0.5, 1, 1], align='center')
  1635. @check_figures_equal(extensions=["png"])
  1636. def test_bar_decimal_width(fig_test, fig_ref):
  1637. x = [1.5, 8.4, 5.3, 4.2]
  1638. y = [1.1, 2.2, 3.3, 4.4]
  1639. w0 = [0.7, 1.45, 1, 2]
  1640. w = [Decimal(i) for i in w0]
  1641. # Test image - vertical bar chart with Decimal() width
  1642. ax = fig_test.subplots()
  1643. ax.bar(x, y, width=w, align='center')
  1644. # Reference image
  1645. ax = fig_ref.subplots()
  1646. ax.bar(x, y, width=w0, align='center')
  1647. @check_figures_equal(extensions=["png"])
  1648. def test_barh_decimal_height(fig_test, fig_ref):
  1649. x = [1.5, 8.4, 5.3, 4.2]
  1650. y = [1.1, 2.2, 3.3, 4.4]
  1651. h0 = [0.7, 1.45, 1, 2]
  1652. h = [Decimal(i) for i in h0]
  1653. # Test image - horizontal bar chart with Decimal() height
  1654. ax = fig_test.subplots()
  1655. ax.barh(x, y, height=h, align='center')
  1656. # Reference image
  1657. ax = fig_ref.subplots()
  1658. ax.barh(x, y, height=h0, align='center')
  1659. def test_bar_color_none_alpha():
  1660. ax = plt.gca()
  1661. rects = ax.bar([1, 2], [2, 4], alpha=0.3, color='none', edgecolor='r')
  1662. for rect in rects:
  1663. assert rect.get_facecolor() == (0, 0, 0, 0)
  1664. assert rect.get_edgecolor() == (1, 0, 0, 0.3)
  1665. def test_bar_edgecolor_none_alpha():
  1666. ax = plt.gca()
  1667. rects = ax.bar([1, 2], [2, 4], alpha=0.3, color='r', edgecolor='none')
  1668. for rect in rects:
  1669. assert rect.get_facecolor() == (1, 0, 0, 0.3)
  1670. assert rect.get_edgecolor() == (0, 0, 0, 0)
  1671. @image_comparison(['barh_tick_label.png'])
  1672. def test_barh_tick_label():
  1673. # From 2516: plot barh with array of string labels for y axis
  1674. ax = plt.gca()
  1675. ax.barh([1, 2.5], [1, 2], height=[0.2, 0.5], tick_label=['a', 'b'],
  1676. align='center')
  1677. def test_bar_timedelta():
  1678. """Smoketest that bar can handle width and height in delta units."""
  1679. fig, ax = plt.subplots()
  1680. ax.bar(datetime.datetime(2018, 1, 1), 1.,
  1681. width=datetime.timedelta(hours=3))
  1682. ax.bar(datetime.datetime(2018, 1, 1), 1.,
  1683. xerr=datetime.timedelta(hours=2),
  1684. width=datetime.timedelta(hours=3))
  1685. fig, ax = plt.subplots()
  1686. ax.barh(datetime.datetime(2018, 1, 1), 1,
  1687. height=datetime.timedelta(hours=3))
  1688. ax.barh(datetime.datetime(2018, 1, 1), 1,
  1689. height=datetime.timedelta(hours=3),
  1690. yerr=datetime.timedelta(hours=2))
  1691. fig, ax = plt.subplots()
  1692. ax.barh([datetime.datetime(2018, 1, 1), datetime.datetime(2018, 1, 1)],
  1693. np.array([1, 1.5]),
  1694. height=datetime.timedelta(hours=3))
  1695. ax.barh([datetime.datetime(2018, 1, 1), datetime.datetime(2018, 1, 1)],
  1696. np.array([1, 1.5]),
  1697. height=[datetime.timedelta(hours=t) for t in [1, 2]])
  1698. ax.broken_barh([(datetime.datetime(2018, 1, 1),
  1699. datetime.timedelta(hours=1))],
  1700. (10, 20))
  1701. def test_bar_datetime_start():
  1702. """test that tickers are correct for datetimes"""
  1703. start = np.array([np.datetime64('2012-01-01'), np.datetime64('2012-02-01'),
  1704. np.datetime64('2012-01-15')])
  1705. stop = np.array([np.datetime64('2012-02-07'), np.datetime64('2012-02-13'),
  1706. np.datetime64('2012-02-12')])
  1707. fig, ax = plt.subplots()
  1708. ax.bar([0, 1, 3], height=stop-start, bottom=start)
  1709. assert isinstance(ax.yaxis.get_major_formatter(), mdates.AutoDateFormatter)
  1710. fig, ax = plt.subplots()
  1711. ax.barh([0, 1, 3], width=stop-start, left=start)
  1712. assert isinstance(ax.xaxis.get_major_formatter(), mdates.AutoDateFormatter)
  1713. def test_boxplot_dates_pandas(pd):
  1714. # smoke test for boxplot and dates in pandas
  1715. data = np.random.rand(5, 2)
  1716. years = pd.date_range('1/1/2000',
  1717. periods=2, freq=pd.DateOffset(years=1)).year
  1718. plt.figure()
  1719. plt.boxplot(data, positions=years)
  1720. def test_boxplot_capwidths():
  1721. data = np.random.rand(5, 3)
  1722. fig, axs = plt.subplots(9)
  1723. axs[0].boxplot(data, capwidths=[0.3, 0.2, 0.1], widths=[0.1, 0.2, 0.3])
  1724. axs[1].boxplot(data, capwidths=[0.3, 0.2, 0.1], widths=0.2)
  1725. axs[2].boxplot(data, capwidths=[0.3, 0.2, 0.1])
  1726. axs[3].boxplot(data, capwidths=0.5, widths=[0.1, 0.2, 0.3])
  1727. axs[4].boxplot(data, capwidths=0.5, widths=0.2)
  1728. axs[5].boxplot(data, capwidths=0.5)
  1729. axs[6].boxplot(data, widths=[0.1, 0.2, 0.3])
  1730. axs[7].boxplot(data, widths=0.2)
  1731. axs[8].boxplot(data)
  1732. def test_pcolor_regression(pd):
  1733. from pandas.plotting import (
  1734. register_matplotlib_converters,
  1735. deregister_matplotlib_converters,
  1736. )
  1737. fig = plt.figure()
  1738. ax = fig.add_subplot(111)
  1739. times = [datetime.datetime(2021, 1, 1)]
  1740. while len(times) < 7:
  1741. times.append(times[-1] + datetime.timedelta(seconds=120))
  1742. y_vals = np.arange(5)
  1743. time_axis, y_axis = np.meshgrid(times, y_vals)
  1744. shape = (len(y_vals) - 1, len(times) - 1)
  1745. z_data = np.arange(shape[0] * shape[1])
  1746. z_data.shape = shape
  1747. try:
  1748. register_matplotlib_converters()
  1749. im = ax.pcolormesh(time_axis, y_axis, z_data)
  1750. # make sure this does not raise!
  1751. fig.canvas.draw()
  1752. finally:
  1753. deregister_matplotlib_converters()
  1754. def test_bar_pandas(pd):
  1755. # Smoke test for pandas
  1756. df = pd.DataFrame(
  1757. {'year': [2018, 2018, 2018],
  1758. 'month': [1, 1, 1],
  1759. 'day': [1, 2, 3],
  1760. 'value': [1, 2, 3]})
  1761. df['date'] = pd.to_datetime(df[['year', 'month', 'day']])
  1762. monthly = df[['date', 'value']].groupby(['date']).sum()
  1763. dates = monthly.index
  1764. forecast = monthly['value']
  1765. baseline = monthly['value']
  1766. fig, ax = plt.subplots()
  1767. ax.bar(dates, forecast, width=10, align='center')
  1768. ax.plot(dates, baseline, color='orange', lw=4)
  1769. def test_bar_pandas_indexed(pd):
  1770. # Smoke test for indexed pandas
  1771. df = pd.DataFrame({"x": [1., 2., 3.], "width": [.2, .4, .6]},
  1772. index=[1, 2, 3])
  1773. fig, ax = plt.subplots()
  1774. ax.bar(df.x, 1., width=df.width)
  1775. @mpl.style.context('default')
  1776. @check_figures_equal(extensions=['png'])
  1777. def test_bar_hatches(fig_test, fig_ref):
  1778. ax_test = fig_test.subplots()
  1779. ax_ref = fig_ref.subplots()
  1780. x = [1, 2]
  1781. y = [2, 3]
  1782. hatches = ['x', 'o']
  1783. for i in range(2):
  1784. ax_ref.bar(x[i], y[i], color='C0', hatch=hatches[i])
  1785. ax_test.bar(x, y, hatch=hatches)
  1786. @pytest.mark.parametrize(
  1787. ("x", "width", "label", "expected_labels", "container_label"),
  1788. [
  1789. ("x", 1, "x", ["_nolegend_"], "x"),
  1790. (["a", "b", "c"], [10, 20, 15], ["A", "B", "C"],
  1791. ["A", "B", "C"], "_nolegend_"),
  1792. (["a", "b", "c"], [10, 20, 15], ["R", "Y", "_nolegend_"],
  1793. ["R", "Y", "_nolegend_"], "_nolegend_"),
  1794. (["a", "b", "c"], [10, 20, 15], "bars",
  1795. ["_nolegend_", "_nolegend_", "_nolegend_"], "bars"),
  1796. ]
  1797. )
  1798. def test_bar_labels(x, width, label, expected_labels, container_label):
  1799. _, ax = plt.subplots()
  1800. bar_container = ax.bar(x, width, label=label)
  1801. bar_labels = [bar.get_label() for bar in bar_container]
  1802. assert expected_labels == bar_labels
  1803. assert bar_container.get_label() == container_label
  1804. def test_bar_labels_length():
  1805. _, ax = plt.subplots()
  1806. with pytest.raises(ValueError):
  1807. ax.bar(["x", "y"], [1, 2], label=["X", "Y", "Z"])
  1808. _, ax = plt.subplots()
  1809. with pytest.raises(ValueError):
  1810. ax.bar(["x", "y"], [1, 2], label=["X"])
  1811. def test_pandas_minimal_plot(pd):
  1812. # smoke test that series and index objects do not warn
  1813. for x in [pd.Series([1, 2], dtype="float64"),
  1814. pd.Series([1, 2], dtype="Float64")]:
  1815. plt.plot(x, x)
  1816. plt.plot(x.index, x)
  1817. plt.plot(x)
  1818. plt.plot(x.index)
  1819. df = pd.DataFrame({'col': [1, 2, 3]})
  1820. plt.plot(df)
  1821. plt.plot(df, df)
  1822. @image_comparison(['hist_log.png'], remove_text=True)
  1823. def test_hist_log():
  1824. data0 = np.linspace(0, 1, 200)**3
  1825. data = np.concatenate([1 - data0, 1 + data0])
  1826. fig, ax = plt.subplots()
  1827. ax.hist(data, fill=False, log=True)
  1828. @check_figures_equal(extensions=["png"])
  1829. def test_hist_log_2(fig_test, fig_ref):
  1830. axs_test = fig_test.subplots(2, 3)
  1831. axs_ref = fig_ref.subplots(2, 3)
  1832. for i, histtype in enumerate(["bar", "step", "stepfilled"]):
  1833. # Set log scale, then call hist().
  1834. axs_test[0, i].set_yscale("log")
  1835. axs_test[0, i].hist(1, 1, histtype=histtype)
  1836. # Call hist(), then set log scale.
  1837. axs_test[1, i].hist(1, 1, histtype=histtype)
  1838. axs_test[1, i].set_yscale("log")
  1839. # Use hist(..., log=True).
  1840. for ax in axs_ref[:, i]:
  1841. ax.hist(1, 1, log=True, histtype=histtype)
  1842. def test_hist_log_barstacked():
  1843. fig, axs = plt.subplots(2)
  1844. axs[0].hist([[0], [0, 1]], 2, histtype="barstacked")
  1845. axs[0].set_yscale("log")
  1846. axs[1].hist([0, 0, 1], 2, histtype="barstacked")
  1847. axs[1].set_yscale("log")
  1848. fig.canvas.draw()
  1849. assert axs[0].get_ylim() == axs[1].get_ylim()
  1850. @image_comparison(['hist_bar_empty.png'], remove_text=True)
  1851. def test_hist_bar_empty():
  1852. # From #3886: creating hist from empty dataset raises ValueError
  1853. ax = plt.gca()
  1854. ax.hist([], histtype='bar')
  1855. def test_hist_float16():
  1856. np.random.seed(19680801)
  1857. values = np.clip(
  1858. np.random.normal(0.5, 0.3, size=1000), 0, 1).astype(np.float16)
  1859. h = plt.hist(values, bins=3, alpha=0.5)
  1860. bc = h[2]
  1861. # Check that there are no overlapping rectangles
  1862. for r in range(1, len(bc)):
  1863. rleft = bc[r-1].get_corners()
  1864. rright = bc[r].get_corners()
  1865. # right hand position of left rectangle <=
  1866. # left hand position of right rectangle
  1867. assert rleft[1][0] <= rright[0][0]
  1868. @image_comparison(['hist_step_empty.png'], remove_text=True)
  1869. def test_hist_step_empty():
  1870. # From #3886: creating hist from empty dataset raises ValueError
  1871. ax = plt.gca()
  1872. ax.hist([], histtype='step')
  1873. @image_comparison(['hist_step_filled.png'], remove_text=True)
  1874. def test_hist_step_filled():
  1875. np.random.seed(0)
  1876. x = np.random.randn(1000, 3)
  1877. n_bins = 10
  1878. kwargs = [{'fill': True}, {'fill': False}, {'fill': None}, {}]*2
  1879. types = ['step']*4+['stepfilled']*4
  1880. fig, axs = plt.subplots(nrows=2, ncols=4)
  1881. for kg, _type, ax in zip(kwargs, types, axs.flat):
  1882. ax.hist(x, n_bins, histtype=_type, stacked=True, **kg)
  1883. ax.set_title(f'{kg}/{_type}')
  1884. ax.set_ylim(bottom=-50)
  1885. patches = axs[0, 0].patches
  1886. assert all(p.get_facecolor() == p.get_edgecolor() for p in patches)
  1887. @image_comparison(['hist_density.png'])
  1888. def test_hist_density():
  1889. np.random.seed(19680801)
  1890. data = np.random.standard_normal(2000)
  1891. fig, ax = plt.subplots()
  1892. ax.hist(data, density=True)
  1893. def test_hist_unequal_bins_density():
  1894. # Test correct behavior of normalized histogram with unequal bins
  1895. # https://github.com/matplotlib/matplotlib/issues/9557
  1896. rng = np.random.RandomState(57483)
  1897. t = rng.randn(100)
  1898. bins = [-3, -1, -0.5, 0, 1, 5]
  1899. mpl_heights, _, _ = plt.hist(t, bins=bins, density=True)
  1900. np_heights, _ = np.histogram(t, bins=bins, density=True)
  1901. assert_allclose(mpl_heights, np_heights)
  1902. def test_hist_datetime_datasets():
  1903. data = [[datetime.datetime(2017, 1, 1), datetime.datetime(2017, 1, 1)],
  1904. [datetime.datetime(2017, 1, 1), datetime.datetime(2017, 1, 2)]]
  1905. fig, ax = plt.subplots()
  1906. ax.hist(data, stacked=True)
  1907. ax.hist(data, stacked=False)
  1908. @pytest.mark.parametrize("bins_preprocess",
  1909. [mpl.dates.date2num,
  1910. lambda bins: bins,
  1911. lambda bins: np.asarray(bins, 'datetime64')],
  1912. ids=['date2num', 'datetime.datetime',
  1913. 'np.datetime64'])
  1914. def test_hist_datetime_datasets_bins(bins_preprocess):
  1915. data = [[datetime.datetime(2019, 1, 5), datetime.datetime(2019, 1, 11),
  1916. datetime.datetime(2019, 2, 1), datetime.datetime(2019, 3, 1)],
  1917. [datetime.datetime(2019, 1, 11), datetime.datetime(2019, 2, 5),
  1918. datetime.datetime(2019, 2, 18), datetime.datetime(2019, 3, 1)]]
  1919. date_edges = [datetime.datetime(2019, 1, 1), datetime.datetime(2019, 2, 1),
  1920. datetime.datetime(2019, 3, 1)]
  1921. fig, ax = plt.subplots()
  1922. _, bins, _ = ax.hist(data, bins=bins_preprocess(date_edges), stacked=True)
  1923. np.testing.assert_allclose(bins, mpl.dates.date2num(date_edges))
  1924. _, bins, _ = ax.hist(data, bins=bins_preprocess(date_edges), stacked=False)
  1925. np.testing.assert_allclose(bins, mpl.dates.date2num(date_edges))
  1926. @pytest.mark.parametrize('data, expected_number_of_hists',
  1927. [([], 1),
  1928. ([[]], 1),
  1929. ([[], []], 2)])
  1930. def test_hist_with_empty_input(data, expected_number_of_hists):
  1931. hists, _, _ = plt.hist(data)
  1932. hists = np.asarray(hists)
  1933. if hists.ndim == 1:
  1934. assert 1 == expected_number_of_hists
  1935. else:
  1936. assert hists.shape[0] == expected_number_of_hists
  1937. @pytest.mark.parametrize("histtype, zorder",
  1938. [("bar", mpl.patches.Patch.zorder),
  1939. ("step", mpl.lines.Line2D.zorder),
  1940. ("stepfilled", mpl.patches.Patch.zorder)])
  1941. def test_hist_zorder(histtype, zorder):
  1942. ax = plt.figure().add_subplot()
  1943. ax.hist([1, 2], histtype=histtype)
  1944. assert ax.patches
  1945. for patch in ax.patches:
  1946. assert patch.get_zorder() == zorder
  1947. def test_stairs_no_baseline_fill_warns():
  1948. fig, ax = plt.subplots()
  1949. with pytest.warns(UserWarning, match="baseline=None and fill=True"):
  1950. ax.stairs(
  1951. [4, 5, 1, 0, 2],
  1952. [1, 2, 3, 4, 5, 6],
  1953. facecolor="blue",
  1954. baseline=None,
  1955. fill=True
  1956. )
  1957. @check_figures_equal(extensions=['png'])
  1958. def test_stairs(fig_test, fig_ref):
  1959. import matplotlib.lines as mlines
  1960. y = np.array([6, 14, 32, 37, 48, 32, 21, 4]) # hist
  1961. x = np.array([1., 2., 3., 4., 5., 6., 7., 8., 9.]) # bins
  1962. test_axes = fig_test.subplots(3, 2).flatten()
  1963. test_axes[0].stairs(y, x, baseline=None)
  1964. test_axes[1].stairs(y, x, baseline=None, orientation='horizontal')
  1965. test_axes[2].stairs(y, x)
  1966. test_axes[3].stairs(y, x, orientation='horizontal')
  1967. test_axes[4].stairs(y, x)
  1968. test_axes[4].semilogy()
  1969. test_axes[5].stairs(y, x, orientation='horizontal')
  1970. test_axes[5].semilogx()
  1971. # defaults of `PathPatch` to be used for all following Line2D
  1972. style = {'solid_joinstyle': 'miter', 'solid_capstyle': 'butt'}
  1973. ref_axes = fig_ref.subplots(3, 2).flatten()
  1974. ref_axes[0].plot(x, np.append(y, y[-1]), drawstyle='steps-post', **style)
  1975. ref_axes[1].plot(np.append(y[0], y), x, drawstyle='steps-post', **style)
  1976. ref_axes[2].plot(x, np.append(y, y[-1]), drawstyle='steps-post', **style)
  1977. ref_axes[2].add_line(mlines.Line2D([x[0], x[0]], [0, y[0]], **style))
  1978. ref_axes[2].add_line(mlines.Line2D([x[-1], x[-1]], [0, y[-1]], **style))
  1979. ref_axes[2].set_ylim(0, None)
  1980. ref_axes[3].plot(np.append(y[0], y), x, drawstyle='steps-post', **style)
  1981. ref_axes[3].add_line(mlines.Line2D([0, y[0]], [x[0], x[0]], **style))
  1982. ref_axes[3].add_line(mlines.Line2D([0, y[-1]], [x[-1], x[-1]], **style))
  1983. ref_axes[3].set_xlim(0, None)
  1984. ref_axes[4].plot(x, np.append(y, y[-1]), drawstyle='steps-post', **style)
  1985. ref_axes[4].add_line(mlines.Line2D([x[0], x[0]], [0, y[0]], **style))
  1986. ref_axes[4].add_line(mlines.Line2D([x[-1], x[-1]], [0, y[-1]], **style))
  1987. ref_axes[4].semilogy()
  1988. ref_axes[5].plot(np.append(y[0], y), x, drawstyle='steps-post', **style)
  1989. ref_axes[5].add_line(mlines.Line2D([0, y[0]], [x[0], x[0]], **style))
  1990. ref_axes[5].add_line(mlines.Line2D([0, y[-1]], [x[-1], x[-1]], **style))
  1991. ref_axes[5].semilogx()
  1992. @check_figures_equal(extensions=['png'])
  1993. def test_stairs_fill(fig_test, fig_ref):
  1994. h, bins = [1, 2, 3, 4, 2], [0, 1, 2, 3, 4, 5]
  1995. bs = -2
  1996. # Test
  1997. test_axes = fig_test.subplots(2, 2).flatten()
  1998. test_axes[0].stairs(h, bins, fill=True)
  1999. test_axes[1].stairs(h, bins, orientation='horizontal', fill=True)
  2000. test_axes[2].stairs(h, bins, baseline=bs, fill=True)
  2001. test_axes[3].stairs(h, bins, baseline=bs, orientation='horizontal',
  2002. fill=True)
  2003. # # Ref
  2004. ref_axes = fig_ref.subplots(2, 2).flatten()
  2005. ref_axes[0].fill_between(bins, np.append(h, h[-1]), step='post', lw=0)
  2006. ref_axes[0].set_ylim(0, None)
  2007. ref_axes[1].fill_betweenx(bins, np.append(h, h[-1]), step='post', lw=0)
  2008. ref_axes[1].set_xlim(0, None)
  2009. ref_axes[2].fill_between(bins, np.append(h, h[-1]),
  2010. np.ones(len(h)+1)*bs, step='post', lw=0)
  2011. ref_axes[2].set_ylim(bs, None)
  2012. ref_axes[3].fill_betweenx(bins, np.append(h, h[-1]),
  2013. np.ones(len(h)+1)*bs, step='post', lw=0)
  2014. ref_axes[3].set_xlim(bs, None)
  2015. @check_figures_equal(extensions=['png'])
  2016. def test_stairs_update(fig_test, fig_ref):
  2017. # fixed ylim because stairs() does autoscale, but updating data does not
  2018. ylim = -3, 4
  2019. # Test
  2020. test_ax = fig_test.add_subplot()
  2021. h = test_ax.stairs([1, 2, 3])
  2022. test_ax.set_ylim(ylim)
  2023. h.set_data([3, 2, 1])
  2024. h.set_data(edges=np.arange(4)+2)
  2025. h.set_data([1, 2, 1], np.arange(4)/2)
  2026. h.set_data([1, 2, 3])
  2027. h.set_data(None, np.arange(4))
  2028. assert np.allclose(h.get_data()[0], np.arange(1, 4))
  2029. assert np.allclose(h.get_data()[1], np.arange(4))
  2030. h.set_data(baseline=-2)
  2031. assert h.get_data().baseline == -2
  2032. # Ref
  2033. ref_ax = fig_ref.add_subplot()
  2034. h = ref_ax.stairs([1, 2, 3], baseline=-2)
  2035. ref_ax.set_ylim(ylim)
  2036. @check_figures_equal(extensions=['png'])
  2037. def test_stairs_baseline_None(fig_test, fig_ref):
  2038. x = np.array([0, 2, 3, 5, 10])
  2039. y = np.array([1.148, 1.231, 1.248, 1.25])
  2040. test_axes = fig_test.add_subplot()
  2041. test_axes.stairs(y, x, baseline=None)
  2042. style = {'solid_joinstyle': 'miter', 'solid_capstyle': 'butt'}
  2043. ref_axes = fig_ref.add_subplot()
  2044. ref_axes.plot(x, np.append(y, y[-1]), drawstyle='steps-post', **style)
  2045. def test_stairs_empty():
  2046. ax = plt.figure().add_subplot()
  2047. ax.stairs([], [42])
  2048. assert ax.get_xlim() == (39, 45)
  2049. assert ax.get_ylim() == (-0.06, 0.06)
  2050. def test_stairs_invalid_nan():
  2051. with pytest.raises(ValueError, match='Nan values in "edges"'):
  2052. plt.stairs([1, 2], [0, np.nan, 1])
  2053. def test_stairs_invalid_mismatch():
  2054. with pytest.raises(ValueError, match='Size mismatch'):
  2055. plt.stairs([1, 2], [0, 1])
  2056. def test_stairs_invalid_update():
  2057. h = plt.stairs([1, 2], [0, 1, 2])
  2058. with pytest.raises(ValueError, match='Nan values in "edges"'):
  2059. h.set_data(edges=[1, np.nan, 2])
  2060. def test_stairs_invalid_update2():
  2061. h = plt.stairs([1, 2], [0, 1, 2])
  2062. with pytest.raises(ValueError, match='Size mismatch'):
  2063. h.set_data(edges=np.arange(5))
  2064. @image_comparison(['test_stairs_options.png'], remove_text=True)
  2065. def test_stairs_options():
  2066. x, y = np.array([1, 2, 3, 4, 5]), np.array([1, 2, 3, 4]).astype(float)
  2067. yn = y.copy()
  2068. yn[1] = np.nan
  2069. fig, ax = plt.subplots()
  2070. ax.stairs(y*3, x, color='green', fill=True, label="A")
  2071. ax.stairs(y, x*3-3, color='red', fill=True,
  2072. orientation='horizontal', label="B")
  2073. ax.stairs(yn, x, color='orange', ls='--', lw=2, label="C")
  2074. ax.stairs(yn/3, x*3-2, ls='--', lw=2, baseline=0.5,
  2075. orientation='horizontal', label="D")
  2076. ax.stairs(y[::-1]*3+13, x-1, color='red', ls='--', lw=2, baseline=None,
  2077. label="E")
  2078. ax.stairs(y[::-1]*3+14, x, baseline=26,
  2079. color='purple', ls='--', lw=2, label="F")
  2080. ax.stairs(yn[::-1]*3+15, x+1, baseline=np.linspace(27, 25, len(y)),
  2081. color='blue', ls='--', label="G", fill=True)
  2082. ax.stairs(y[:-1][::-1]*2+11, x[:-1]+0.5, color='black', ls='--', lw=2,
  2083. baseline=12, hatch='//', label="H")
  2084. ax.legend(loc=0)
  2085. @image_comparison(['test_stairs_datetime.png'])
  2086. def test_stairs_datetime():
  2087. f, ax = plt.subplots(constrained_layout=True)
  2088. ax.stairs(np.arange(36),
  2089. np.arange(np.datetime64('2001-12-27'),
  2090. np.datetime64('2002-02-02')))
  2091. plt.xticks(rotation=30)
  2092. @check_figures_equal(extensions=['png'])
  2093. def test_stairs_edge_handling(fig_test, fig_ref):
  2094. # Test
  2095. test_ax = fig_test.add_subplot()
  2096. test_ax.stairs([1, 2, 3], color='red', fill=True)
  2097. # Ref
  2098. ref_ax = fig_ref.add_subplot()
  2099. st = ref_ax.stairs([1, 2, 3], fill=True)
  2100. st.set_color('red')
  2101. def contour_dat():
  2102. x = np.linspace(-3, 5, 150)
  2103. y = np.linspace(-3, 5, 120)
  2104. z = np.cos(x) + np.sin(y[:, np.newaxis])
  2105. return x, y, z
  2106. @image_comparison(['contour_hatching'], remove_text=True, style='mpl20')
  2107. def test_contour_hatching():
  2108. x, y, z = contour_dat()
  2109. fig, ax = plt.subplots()
  2110. ax.contourf(x, y, z, 7, hatches=['/', '\\', '//', '-'],
  2111. cmap=mpl.colormaps['gray'],
  2112. extend='both', alpha=0.5)
  2113. @image_comparison(['contour_colorbar'], style='mpl20',
  2114. tol=0 if platform.machine() == 'x86_64' else 0.54)
  2115. def test_contour_colorbar():
  2116. x, y, z = contour_dat()
  2117. fig, ax = plt.subplots()
  2118. cs = ax.contourf(x, y, z, levels=np.arange(-1.8, 1.801, 0.2),
  2119. cmap=mpl.colormaps['RdBu'],
  2120. vmin=-0.6,
  2121. vmax=0.6,
  2122. extend='both')
  2123. cs1 = ax.contour(x, y, z, levels=np.arange(-2.2, -0.599, 0.2),
  2124. colors=['y'],
  2125. linestyles='solid',
  2126. linewidths=2)
  2127. cs2 = ax.contour(x, y, z, levels=np.arange(0.6, 2.2, 0.2),
  2128. colors=['c'],
  2129. linewidths=2)
  2130. cbar = fig.colorbar(cs, ax=ax)
  2131. cbar.add_lines(cs1)
  2132. cbar.add_lines(cs2, erase=False)
  2133. @image_comparison(['hist2d.png', 'hist2d.png'], remove_text=True, style='mpl20')
  2134. def test_hist2d():
  2135. # Remove this line when this test image is regenerated.
  2136. plt.rcParams['pcolormesh.snap'] = False
  2137. np.random.seed(0)
  2138. # make it not symmetric in case we switch x and y axis
  2139. x = np.random.randn(100)*2+5
  2140. y = np.random.randn(100)-2
  2141. fig, ax = plt.subplots()
  2142. ax.hist2d(x, y, bins=10, rasterized=True)
  2143. # Reuse testcase from above for a labeled data test
  2144. data = {"x": x, "y": y}
  2145. fig, ax = plt.subplots()
  2146. ax.hist2d("x", "y", bins=10, data=data, rasterized=True)
  2147. @image_comparison(['hist2d_transpose.png'], remove_text=True, style='mpl20')
  2148. def test_hist2d_transpose():
  2149. # Remove this line when this test image is regenerated.
  2150. plt.rcParams['pcolormesh.snap'] = False
  2151. np.random.seed(0)
  2152. # make sure the output from np.histogram is transposed before
  2153. # passing to pcolorfast
  2154. x = np.array([5]*100)
  2155. y = np.random.randn(100)-2
  2156. fig, ax = plt.subplots()
  2157. ax.hist2d(x, y, bins=10, rasterized=True)
  2158. def test_hist2d_density():
  2159. x, y = np.random.random((2, 100))
  2160. ax = plt.figure().subplots()
  2161. for obj in [ax, plt]:
  2162. obj.hist2d(x, y, density=True)
  2163. class TestScatter:
  2164. @image_comparison(['scatter'], style='mpl20', remove_text=True)
  2165. def test_scatter_plot(self):
  2166. data = {"x": np.array([3, 4, 2, 6]), "y": np.array([2, 5, 2, 3]),
  2167. "c": ['r', 'y', 'b', 'lime'], "s": [24, 15, 19, 29],
  2168. "c2": ['0.5', '0.6', '0.7', '0.8']}
  2169. fig, ax = plt.subplots()
  2170. ax.scatter(data["x"] - 1., data["y"] - 1., c=data["c"], s=data["s"])
  2171. ax.scatter(data["x"] + 1., data["y"] + 1., c=data["c2"], s=data["s"])
  2172. ax.scatter("x", "y", c="c", s="s", data=data)
  2173. @image_comparison(['scatter_marker.png'], remove_text=True)
  2174. def test_scatter_marker(self):
  2175. fig, (ax0, ax1, ax2) = plt.subplots(ncols=3)
  2176. ax0.scatter([3, 4, 2, 6], [2, 5, 2, 3],
  2177. c=[(1, 0, 0), 'y', 'b', 'lime'],
  2178. s=[60, 50, 40, 30],
  2179. edgecolors=['k', 'r', 'g', 'b'],
  2180. marker='s')
  2181. ax1.scatter([3, 4, 2, 6], [2, 5, 2, 3],
  2182. c=[(1, 0, 0), 'y', 'b', 'lime'],
  2183. s=[60, 50, 40, 30],
  2184. edgecolors=['k', 'r', 'g', 'b'],
  2185. marker=mmarkers.MarkerStyle('o', fillstyle='top'))
  2186. # unit area ellipse
  2187. rx, ry = 3, 1
  2188. area = rx * ry * np.pi
  2189. theta = np.linspace(0, 2 * np.pi, 21)
  2190. verts = np.column_stack([np.cos(theta) * rx / area,
  2191. np.sin(theta) * ry / area])
  2192. ax2.scatter([3, 4, 2, 6], [2, 5, 2, 3],
  2193. c=[(1, 0, 0), 'y', 'b', 'lime'],
  2194. s=[60, 50, 40, 30],
  2195. edgecolors=['k', 'r', 'g', 'b'],
  2196. marker=verts)
  2197. @image_comparison(['scatter_2D'], remove_text=True, extensions=['png'])
  2198. def test_scatter_2D(self):
  2199. x = np.arange(3)
  2200. y = np.arange(2)
  2201. x, y = np.meshgrid(x, y)
  2202. z = x + y
  2203. fig, ax = plt.subplots()
  2204. ax.scatter(x, y, c=z, s=200, edgecolors='face')
  2205. @check_figures_equal(extensions=["png"])
  2206. def test_scatter_decimal(self, fig_test, fig_ref):
  2207. x0 = np.array([1.5, 8.4, 5.3, 4.2])
  2208. y0 = np.array([1.1, 2.2, 3.3, 4.4])
  2209. x = np.array([Decimal(i) for i in x0])
  2210. y = np.array([Decimal(i) for i in y0])
  2211. c = ['r', 'y', 'b', 'lime']
  2212. s = [24, 15, 19, 29]
  2213. # Test image - scatter plot with Decimal() input
  2214. ax = fig_test.subplots()
  2215. ax.scatter(x, y, c=c, s=s)
  2216. # Reference image
  2217. ax = fig_ref.subplots()
  2218. ax.scatter(x0, y0, c=c, s=s)
  2219. def test_scatter_color(self):
  2220. # Try to catch cases where 'c' kwarg should have been used.
  2221. with pytest.raises(ValueError):
  2222. plt.scatter([1, 2], [1, 2], color=[0.1, 0.2])
  2223. with pytest.raises(ValueError):
  2224. plt.scatter([1, 2, 3], [1, 2, 3], color=[1, 2, 3])
  2225. @pytest.mark.parametrize('kwargs',
  2226. [
  2227. {'cmap': 'gray'},
  2228. {'norm': mcolors.Normalize()},
  2229. {'vmin': 0},
  2230. {'vmax': 0}
  2231. ])
  2232. def test_scatter_color_warning(self, kwargs):
  2233. warn_match = "No data for colormapping provided "
  2234. # Warn for cases where 'cmap', 'norm', 'vmin', 'vmax'
  2235. # kwargs are being overridden
  2236. with pytest.warns(Warning, match=warn_match):
  2237. plt.scatter([], [], **kwargs)
  2238. with pytest.warns(Warning, match=warn_match):
  2239. plt.scatter([1, 2], [3, 4], c=[], **kwargs)
  2240. # Do not warn for cases where 'c' matches 'x' and 'y'
  2241. plt.scatter([], [], c=[], **kwargs)
  2242. plt.scatter([1, 2], [3, 4], c=[4, 5], **kwargs)
  2243. def test_scatter_unfilled(self):
  2244. coll = plt.scatter([0, 1, 2], [1, 3, 2], c=['0.1', '0.3', '0.5'],
  2245. marker=mmarkers.MarkerStyle('o', fillstyle='none'),
  2246. linewidths=[1.1, 1.2, 1.3])
  2247. assert coll.get_facecolors().shape == (0, 4) # no facecolors
  2248. assert_array_equal(coll.get_edgecolors(), [[0.1, 0.1, 0.1, 1],
  2249. [0.3, 0.3, 0.3, 1],
  2250. [0.5, 0.5, 0.5, 1]])
  2251. assert_array_equal(coll.get_linewidths(), [1.1, 1.2, 1.3])
  2252. @mpl.style.context('default')
  2253. def test_scatter_unfillable(self):
  2254. coll = plt.scatter([0, 1, 2], [1, 3, 2], c=['0.1', '0.3', '0.5'],
  2255. marker='x',
  2256. linewidths=[1.1, 1.2, 1.3])
  2257. assert_array_equal(coll.get_facecolors(), coll.get_edgecolors())
  2258. assert_array_equal(coll.get_edgecolors(), [[0.1, 0.1, 0.1, 1],
  2259. [0.3, 0.3, 0.3, 1],
  2260. [0.5, 0.5, 0.5, 1]])
  2261. assert_array_equal(coll.get_linewidths(), [1.1, 1.2, 1.3])
  2262. def test_scatter_size_arg_size(self):
  2263. x = np.arange(4)
  2264. with pytest.raises(ValueError, match='same size as x and y'):
  2265. plt.scatter(x, x, x[1:])
  2266. with pytest.raises(ValueError, match='same size as x and y'):
  2267. plt.scatter(x[1:], x[1:], x)
  2268. with pytest.raises(ValueError, match='float array-like'):
  2269. plt.scatter(x, x, 'foo')
  2270. def test_scatter_edgecolor_RGB(self):
  2271. # GitHub issue 19066
  2272. coll = plt.scatter([1, 2, 3], [1, np.nan, np.nan],
  2273. edgecolor=(1, 0, 0))
  2274. assert mcolors.same_color(coll.get_edgecolor(), (1, 0, 0))
  2275. coll = plt.scatter([1, 2, 3, 4], [1, np.nan, np.nan, 1],
  2276. edgecolor=(1, 0, 0, 1))
  2277. assert mcolors.same_color(coll.get_edgecolor(), (1, 0, 0, 1))
  2278. @check_figures_equal(extensions=["png"])
  2279. def test_scatter_invalid_color(self, fig_test, fig_ref):
  2280. ax = fig_test.subplots()
  2281. cmap = mpl.colormaps["viridis"].resampled(16)
  2282. cmap.set_bad("k", 1)
  2283. # Set a nonuniform size to prevent the last call to `scatter` (plotting
  2284. # the invalid points separately in fig_ref) from using the marker
  2285. # stamping fast path, which would result in slightly offset markers.
  2286. ax.scatter(range(4), range(4),
  2287. c=[1, np.nan, 2, np.nan], s=[1, 2, 3, 4],
  2288. cmap=cmap, plotnonfinite=True)
  2289. ax = fig_ref.subplots()
  2290. cmap = mpl.colormaps["viridis"].resampled(16)
  2291. ax.scatter([0, 2], [0, 2], c=[1, 2], s=[1, 3], cmap=cmap)
  2292. ax.scatter([1, 3], [1, 3], s=[2, 4], color="k")
  2293. @check_figures_equal(extensions=["png"])
  2294. def test_scatter_no_invalid_color(self, fig_test, fig_ref):
  2295. # With plotnonfinite=False we plot only 2 points.
  2296. ax = fig_test.subplots()
  2297. cmap = mpl.colormaps["viridis"].resampled(16)
  2298. cmap.set_bad("k", 1)
  2299. ax.scatter(range(4), range(4),
  2300. c=[1, np.nan, 2, np.nan], s=[1, 2, 3, 4],
  2301. cmap=cmap, plotnonfinite=False)
  2302. ax = fig_ref.subplots()
  2303. ax.scatter([0, 2], [0, 2], c=[1, 2], s=[1, 3], cmap=cmap)
  2304. def test_scatter_norm_vminvmax(self):
  2305. """Parameters vmin, vmax should error if norm is given."""
  2306. x = [1, 2, 3]
  2307. ax = plt.axes()
  2308. with pytest.raises(ValueError,
  2309. match="Passing a Normalize instance simultaneously "
  2310. "with vmin/vmax is not supported."):
  2311. ax.scatter(x, x, c=x, norm=mcolors.Normalize(-10, 10),
  2312. vmin=0, vmax=5)
  2313. @check_figures_equal(extensions=["png"])
  2314. def test_scatter_single_point(self, fig_test, fig_ref):
  2315. ax = fig_test.subplots()
  2316. ax.scatter(1, 1, c=1)
  2317. ax = fig_ref.subplots()
  2318. ax.scatter([1], [1], c=[1])
  2319. @check_figures_equal(extensions=["png"])
  2320. def test_scatter_different_shapes(self, fig_test, fig_ref):
  2321. x = np.arange(10)
  2322. ax = fig_test.subplots()
  2323. ax.scatter(x, x.reshape(2, 5), c=x.reshape(5, 2))
  2324. ax = fig_ref.subplots()
  2325. ax.scatter(x.reshape(5, 2), x, c=x.reshape(2, 5))
  2326. # Parameters for *test_scatter_c*. NB: assuming that the
  2327. # scatter plot will have 4 elements. The tuple scheme is:
  2328. # (*c* parameter case, exception regexp key or None if no exception)
  2329. params_test_scatter_c = [
  2330. # single string:
  2331. ('0.5', None),
  2332. # Single letter-sequences
  2333. (["rgby"], "conversion"),
  2334. # Special cases
  2335. ("red", None),
  2336. ("none", None),
  2337. (None, None),
  2338. (["r", "g", "b", "none"], None),
  2339. # Non-valid color spec (FWIW, 'jaune' means yellow in French)
  2340. ("jaune", "conversion"),
  2341. (["jaune"], "conversion"), # wrong type before wrong size
  2342. (["jaune"]*4, "conversion"),
  2343. # Value-mapping like
  2344. ([0.5]*3, None), # should emit a warning for user's eyes though
  2345. ([0.5]*4, None), # NB: no warning as matching size allows mapping
  2346. ([0.5]*5, "shape"),
  2347. # list of strings:
  2348. (['0.5', '0.4', '0.6', '0.7'], None),
  2349. (['0.5', 'red', '0.6', 'C5'], None),
  2350. (['0.5', 0.5, '0.6', 'C5'], "conversion"),
  2351. # RGB values
  2352. ([[1, 0, 0]], None),
  2353. ([[1, 0, 0]]*3, "shape"),
  2354. ([[1, 0, 0]]*4, None),
  2355. ([[1, 0, 0]]*5, "shape"),
  2356. # RGBA values
  2357. ([[1, 0, 0, 0.5]], None),
  2358. ([[1, 0, 0, 0.5]]*3, "shape"),
  2359. ([[1, 0, 0, 0.5]]*4, None),
  2360. ([[1, 0, 0, 0.5]]*5, "shape"),
  2361. # Mix of valid color specs
  2362. ([[1, 0, 0, 0.5]]*3 + [[1, 0, 0]], None),
  2363. ([[1, 0, 0, 0.5], "red", "0.0"], "shape"),
  2364. ([[1, 0, 0, 0.5], "red", "0.0", "C5"], None),
  2365. ([[1, 0, 0, 0.5], "red", "0.0", "C5", [0, 1, 0]], "shape"),
  2366. # Mix of valid and non valid color specs
  2367. ([[1, 0, 0, 0.5], "red", "jaune"], "conversion"),
  2368. ([[1, 0, 0, 0.5], "red", "0.0", "jaune"], "conversion"),
  2369. ([[1, 0, 0, 0.5], "red", "0.0", "C5", "jaune"], "conversion"),
  2370. ]
  2371. @pytest.mark.parametrize('c_case, re_key', params_test_scatter_c)
  2372. def test_scatter_c(self, c_case, re_key):
  2373. def get_next_color(): # pragma: no cover
  2374. return 'blue' # currently unused
  2375. xsize = 4
  2376. # Additional checking of *c* (introduced in #11383).
  2377. REGEXP = {
  2378. "shape": "^'c' argument has [0-9]+ elements", # shape mismatch
  2379. "conversion": "^'c' argument must be a color", # bad vals
  2380. }
  2381. assert_context = (
  2382. pytest.raises(ValueError, match=REGEXP[re_key])
  2383. if re_key is not None
  2384. else pytest.warns(match="argument looks like a single numeric RGB")
  2385. if isinstance(c_case, list) and len(c_case) == 3
  2386. else contextlib.nullcontext()
  2387. )
  2388. with assert_context:
  2389. mpl.axes.Axes._parse_scatter_color_args(
  2390. c=c_case, edgecolors="black", kwargs={}, xsize=xsize,
  2391. get_next_color_func=get_next_color)
  2392. @mpl.style.context('default')
  2393. @check_figures_equal(extensions=["png"])
  2394. def test_scatter_single_color_c(self, fig_test, fig_ref):
  2395. rgb = [[1, 0.5, 0.05]]
  2396. rgba = [[1, 0.5, 0.05, .5]]
  2397. # set via color kwarg
  2398. ax_ref = fig_ref.subplots()
  2399. ax_ref.scatter(np.ones(3), range(3), color=rgb)
  2400. ax_ref.scatter(np.ones(4)*2, range(4), color=rgba)
  2401. # set via broadcasting via c
  2402. ax_test = fig_test.subplots()
  2403. ax_test.scatter(np.ones(3), range(3), c=rgb)
  2404. ax_test.scatter(np.ones(4)*2, range(4), c=rgba)
  2405. def test_scatter_linewidths(self):
  2406. x = np.arange(5)
  2407. fig, ax = plt.subplots()
  2408. for i in range(3):
  2409. pc = ax.scatter(x, np.full(5, i), c=f'C{i}', marker='x', s=100,
  2410. linewidths=i + 1)
  2411. assert pc.get_linewidths() == i + 1
  2412. pc = ax.scatter(x, np.full(5, 3), c='C3', marker='x', s=100,
  2413. linewidths=[*range(1, 5), None])
  2414. assert_array_equal(pc.get_linewidths(),
  2415. [*range(1, 5), mpl.rcParams['lines.linewidth']])
  2416. def test_scatter_singular_plural_arguments(self):
  2417. with pytest.raises(TypeError,
  2418. match="Got both 'linewidth' and 'linewidths',\
  2419. which are aliases of one another"):
  2420. plt.scatter([1, 2, 3], [1, 2, 3], linewidths=[0.5, 0.4, 0.3], linewidth=0.2)
  2421. with pytest.raises(TypeError,
  2422. match="Got both 'edgecolor' and 'edgecolors',\
  2423. which are aliases of one another"):
  2424. plt.scatter([1, 2, 3], [1, 2, 3],
  2425. edgecolors=["#ffffff", "#000000", "#f0f0f0"],
  2426. edgecolor="#ffffff")
  2427. with pytest.raises(TypeError,
  2428. match="Got both 'facecolors' and 'facecolor',\
  2429. which are aliases of one another"):
  2430. plt.scatter([1, 2, 3], [1, 2, 3],
  2431. facecolors=["#ffffff", "#000000", "#f0f0f0"],
  2432. facecolor="#ffffff")
  2433. def _params(c=None, xsize=2, *, edgecolors=None, **kwargs):
  2434. return (c, edgecolors, kwargs, xsize)
  2435. _result = namedtuple('_result', 'c, colors')
  2436. @pytest.mark.parametrize(
  2437. 'params, expected_result',
  2438. [(_params(),
  2439. _result(c='b', colors=np.array([[0, 0, 1, 1]]))),
  2440. (_params(c='r'),
  2441. _result(c='r', colors=np.array([[1, 0, 0, 1]]))),
  2442. (_params(c='r', colors='b'),
  2443. _result(c='r', colors=np.array([[1, 0, 0, 1]]))),
  2444. # color
  2445. (_params(color='b'),
  2446. _result(c='b', colors=np.array([[0, 0, 1, 1]]))),
  2447. (_params(color=['b', 'g']),
  2448. _result(c=['b', 'g'], colors=np.array([[0, 0, 1, 1], [0, .5, 0, 1]]))),
  2449. ])
  2450. def test_parse_scatter_color_args(params, expected_result):
  2451. def get_next_color(): # pragma: no cover
  2452. return 'blue' # currently unused
  2453. c, colors, _edgecolors = mpl.axes.Axes._parse_scatter_color_args(
  2454. *params, get_next_color_func=get_next_color)
  2455. assert c == expected_result.c
  2456. assert_allclose(colors, expected_result.colors)
  2457. del _params
  2458. del _result
  2459. @pytest.mark.parametrize(
  2460. 'kwargs, expected_edgecolors',
  2461. [(dict(), None),
  2462. (dict(c='b'), None),
  2463. (dict(edgecolors='r'), 'r'),
  2464. (dict(edgecolors=['r', 'g']), ['r', 'g']),
  2465. (dict(edgecolor='r'), 'r'),
  2466. (dict(edgecolors='face'), 'face'),
  2467. (dict(edgecolors='none'), 'none'),
  2468. (dict(edgecolor='r', edgecolors='g'), 'r'),
  2469. (dict(c='b', edgecolor='r', edgecolors='g'), 'r'),
  2470. (dict(color='r'), 'r'),
  2471. (dict(color='r', edgecolor='g'), 'g'),
  2472. ])
  2473. def test_parse_scatter_color_args_edgecolors(kwargs, expected_edgecolors):
  2474. def get_next_color(): # pragma: no cover
  2475. return 'blue' # currently unused
  2476. c = kwargs.pop('c', None)
  2477. edgecolors = kwargs.pop('edgecolors', None)
  2478. _, _, result_edgecolors = \
  2479. mpl.axes.Axes._parse_scatter_color_args(
  2480. c, edgecolors, kwargs, xsize=2, get_next_color_func=get_next_color)
  2481. assert result_edgecolors == expected_edgecolors
  2482. def test_parse_scatter_color_args_error():
  2483. def get_next_color(): # pragma: no cover
  2484. return 'blue' # currently unused
  2485. with pytest.raises(ValueError,
  2486. match="RGBA values should be within 0-1 range"):
  2487. c = np.array([[0.1, 0.2, 0.7], [0.2, 0.4, 1.4]]) # value > 1
  2488. mpl.axes.Axes._parse_scatter_color_args(
  2489. c, None, kwargs={}, xsize=2, get_next_color_func=get_next_color)
  2490. # Warning message tested in the next two tests.
  2491. WARN_MSG = (
  2492. "You passed both c and facecolor/facecolors for the markers. "
  2493. "c has precedence over facecolor/facecolors. This behavior may "
  2494. "change in the future."
  2495. )
  2496. # Test cases shared between direct and integration tests
  2497. COLOR_TEST_CASES = [
  2498. ('red', 'blue'),
  2499. (['red', 'blue'], ['green', 'yellow']),
  2500. ([[1, 0, 0], [0, 1, 0]], [[0, 0, 1], [1, 1, 0]])
  2501. ]
  2502. @pytest.mark.parametrize('c, facecolor', COLOR_TEST_CASES)
  2503. def test_parse_c_facecolor_warning_direct(c, facecolor):
  2504. """Test the internal _parse_scatter_color_args method directly."""
  2505. def get_next_color(): # pragma: no cover
  2506. return 'blue' # currently unused
  2507. # Test with facecolors (plural)
  2508. with pytest.warns(UserWarning, match=WARN_MSG):
  2509. mpl.axes.Axes._parse_scatter_color_args(
  2510. c=c, edgecolors=None, kwargs={'facecolors': facecolor},
  2511. xsize=2, get_next_color_func=get_next_color)
  2512. # Test with facecolor (singular)
  2513. with pytest.warns(UserWarning, match=WARN_MSG):
  2514. mpl.axes.Axes._parse_scatter_color_args(
  2515. c=c, edgecolors=None, kwargs={'facecolor': facecolor},
  2516. xsize=2, get_next_color_func=get_next_color)
  2517. @pytest.mark.parametrize('c, facecolor', COLOR_TEST_CASES)
  2518. def test_scatter_c_facecolor_warning_integration(c, facecolor):
  2519. """Test the warning through the actual scatter plot creation."""
  2520. fig, ax = plt.subplots()
  2521. x = [0, 1] if isinstance(c, (list, tuple)) else [0]
  2522. y = x
  2523. # Test with facecolors (plural)
  2524. with pytest.warns(UserWarning, match=WARN_MSG):
  2525. ax.scatter(x, y, c=c, facecolors=facecolor)
  2526. # Test with facecolor (singular)
  2527. with pytest.warns(UserWarning, match=WARN_MSG):
  2528. ax.scatter(x, y, c=c, facecolor=facecolor)
  2529. def test_as_mpl_axes_api():
  2530. # tests the _as_mpl_axes api
  2531. class Polar:
  2532. def __init__(self):
  2533. self.theta_offset = 0
  2534. def _as_mpl_axes(self):
  2535. # implement the matplotlib axes interface
  2536. return PolarAxes, {'theta_offset': self.theta_offset}
  2537. prj = Polar()
  2538. prj2 = Polar()
  2539. prj2.theta_offset = np.pi
  2540. # testing axes creation with plt.axes
  2541. ax = plt.axes((0, 0, 1, 1), projection=prj)
  2542. assert type(ax) is PolarAxes
  2543. plt.close()
  2544. # testing axes creation with subplot
  2545. ax = plt.subplot(121, projection=prj)
  2546. assert type(ax) is PolarAxes
  2547. plt.close()
  2548. def test_pyplot_axes():
  2549. # test focusing of Axes in other Figure
  2550. fig1, ax1 = plt.subplots()
  2551. fig2, ax2 = plt.subplots()
  2552. plt.sca(ax1)
  2553. assert ax1 is plt.gca()
  2554. assert fig1 is plt.gcf()
  2555. plt.close(fig1)
  2556. plt.close(fig2)
  2557. def test_log_scales():
  2558. fig, ax = plt.subplots()
  2559. ax.plot(np.log(np.linspace(0.1, 100)))
  2560. ax.set_yscale('log', base=5.5)
  2561. ax.invert_yaxis()
  2562. ax.set_xscale('log', base=9.0)
  2563. xticks, yticks = (
  2564. [(t.get_loc(), t.label1.get_text()) for t in axis._update_ticks()]
  2565. for axis in [ax.xaxis, ax.yaxis]
  2566. )
  2567. assert xticks == [
  2568. (1.0, '$\\mathdefault{9^{0}}$'),
  2569. (9.0, '$\\mathdefault{9^{1}}$'),
  2570. (81.0, '$\\mathdefault{9^{2}}$'),
  2571. (2.0, ''),
  2572. (3.0, ''),
  2573. (4.0, ''),
  2574. (5.0, ''),
  2575. (6.0, ''),
  2576. (7.0, ''),
  2577. (8.0, ''),
  2578. (18.0, ''),
  2579. (27.0, ''),
  2580. (36.0, ''),
  2581. (45.0, ''),
  2582. (54.0, ''),
  2583. (63.0, ''),
  2584. (72.0, ''),
  2585. ]
  2586. assert yticks == [
  2587. (0.18181818181818182, '$\\mathdefault{5.5^{-1}}$'),
  2588. (1.0, '$\\mathdefault{5.5^{0}}$'),
  2589. (5.5, '$\\mathdefault{5.5^{1}}$'),
  2590. (0.36363636363636365, ''),
  2591. (0.5454545454545454, ''),
  2592. (0.7272727272727273, ''),
  2593. (0.9090909090909092, ''),
  2594. (2.0, ''),
  2595. (3.0, ''),
  2596. (4.0, ''),
  2597. (5.0, ''),
  2598. ]
  2599. def test_log_scales_no_data():
  2600. _, ax = plt.subplots()
  2601. ax.set(xscale="log", yscale="log")
  2602. ax.xaxis.set_major_locator(mticker.MultipleLocator(1))
  2603. assert ax.get_xlim() == ax.get_ylim() == (1, 10)
  2604. def test_log_scales_invalid():
  2605. fig, ax = plt.subplots()
  2606. ax.set_xscale('log')
  2607. with pytest.warns(UserWarning, match='Attempt to set non-positive'):
  2608. ax.set_xlim(-1, 10)
  2609. ax.set_yscale('log')
  2610. with pytest.warns(UserWarning, match='Attempt to set non-positive'):
  2611. ax.set_ylim(-1, 10)
  2612. @image_comparison(['stackplot_test_image.png', 'stackplot_test_image.png'],
  2613. tol=0 if platform.machine() == 'x86_64' else 0.031)
  2614. def test_stackplot():
  2615. fig = plt.figure()
  2616. x = np.linspace(0, 10, 10)
  2617. y1 = 1.0 * x
  2618. y2 = 2.0 * x + 1
  2619. y3 = 3.0 * x + 2
  2620. ax = fig.add_subplot(1, 1, 1)
  2621. ax.stackplot(x, y1, y2, y3)
  2622. ax.set_xlim((0, 10))
  2623. ax.set_ylim((0, 70))
  2624. # Reuse testcase from above for a test with labeled data and with colours
  2625. # from the Axes property cycle.
  2626. data = {"x": x, "y1": y1, "y2": y2, "y3": y3}
  2627. fig, ax = plt.subplots()
  2628. ax.stackplot("x", "y1", "y2", "y3", data=data, colors=["C0", "C1", "C2"])
  2629. ax.set_xlim((0, 10))
  2630. ax.set_ylim((0, 70))
  2631. @image_comparison(['stackplot_test_baseline.png'], remove_text=True)
  2632. def test_stackplot_baseline():
  2633. np.random.seed(0)
  2634. def layers(n, m):
  2635. a = np.zeros((m, n))
  2636. for i in range(n):
  2637. for j in range(5):
  2638. x = 1 / (.1 + np.random.random())
  2639. y = 2 * np.random.random() - .5
  2640. z = 10 / (.1 + np.random.random())
  2641. a[:, i] += x * np.exp(-((np.arange(m) / m - y) * z) ** 2)
  2642. return a
  2643. d = layers(3, 100)
  2644. d[50, :] = 0 # test for fixed weighted wiggle (issue #6313)
  2645. fig, axs = plt.subplots(2, 2)
  2646. axs[0, 0].stackplot(range(100), d.T, baseline='zero')
  2647. axs[0, 1].stackplot(range(100), d.T, baseline='sym')
  2648. axs[1, 0].stackplot(range(100), d.T, baseline='wiggle')
  2649. axs[1, 1].stackplot(range(100), d.T, baseline='weighted_wiggle')
  2650. @check_figures_equal(extensions=['png'])
  2651. def test_stackplot_hatching(fig_ref, fig_test):
  2652. x = np.linspace(0, 10, 10)
  2653. y1 = 1.0 * x
  2654. y2 = 2.0 * x + 1
  2655. y3 = 3.0 * x + 2
  2656. # stackplot with different hatching styles (issue #27146)
  2657. ax_test = fig_test.subplots()
  2658. ax_test.stackplot(x, y1, y2, y3, hatch=["x", "//", "\\\\"], colors=["white"])
  2659. ax_test.set_xlim((0, 10))
  2660. ax_test.set_ylim((0, 70))
  2661. # compare with result from hatching each layer individually
  2662. stack_baseline = np.zeros(len(x))
  2663. ax_ref = fig_ref.subplots()
  2664. ax_ref.fill_between(x, stack_baseline, y1, hatch="x", facecolor="white")
  2665. ax_ref.fill_between(x, y1, y1+y2, hatch="//", facecolor="white")
  2666. ax_ref.fill_between(x, y1+y2, y1+y2+y3, hatch="\\\\", facecolor="white")
  2667. ax_ref.set_xlim((0, 10))
  2668. ax_ref.set_ylim((0, 70))
  2669. def test_stackplot_subfig_legend():
  2670. # Smoke test for https://github.com/matplotlib/matplotlib/issues/30158
  2671. fig = plt.figure()
  2672. subfigs = fig.subfigures(nrows=1, ncols=2)
  2673. for _fig in subfigs:
  2674. ax = _fig.subplots(nrows=1, ncols=1)
  2675. ax.stackplot([3, 4], [[1, 2]], labels=['a'])
  2676. fig.legend()
  2677. fig.draw_without_rendering()
  2678. def _bxp_test_helper(
  2679. stats_kwargs={}, transform_stats=lambda s: s, bxp_kwargs={}):
  2680. np.random.seed(937)
  2681. logstats = mpl.cbook.boxplot_stats(
  2682. np.random.lognormal(mean=1.25, sigma=1., size=(37, 4)), **stats_kwargs)
  2683. fig, ax = plt.subplots()
  2684. if bxp_kwargs.get('orientation', 'vertical') == 'vertical':
  2685. ax.set_yscale('log')
  2686. else:
  2687. ax.set_xscale('log')
  2688. # Work around baseline images generate back when bxp did not respect the
  2689. # boxplot.boxprops.linewidth rcParam when patch_artist is False.
  2690. if not bxp_kwargs.get('patch_artist', False):
  2691. mpl.rcParams['boxplot.boxprops.linewidth'] = \
  2692. mpl.rcParams['lines.linewidth']
  2693. ax.bxp(transform_stats(logstats), **bxp_kwargs)
  2694. @image_comparison(['bxp_baseline.png'],
  2695. savefig_kwarg={'dpi': 40},
  2696. style='default')
  2697. def test_bxp_baseline():
  2698. _bxp_test_helper()
  2699. @image_comparison(['bxp_rangewhis.png'],
  2700. savefig_kwarg={'dpi': 40},
  2701. style='default')
  2702. def test_bxp_rangewhis():
  2703. _bxp_test_helper(stats_kwargs=dict(whis=[0, 100]))
  2704. @image_comparison(['bxp_percentilewhis.png'],
  2705. savefig_kwarg={'dpi': 40},
  2706. style='default')
  2707. def test_bxp_percentilewhis():
  2708. _bxp_test_helper(stats_kwargs=dict(whis=[5, 95]))
  2709. @image_comparison(['bxp_with_xlabels.png'],
  2710. savefig_kwarg={'dpi': 40},
  2711. style='default')
  2712. def test_bxp_with_xlabels():
  2713. def transform(stats):
  2714. for s, label in zip(stats, list('ABCD')):
  2715. s['label'] = label
  2716. return stats
  2717. _bxp_test_helper(transform_stats=transform)
  2718. @image_comparison(['bxp_horizontal.png'],
  2719. remove_text=True,
  2720. savefig_kwarg={'dpi': 40},
  2721. style='default',
  2722. tol=0.1)
  2723. def test_bxp_horizontal():
  2724. _bxp_test_helper(bxp_kwargs=dict(orientation='horizontal'))
  2725. @image_comparison(['bxp_with_ylabels.png'],
  2726. savefig_kwarg={'dpi': 40},
  2727. style='default',
  2728. tol=0.1)
  2729. def test_bxp_with_ylabels():
  2730. def transform(stats):
  2731. for s, label in zip(stats, list('ABCD')):
  2732. s['label'] = label
  2733. return stats
  2734. _bxp_test_helper(transform_stats=transform,
  2735. bxp_kwargs=dict(orientation='horizontal'))
  2736. @image_comparison(['bxp_patchartist.png'],
  2737. remove_text=True,
  2738. savefig_kwarg={'dpi': 40},
  2739. style='default')
  2740. def test_bxp_patchartist():
  2741. _bxp_test_helper(bxp_kwargs=dict(patch_artist=True))
  2742. @image_comparison(['bxp_custompatchartist.png'],
  2743. remove_text=True,
  2744. savefig_kwarg={'dpi': 100},
  2745. style='default')
  2746. def test_bxp_custompatchartist():
  2747. _bxp_test_helper(bxp_kwargs=dict(
  2748. patch_artist=True,
  2749. boxprops=dict(facecolor='yellow', edgecolor='green', ls=':')))
  2750. @image_comparison(['bxp_customoutlier.png'],
  2751. remove_text=True,
  2752. savefig_kwarg={'dpi': 40},
  2753. style='default')
  2754. def test_bxp_customoutlier():
  2755. _bxp_test_helper(bxp_kwargs=dict(
  2756. flierprops=dict(linestyle='none', marker='d', mfc='g')))
  2757. @image_comparison(['bxp_withmean_custompoint.png'],
  2758. remove_text=True,
  2759. savefig_kwarg={'dpi': 40},
  2760. style='default')
  2761. def test_bxp_showcustommean():
  2762. _bxp_test_helper(bxp_kwargs=dict(
  2763. showmeans=True,
  2764. meanprops=dict(linestyle='none', marker='d', mfc='green'),
  2765. ))
  2766. @image_comparison(['bxp_custombox.png'],
  2767. remove_text=True,
  2768. savefig_kwarg={'dpi': 40},
  2769. style='default')
  2770. def test_bxp_custombox():
  2771. _bxp_test_helper(bxp_kwargs=dict(
  2772. boxprops=dict(linestyle='--', color='b', lw=3)))
  2773. @image_comparison(['bxp_custommedian.png'],
  2774. remove_text=True,
  2775. savefig_kwarg={'dpi': 40},
  2776. style='default')
  2777. def test_bxp_custommedian():
  2778. _bxp_test_helper(bxp_kwargs=dict(
  2779. medianprops=dict(linestyle='--', color='b', lw=3)))
  2780. @image_comparison(['bxp_customcap.png'],
  2781. remove_text=True,
  2782. savefig_kwarg={'dpi': 40},
  2783. style='default')
  2784. def test_bxp_customcap():
  2785. _bxp_test_helper(bxp_kwargs=dict(
  2786. capprops=dict(linestyle='--', color='g', lw=3)))
  2787. @image_comparison(['bxp_customwhisker.png'],
  2788. remove_text=True,
  2789. savefig_kwarg={'dpi': 40},
  2790. style='default')
  2791. def test_bxp_customwhisker():
  2792. _bxp_test_helper(bxp_kwargs=dict(
  2793. whiskerprops=dict(linestyle='-', color='m', lw=3)))
  2794. @check_figures_equal(extensions=['png'])
  2795. def test_boxplot_median_bound_by_box(fig_test, fig_ref):
  2796. data = np.arange(3)
  2797. medianprops_test = {"linewidth": 12}
  2798. medianprops_ref = {**medianprops_test, "solid_capstyle": "butt"}
  2799. fig_test.subplots().boxplot(data, medianprops=medianprops_test)
  2800. fig_ref.subplots().boxplot(data, medianprops=medianprops_ref)
  2801. @image_comparison(['bxp_withnotch.png'],
  2802. remove_text=True,
  2803. savefig_kwarg={'dpi': 40},
  2804. style='default')
  2805. def test_bxp_shownotches():
  2806. _bxp_test_helper(bxp_kwargs=dict(shownotches=True))
  2807. @image_comparison(['bxp_nocaps.png'],
  2808. remove_text=True,
  2809. savefig_kwarg={'dpi': 40},
  2810. style='default')
  2811. def test_bxp_nocaps():
  2812. _bxp_test_helper(bxp_kwargs=dict(showcaps=False))
  2813. @image_comparison(['bxp_nobox.png'],
  2814. remove_text=True,
  2815. savefig_kwarg={'dpi': 40},
  2816. style='default')
  2817. def test_bxp_nobox():
  2818. _bxp_test_helper(bxp_kwargs=dict(showbox=False))
  2819. @image_comparison(['bxp_no_flier_stats.png'],
  2820. remove_text=True,
  2821. savefig_kwarg={'dpi': 40},
  2822. style='default')
  2823. def test_bxp_no_flier_stats():
  2824. def transform(stats):
  2825. for s in stats:
  2826. s.pop('fliers', None)
  2827. return stats
  2828. _bxp_test_helper(transform_stats=transform,
  2829. bxp_kwargs=dict(showfliers=False))
  2830. @image_comparison(['bxp_withmean_point.png'],
  2831. remove_text=True,
  2832. savefig_kwarg={'dpi': 40},
  2833. style='default')
  2834. def test_bxp_showmean():
  2835. _bxp_test_helper(bxp_kwargs=dict(showmeans=True, meanline=False))
  2836. @image_comparison(['bxp_withmean_line.png'],
  2837. remove_text=True,
  2838. savefig_kwarg={'dpi': 40},
  2839. style='default')
  2840. def test_bxp_showmeanasline():
  2841. _bxp_test_helper(bxp_kwargs=dict(showmeans=True, meanline=True))
  2842. @image_comparison(['bxp_scalarwidth.png'],
  2843. remove_text=True,
  2844. savefig_kwarg={'dpi': 40},
  2845. style='default')
  2846. def test_bxp_scalarwidth():
  2847. _bxp_test_helper(bxp_kwargs=dict(widths=.25))
  2848. @image_comparison(['bxp_customwidths.png'],
  2849. remove_text=True,
  2850. savefig_kwarg={'dpi': 40},
  2851. style='default')
  2852. def test_bxp_customwidths():
  2853. _bxp_test_helper(bxp_kwargs=dict(widths=[0.10, 0.25, 0.65, 0.85]))
  2854. @image_comparison(['bxp_custompositions.png'],
  2855. remove_text=True,
  2856. savefig_kwarg={'dpi': 40},
  2857. style='default')
  2858. def test_bxp_custompositions():
  2859. _bxp_test_helper(bxp_kwargs=dict(positions=[1, 5, 6, 7]))
  2860. def test_bxp_bad_widths():
  2861. with pytest.raises(ValueError):
  2862. _bxp_test_helper(bxp_kwargs=dict(widths=[1]))
  2863. def test_bxp_bad_positions():
  2864. with pytest.raises(ValueError):
  2865. _bxp_test_helper(bxp_kwargs=dict(positions=[2, 3]))
  2866. @image_comparison(['bxp_custom_capwidths.png'],
  2867. savefig_kwarg={'dpi': 40},
  2868. style='default')
  2869. def test_bxp_custom_capwidths():
  2870. _bxp_test_helper(bxp_kwargs=dict(capwidths=[0.0, 0.1, 0.5, 1.0]))
  2871. @image_comparison(['bxp_custom_capwidth.png'],
  2872. savefig_kwarg={'dpi': 40},
  2873. style='default')
  2874. def test_bxp_custom_capwidth():
  2875. _bxp_test_helper(bxp_kwargs=dict(capwidths=0.6))
  2876. def test_bxp_bad_capwidths():
  2877. with pytest.raises(ValueError):
  2878. _bxp_test_helper(bxp_kwargs=dict(capwidths=[1]))
  2879. @image_comparison(['boxplot.png', 'boxplot.png'], tol=1.28, style='default')
  2880. def test_boxplot():
  2881. # Randomness used for bootstrapping.
  2882. np.random.seed(937)
  2883. x = np.linspace(-7, 7, 140)
  2884. x = np.hstack([-25, x, 25])
  2885. fig, ax = plt.subplots()
  2886. ax.boxplot([x, x], bootstrap=10000, notch=1)
  2887. ax.set_ylim((-30, 30))
  2888. # Reuse testcase from above for a labeled data test
  2889. data = {"x": [x, x]}
  2890. fig, ax = plt.subplots()
  2891. ax.boxplot("x", bootstrap=10000, notch=1, data=data)
  2892. ax.set_ylim((-30, 30))
  2893. @check_figures_equal(extensions=["png"])
  2894. def test_boxplot_masked(fig_test, fig_ref):
  2895. # Check that masked values are ignored when plotting a boxplot
  2896. x_orig = np.linspace(-1, 1, 200)
  2897. ax = fig_test.subplots()
  2898. x = x_orig[x_orig >= 0]
  2899. ax.boxplot(x)
  2900. x = np.ma.masked_less(x_orig, 0)
  2901. ax = fig_ref.subplots()
  2902. ax.boxplot(x)
  2903. @image_comparison(['boxplot_custom_capwidths.png'],
  2904. savefig_kwarg={'dpi': 40}, style='default')
  2905. def test_boxplot_custom_capwidths():
  2906. x = np.linspace(-7, 7, 140)
  2907. x = np.hstack([-25, x, 25])
  2908. fig, ax = plt.subplots()
  2909. ax.boxplot([x, x], notch=1, capwidths=[0.01, 0.2])
  2910. @image_comparison(['boxplot_sym2.png'], remove_text=True, style='default')
  2911. def test_boxplot_sym2():
  2912. # Randomness used for bootstrapping.
  2913. np.random.seed(937)
  2914. x = np.linspace(-7, 7, 140)
  2915. x = np.hstack([-25, x, 25])
  2916. fig, [ax1, ax2] = plt.subplots(1, 2)
  2917. ax1.boxplot([x, x], bootstrap=10000, sym='^')
  2918. ax1.set_ylim((-30, 30))
  2919. ax2.boxplot([x, x], bootstrap=10000, sym='g')
  2920. ax2.set_ylim((-30, 30))
  2921. @image_comparison(['boxplot_sym.png'],
  2922. remove_text=True,
  2923. savefig_kwarg={'dpi': 40},
  2924. style='default')
  2925. def test_boxplot_sym():
  2926. x = np.linspace(-7, 7, 140)
  2927. x = np.hstack([-25, x, 25])
  2928. fig, ax = plt.subplots()
  2929. ax.boxplot([x, x], sym='gs')
  2930. ax.set_ylim((-30, 30))
  2931. @image_comparison(['boxplot_autorange_false_whiskers.png',
  2932. 'boxplot_autorange_true_whiskers.png'],
  2933. style='default')
  2934. def test_boxplot_autorange_whiskers():
  2935. # Randomness used for bootstrapping.
  2936. np.random.seed(937)
  2937. x = np.ones(140)
  2938. x = np.hstack([0, x, 2])
  2939. fig1, ax1 = plt.subplots()
  2940. ax1.boxplot([x, x], bootstrap=10000, notch=1)
  2941. ax1.set_ylim((-5, 5))
  2942. fig2, ax2 = plt.subplots()
  2943. ax2.boxplot([x, x], bootstrap=10000, notch=1, autorange=True)
  2944. ax2.set_ylim((-5, 5))
  2945. def _rc_test_bxp_helper(ax, rc_dict):
  2946. x = np.linspace(-7, 7, 140)
  2947. x = np.hstack([-25, x, 25])
  2948. with matplotlib.rc_context(rc_dict):
  2949. ax.boxplot([x, x])
  2950. return ax
  2951. @image_comparison(['boxplot_rc_parameters.png'],
  2952. savefig_kwarg={'dpi': 100}, remove_text=True,
  2953. tol=1, style='default')
  2954. def test_boxplot_rc_parameters():
  2955. # Randomness used for bootstrapping.
  2956. np.random.seed(937)
  2957. fig, ax = plt.subplots(3)
  2958. rc_axis0 = {
  2959. 'boxplot.notch': True,
  2960. 'boxplot.whiskers': [5, 95],
  2961. 'boxplot.bootstrap': 10000,
  2962. 'boxplot.flierprops.color': 'b',
  2963. 'boxplot.flierprops.marker': 'o',
  2964. 'boxplot.flierprops.markerfacecolor': 'g',
  2965. 'boxplot.flierprops.markeredgecolor': 'b',
  2966. 'boxplot.flierprops.markersize': 5,
  2967. 'boxplot.flierprops.linestyle': '--',
  2968. 'boxplot.flierprops.linewidth': 2.0,
  2969. 'boxplot.boxprops.color': 'r',
  2970. 'boxplot.boxprops.linewidth': 2.0,
  2971. 'boxplot.boxprops.linestyle': '--',
  2972. 'boxplot.capprops.color': 'c',
  2973. 'boxplot.capprops.linewidth': 2.0,
  2974. 'boxplot.capprops.linestyle': '--',
  2975. 'boxplot.medianprops.color': 'k',
  2976. 'boxplot.medianprops.linewidth': 2.0,
  2977. 'boxplot.medianprops.linestyle': '--',
  2978. }
  2979. rc_axis1 = {
  2980. 'boxplot.whiskers': [0, 100],
  2981. 'boxplot.patchartist': True,
  2982. }
  2983. rc_axis2 = {
  2984. 'boxplot.whiskers': 2.0,
  2985. 'boxplot.showcaps': False,
  2986. 'boxplot.showbox': False,
  2987. 'boxplot.showfliers': False,
  2988. 'boxplot.showmeans': True,
  2989. 'boxplot.meanline': True,
  2990. 'boxplot.meanprops.color': 'c',
  2991. 'boxplot.meanprops.linewidth': 2.0,
  2992. 'boxplot.meanprops.linestyle': '--',
  2993. 'boxplot.whiskerprops.color': 'r',
  2994. 'boxplot.whiskerprops.linewidth': 2.0,
  2995. 'boxplot.whiskerprops.linestyle': '-.',
  2996. }
  2997. dict_list = [rc_axis0, rc_axis1, rc_axis2]
  2998. for axis, rc_axis in zip(ax, dict_list):
  2999. _rc_test_bxp_helper(axis, rc_axis)
  3000. assert (matplotlib.patches.PathPatch in
  3001. [type(t) for t in ax[1].get_children()])
  3002. @image_comparison(['boxplot_with_CIarray.png'],
  3003. remove_text=True, savefig_kwarg={'dpi': 40}, style='default')
  3004. def test_boxplot_with_CIarray():
  3005. # Randomness used for bootstrapping.
  3006. np.random.seed(937)
  3007. x = np.linspace(-7, 7, 140)
  3008. x = np.hstack([-25, x, 25])
  3009. fig, ax = plt.subplots()
  3010. CIs = np.array([[-1.5, 3.], [-1., 3.5]])
  3011. # show a boxplot with Matplotlib medians and confidence intervals, and
  3012. # another with manual values
  3013. ax.boxplot([x, x], bootstrap=10000, usermedians=[None, 1.0],
  3014. conf_intervals=CIs, notch=1)
  3015. ax.set_ylim((-30, 30))
  3016. @image_comparison(['boxplot_no_inverted_whisker.png'],
  3017. remove_text=True, savefig_kwarg={'dpi': 40}, style='default')
  3018. def test_boxplot_no_weird_whisker():
  3019. x = np.array([3, 9000, 150, 88, 350, 200000, 1400, 960],
  3020. dtype=np.float64)
  3021. ax1 = plt.axes()
  3022. ax1.boxplot(x)
  3023. ax1.set_yscale('log')
  3024. ax1.yaxis.grid(False, which='minor')
  3025. ax1.xaxis.grid(False)
  3026. def test_boxplot_bad_medians():
  3027. x = np.linspace(-7, 7, 140)
  3028. x = np.hstack([-25, x, 25])
  3029. fig, ax = plt.subplots()
  3030. with pytest.raises(ValueError):
  3031. ax.boxplot(x, usermedians=[1, 2])
  3032. with pytest.raises(ValueError):
  3033. ax.boxplot([x, x], usermedians=[[1, 2], [1, 2]])
  3034. def test_boxplot_bad_ci():
  3035. x = np.linspace(-7, 7, 140)
  3036. x = np.hstack([-25, x, 25])
  3037. fig, ax = plt.subplots()
  3038. with pytest.raises(ValueError):
  3039. ax.boxplot([x, x], conf_intervals=[[1, 2]])
  3040. with pytest.raises(ValueError):
  3041. ax.boxplot([x, x], conf_intervals=[[1, 2], [1]])
  3042. def test_boxplot_zorder():
  3043. x = np.arange(10)
  3044. fix, ax = plt.subplots()
  3045. assert ax.boxplot(x)['boxes'][0].get_zorder() == 2
  3046. assert ax.boxplot(x, zorder=10)['boxes'][0].get_zorder() == 10
  3047. def test_boxplot_marker_behavior():
  3048. plt.rcParams['lines.marker'] = 's'
  3049. plt.rcParams['boxplot.flierprops.marker'] = 'o'
  3050. plt.rcParams['boxplot.meanprops.marker'] = '^'
  3051. fig, ax = plt.subplots()
  3052. test_data = np.arange(100)
  3053. test_data[-1] = 150 # a flier point
  3054. bxp_handle = ax.boxplot(test_data, showmeans=True)
  3055. for bxp_lines in ['whiskers', 'caps', 'boxes', 'medians']:
  3056. for each_line in bxp_handle[bxp_lines]:
  3057. # Ensure that the rcParams['lines.marker'] is overridden by ''
  3058. assert each_line.get_marker() == ''
  3059. # Ensure that markers for fliers and means aren't overridden with ''
  3060. assert bxp_handle['fliers'][0].get_marker() == 'o'
  3061. assert bxp_handle['means'][0].get_marker() == '^'
  3062. @image_comparison(['boxplot_mod_artists_after_plotting.png'],
  3063. remove_text=True, savefig_kwarg={'dpi': 40}, style='default')
  3064. def test_boxplot_mod_artist_after_plotting():
  3065. x = [0.15, 0.11, 0.06, 0.06, 0.12, 0.56, -0.56]
  3066. fig, ax = plt.subplots()
  3067. bp = ax.boxplot(x, sym="o")
  3068. for key in bp:
  3069. for obj in bp[key]:
  3070. obj.set_color('green')
  3071. @image_comparison(['violinplot_vert_baseline.png',
  3072. 'violinplot_vert_baseline.png'])
  3073. def test_vert_violinplot_baseline():
  3074. # First 9 digits of frac(sqrt(2))
  3075. np.random.seed(414213562)
  3076. data = [np.random.normal(size=100) for _ in range(4)]
  3077. ax = plt.axes()
  3078. ax.violinplot(data, positions=range(4), showmeans=False, showextrema=False,
  3079. showmedians=False)
  3080. # Reuse testcase from above for a labeled data test
  3081. data = {"d": data}
  3082. fig, ax = plt.subplots()
  3083. ax.violinplot("d", positions=range(4), showmeans=False, showextrema=False,
  3084. showmedians=False, data=data)
  3085. @image_comparison(['violinplot_vert_showmeans.png'])
  3086. def test_vert_violinplot_showmeans():
  3087. ax = plt.axes()
  3088. # First 9 digits of frac(sqrt(3))
  3089. np.random.seed(732050807)
  3090. data = [np.random.normal(size=100) for _ in range(4)]
  3091. ax.violinplot(data, positions=range(4), showmeans=True, showextrema=False,
  3092. showmedians=False)
  3093. @image_comparison(['violinplot_vert_showextrema.png'])
  3094. def test_vert_violinplot_showextrema():
  3095. ax = plt.axes()
  3096. # First 9 digits of frac(sqrt(5))
  3097. np.random.seed(236067977)
  3098. data = [np.random.normal(size=100) for _ in range(4)]
  3099. ax.violinplot(data, positions=range(4), showmeans=False, showextrema=True,
  3100. showmedians=False)
  3101. @image_comparison(['violinplot_vert_showmedians.png'])
  3102. def test_vert_violinplot_showmedians():
  3103. ax = plt.axes()
  3104. # First 9 digits of frac(sqrt(7))
  3105. np.random.seed(645751311)
  3106. data = [np.random.normal(size=100) for _ in range(4)]
  3107. ax.violinplot(data, positions=range(4), showmeans=False, showextrema=False,
  3108. showmedians=True)
  3109. @image_comparison(['violinplot_vert_showall.png'])
  3110. def test_vert_violinplot_showall():
  3111. ax = plt.axes()
  3112. # First 9 digits of frac(sqrt(11))
  3113. np.random.seed(316624790)
  3114. data = [np.random.normal(size=100) for _ in range(4)]
  3115. ax.violinplot(data, positions=range(4), showmeans=True, showextrema=True,
  3116. showmedians=True,
  3117. quantiles=[[0.1, 0.9], [0.2, 0.8], [0.3, 0.7], [0.4, 0.6]])
  3118. @image_comparison(['violinplot_vert_custompoints_10.png'])
  3119. def test_vert_violinplot_custompoints_10():
  3120. ax = plt.axes()
  3121. # First 9 digits of frac(sqrt(13))
  3122. np.random.seed(605551275)
  3123. data = [np.random.normal(size=100) for _ in range(4)]
  3124. ax.violinplot(data, positions=range(4), showmeans=False, showextrema=False,
  3125. showmedians=False, points=10)
  3126. @image_comparison(['violinplot_vert_custompoints_200.png'])
  3127. def test_vert_violinplot_custompoints_200():
  3128. ax = plt.axes()
  3129. # First 9 digits of frac(sqrt(17))
  3130. np.random.seed(123105625)
  3131. data = [np.random.normal(size=100) for _ in range(4)]
  3132. ax.violinplot(data, positions=range(4), showmeans=False, showextrema=False,
  3133. showmedians=False, points=200)
  3134. @image_comparison(['violinplot_horiz_baseline.png'])
  3135. def test_horiz_violinplot_baseline():
  3136. ax = plt.axes()
  3137. # First 9 digits of frac(sqrt(19))
  3138. np.random.seed(358898943)
  3139. data = [np.random.normal(size=100) for _ in range(4)]
  3140. ax.violinplot(data, positions=range(4), orientation='horizontal', showmeans=False,
  3141. showextrema=False, showmedians=False)
  3142. @image_comparison(['violinplot_horiz_showmedians.png'])
  3143. def test_horiz_violinplot_showmedians():
  3144. ax = plt.axes()
  3145. # First 9 digits of frac(sqrt(23))
  3146. np.random.seed(795831523)
  3147. data = [np.random.normal(size=100) for _ in range(4)]
  3148. ax.violinplot(data, positions=range(4), orientation='horizontal', showmeans=False,
  3149. showextrema=False, showmedians=True)
  3150. @image_comparison(['violinplot_horiz_showmeans.png'])
  3151. def test_horiz_violinplot_showmeans():
  3152. ax = plt.axes()
  3153. # First 9 digits of frac(sqrt(29))
  3154. np.random.seed(385164807)
  3155. data = [np.random.normal(size=100) for _ in range(4)]
  3156. ax.violinplot(data, positions=range(4), orientation='horizontal', showmeans=True,
  3157. showextrema=False, showmedians=False)
  3158. @image_comparison(['violinplot_horiz_showextrema.png'])
  3159. def test_horiz_violinplot_showextrema():
  3160. ax = plt.axes()
  3161. # First 9 digits of frac(sqrt(31))
  3162. np.random.seed(567764362)
  3163. data = [np.random.normal(size=100) for _ in range(4)]
  3164. ax.violinplot(data, positions=range(4), orientation='horizontal', showmeans=False,
  3165. showextrema=True, showmedians=False)
  3166. @image_comparison(['violinplot_horiz_showall.png'])
  3167. def test_horiz_violinplot_showall():
  3168. ax = plt.axes()
  3169. # First 9 digits of frac(sqrt(37))
  3170. np.random.seed(82762530)
  3171. data = [np.random.normal(size=100) for _ in range(4)]
  3172. ax.violinplot(data, positions=range(4), orientation='horizontal', showmeans=True,
  3173. showextrema=True, showmedians=True,
  3174. quantiles=[[0.1, 0.9], [0.2, 0.8], [0.3, 0.7], [0.4, 0.6]])
  3175. @image_comparison(['violinplot_horiz_custompoints_10.png'])
  3176. def test_horiz_violinplot_custompoints_10():
  3177. ax = plt.axes()
  3178. # First 9 digits of frac(sqrt(41))
  3179. np.random.seed(403124237)
  3180. data = [np.random.normal(size=100) for _ in range(4)]
  3181. ax.violinplot(data, positions=range(4), orientation='horizontal', showmeans=False,
  3182. showextrema=False, showmedians=False, points=10)
  3183. @image_comparison(['violinplot_horiz_custompoints_200.png'])
  3184. def test_horiz_violinplot_custompoints_200():
  3185. ax = plt.axes()
  3186. # First 9 digits of frac(sqrt(43))
  3187. np.random.seed(557438524)
  3188. data = [np.random.normal(size=100) for _ in range(4)]
  3189. ax.violinplot(data, positions=range(4), orientation='horizontal', showmeans=False,
  3190. showextrema=False, showmedians=False, points=200)
  3191. @image_comparison(['violinplot_sides.png'], remove_text=True, style='mpl20')
  3192. def test_violinplot_sides():
  3193. ax = plt.axes()
  3194. np.random.seed(19680801)
  3195. data = [np.random.normal(size=100)]
  3196. # Check horizontal violinplot
  3197. for pos, side in zip([0, -0.5, 0.5], ['both', 'low', 'high']):
  3198. ax.violinplot(data, positions=[pos], orientation='horizontal', showmeans=False,
  3199. showextrema=True, showmedians=True, side=side)
  3200. # Check vertical violinplot
  3201. for pos, side in zip([4, 3.5, 4.5], ['both', 'low', 'high']):
  3202. ax.violinplot(data, positions=[pos], orientation='vertical', showmeans=False,
  3203. showextrema=True, showmedians=True, side=side)
  3204. def test_violinplot_bad_positions():
  3205. ax = plt.axes()
  3206. # First 9 digits of frac(sqrt(47))
  3207. np.random.seed(855654600)
  3208. data = [np.random.normal(size=100) for _ in range(4)]
  3209. with pytest.raises(ValueError):
  3210. ax.violinplot(data, positions=range(5))
  3211. def test_violinplot_bad_widths():
  3212. ax = plt.axes()
  3213. # First 9 digits of frac(sqrt(53))
  3214. np.random.seed(280109889)
  3215. data = [np.random.normal(size=100) for _ in range(4)]
  3216. with pytest.raises(ValueError):
  3217. ax.violinplot(data, positions=range(4), widths=[1, 2, 3])
  3218. def test_violinplot_bad_quantiles():
  3219. ax = plt.axes()
  3220. # First 9 digits of frac(sqrt(73))
  3221. np.random.seed(544003745)
  3222. data = [np.random.normal(size=100)]
  3223. # Different size quantile list and plots
  3224. with pytest.raises(ValueError):
  3225. ax.violinplot(data, quantiles=[[0.1, 0.2], [0.5, 0.7]])
  3226. def test_violinplot_outofrange_quantiles():
  3227. ax = plt.axes()
  3228. # First 9 digits of frac(sqrt(79))
  3229. np.random.seed(888194417)
  3230. data = [np.random.normal(size=100)]
  3231. # Quantile value above 100
  3232. with pytest.raises(ValueError):
  3233. ax.violinplot(data, quantiles=[[0.1, 0.2, 0.3, 1.05]])
  3234. # Quantile value below 0
  3235. with pytest.raises(ValueError):
  3236. ax.violinplot(data, quantiles=[[-0.05, 0.2, 0.3, 0.75]])
  3237. @check_figures_equal(extensions=["png"])
  3238. def test_violinplot_single_list_quantiles(fig_test, fig_ref):
  3239. # Ensures quantile list for 1D can be passed in as single list
  3240. # First 9 digits of frac(sqrt(83))
  3241. np.random.seed(110433579)
  3242. data = [np.random.normal(size=100)]
  3243. # Test image
  3244. ax = fig_test.subplots()
  3245. ax.violinplot(data, quantiles=[0.1, 0.3, 0.9])
  3246. # Reference image
  3247. ax = fig_ref.subplots()
  3248. ax.violinplot(data, quantiles=[[0.1, 0.3, 0.9]])
  3249. @check_figures_equal(extensions=["png"])
  3250. def test_violinplot_pandas_series(fig_test, fig_ref, pd):
  3251. np.random.seed(110433579)
  3252. s1 = pd.Series(np.random.normal(size=7), index=[9, 8, 7, 6, 5, 4, 3])
  3253. s2 = pd.Series(np.random.normal(size=9), index=list('ABCDEFGHI'))
  3254. s3 = pd.Series(np.random.normal(size=11))
  3255. fig_test.subplots().violinplot([s1, s2, s3])
  3256. fig_ref.subplots().violinplot([s1.values, s2.values, s3.values])
  3257. def test_manage_xticks():
  3258. _, ax = plt.subplots()
  3259. ax.set_xlim(0, 4)
  3260. old_xlim = ax.get_xlim()
  3261. np.random.seed(0)
  3262. y1 = np.random.normal(10, 3, 20)
  3263. y2 = np.random.normal(3, 1, 20)
  3264. ax.boxplot([y1, y2], positions=[1, 2], manage_ticks=False)
  3265. new_xlim = ax.get_xlim()
  3266. assert_array_equal(old_xlim, new_xlim)
  3267. def test_boxplot_not_single():
  3268. fig, ax = plt.subplots()
  3269. ax.boxplot(np.random.rand(100), positions=[3])
  3270. ax.boxplot(np.random.rand(100), positions=[5])
  3271. fig.canvas.draw()
  3272. assert ax.get_xlim() == (2.5, 5.5)
  3273. assert list(ax.get_xticks()) == [3, 5]
  3274. assert [t.get_text() for t in ax.get_xticklabels()] == ["3", "5"]
  3275. def test_tick_space_size_0():
  3276. # allow font size to be zero, which affects ticks when there is
  3277. # no other text in the figure.
  3278. plt.plot([0, 1], [0, 1])
  3279. matplotlib.rcParams.update({'font.size': 0})
  3280. b = io.BytesIO()
  3281. plt.savefig(b, dpi=80, format='raw')
  3282. @image_comparison(['errorbar_basic.png', 'errorbar_mixed.png', 'errorbar_basic.png'])
  3283. def test_errorbar():
  3284. # longdouble due to floating point rounding issues with certain
  3285. # computer chipsets
  3286. x = np.arange(0.1, 4, 0.5, dtype=np.longdouble)
  3287. y = np.exp(-x)
  3288. yerr = 0.1 + 0.2*np.sqrt(x)
  3289. xerr = 0.1 + yerr
  3290. # First illustrate basic pyplot interface, using defaults where possible.
  3291. fig = plt.figure()
  3292. ax = fig.gca()
  3293. ax.errorbar(x, y, xerr=0.2, yerr=0.4)
  3294. ax.set_title("Simplest errorbars, 0.2 in x, 0.4 in y")
  3295. # Now switch to a more OO interface to exercise more features.
  3296. fig, axs = plt.subplots(nrows=2, ncols=2, sharex=True)
  3297. ax = axs[0, 0]
  3298. ax.errorbar(x, y, yerr=yerr, fmt='o')
  3299. ax.set_title('Vert. symmetric')
  3300. # With 4 subplots, reduce the number of axis ticks to avoid crowding.
  3301. ax.locator_params(nbins=4)
  3302. ax = axs[0, 1]
  3303. ax.errorbar(x, y, xerr=xerr, fmt='o', alpha=0.4)
  3304. ax.set_title('Hor. symmetric w/ alpha')
  3305. ax = axs[1, 0]
  3306. ax.errorbar(x, y, yerr=[yerr, 2*yerr], xerr=[xerr, 2*xerr], fmt='--o')
  3307. ax.set_title('H, V asymmetric')
  3308. ax = axs[1, 1]
  3309. ax.set_yscale('log')
  3310. # Here we have to be careful to keep all y values positive:
  3311. ylower = np.maximum(1e-2, y - yerr)
  3312. yerr_lower = y - ylower
  3313. ax.errorbar(x, y, yerr=[yerr_lower, 2*yerr], xerr=xerr,
  3314. fmt='o', ecolor='g', capthick=2)
  3315. ax.set_title('Mixed sym., log y')
  3316. # Force limits due to floating point slop potentially expanding the range
  3317. ax.set_ylim(1e-2, 1e1)
  3318. fig.suptitle('Variable errorbars')
  3319. # Reuse the first testcase from above for a labeled data test
  3320. data = {"x": x, "y": y}
  3321. fig = plt.figure()
  3322. ax = fig.gca()
  3323. ax.errorbar("x", "y", xerr=0.2, yerr=0.4, data=data)
  3324. ax.set_title("Simplest errorbars, 0.2 in x, 0.4 in y")
  3325. @image_comparison(['mixed_errorbar_polar_caps.png'], remove_text=True)
  3326. def test_mixed_errorbar_polar_caps():
  3327. """
  3328. Mix several polar errorbar use cases in a single test figure.
  3329. It is advisable to position individual points off the grid. If there are
  3330. problems with reproducibility of this test, consider removing grid.
  3331. """
  3332. fig = plt.figure()
  3333. ax = plt.subplot(111, projection='polar')
  3334. # symmetric errorbars
  3335. th_sym = [1, 2, 3]
  3336. r_sym = [0.9]*3
  3337. ax.errorbar(th_sym, r_sym, xerr=0.35, yerr=0.2, fmt="o")
  3338. # long errorbars
  3339. th_long = [np.pi/2 + .1, np.pi + .1]
  3340. r_long = [1.8, 2.2]
  3341. ax.errorbar(th_long, r_long, xerr=0.8 * np.pi, yerr=0.15, fmt="o")
  3342. # asymmetric errorbars
  3343. th_asym = [4*np.pi/3 + .1, 5*np.pi/3 + .1, 2*np.pi-0.1]
  3344. r_asym = [1.1]*3
  3345. xerr = [[.3, .3, .2], [.2, .3, .3]]
  3346. yerr = [[.35, .5, .5], [.5, .35, .5]]
  3347. ax.errorbar(th_asym, r_asym, xerr=xerr, yerr=yerr, fmt="o")
  3348. # overlapping errorbar
  3349. th_over = [2.1]
  3350. r_over = [3.1]
  3351. ax.errorbar(th_over, r_over, xerr=10, yerr=.2, fmt="o")
  3352. def test_errorbar_colorcycle():
  3353. f, ax = plt.subplots()
  3354. x = np.arange(10)
  3355. y = 2*x
  3356. e1, _, _ = ax.errorbar(x, y, c=None)
  3357. e2, _, _ = ax.errorbar(x, 2*y, c=None)
  3358. ln1, = ax.plot(x, 4*y)
  3359. assert mcolors.to_rgba(e1.get_color()) == mcolors.to_rgba('C0')
  3360. assert mcolors.to_rgba(e2.get_color()) == mcolors.to_rgba('C1')
  3361. assert mcolors.to_rgba(ln1.get_color()) == mcolors.to_rgba('C2')
  3362. @check_figures_equal(extensions=['png'])
  3363. def test_errorbar_cycle_ecolor(fig_test, fig_ref):
  3364. x = np.arange(0.1, 4, 0.5)
  3365. y = [np.exp(-x+n) for n in range(4)]
  3366. axt = fig_test.subplots()
  3367. axr = fig_ref.subplots()
  3368. for yi, color in zip(y, ['C0', 'C1', 'C2', 'C3']):
  3369. axt.errorbar(x, yi, yerr=(yi * 0.25), linestyle='-',
  3370. marker='o', ecolor='black')
  3371. axr.errorbar(x, yi, yerr=(yi * 0.25), linestyle='-',
  3372. marker='o', color=color, ecolor='black')
  3373. def test_errorbar_shape():
  3374. fig = plt.figure()
  3375. ax = fig.gca()
  3376. x = np.arange(0.1, 4, 0.5)
  3377. y = np.exp(-x)
  3378. yerr1 = 0.1 + 0.2*np.sqrt(x)
  3379. yerr = np.vstack((yerr1, 2*yerr1)).T
  3380. xerr = 0.1 + yerr
  3381. with pytest.raises(ValueError):
  3382. ax.errorbar(x, y, yerr=yerr, fmt='o')
  3383. with pytest.raises(ValueError):
  3384. ax.errorbar(x, y, xerr=xerr, fmt='o')
  3385. with pytest.raises(ValueError):
  3386. ax.errorbar(x, y, yerr=yerr, xerr=xerr, fmt='o')
  3387. @image_comparison(['errorbar_limits.png'])
  3388. def test_errorbar_limits():
  3389. x = np.arange(0.5, 5.5, 0.5)
  3390. y = np.exp(-x)
  3391. xerr = 0.1
  3392. yerr = 0.2
  3393. ls = 'dotted'
  3394. fig, ax = plt.subplots()
  3395. # standard error bars
  3396. ax.errorbar(x, y, xerr=xerr, yerr=yerr, ls=ls, color='blue')
  3397. # including upper limits
  3398. uplims = np.zeros_like(x)
  3399. uplims[[1, 5, 9]] = True
  3400. ax.errorbar(x, y+0.5, xerr=xerr, yerr=yerr, uplims=uplims, ls=ls,
  3401. color='green')
  3402. # including lower limits
  3403. lolims = np.zeros_like(x)
  3404. lolims[[2, 4, 8]] = True
  3405. ax.errorbar(x, y+1.0, xerr=xerr, yerr=yerr, lolims=lolims, ls=ls,
  3406. color='red')
  3407. # including upper and lower limits
  3408. ax.errorbar(x, y+1.5, marker='o', ms=8, xerr=xerr, yerr=yerr,
  3409. lolims=lolims, uplims=uplims, ls=ls, color='magenta')
  3410. # including xlower and xupper limits
  3411. xerr = 0.2
  3412. yerr = np.full_like(x, 0.2)
  3413. yerr[[3, 6]] = 0.3
  3414. xlolims = lolims
  3415. xuplims = uplims
  3416. lolims = np.zeros_like(x)
  3417. uplims = np.zeros_like(x)
  3418. lolims[[6]] = True
  3419. uplims[[3]] = True
  3420. ax.errorbar(x, y+2.1, marker='o', ms=8, xerr=xerr, yerr=yerr,
  3421. xlolims=xlolims, xuplims=xuplims, uplims=uplims,
  3422. lolims=lolims, ls='none', mec='blue', capsize=0,
  3423. color='cyan')
  3424. ax.set_xlim((0, 5.5))
  3425. ax.set_title('Errorbar upper and lower limits')
  3426. def test_errorbar_nonefmt():
  3427. # Check that passing 'none' as a format still plots errorbars
  3428. x = np.arange(5)
  3429. y = np.arange(5)
  3430. plotline, _, barlines = plt.errorbar(x, y, xerr=1, yerr=1, fmt='none')
  3431. assert plotline is None
  3432. for errbar in barlines:
  3433. assert np.all(errbar.get_color() == mcolors.to_rgba('C0'))
  3434. def test_errorbar_remove():
  3435. x = np.arange(5)
  3436. y = np.arange(5)
  3437. fig, ax = plt.subplots()
  3438. ec = ax.errorbar(x, y, xerr=1, yerr=1)
  3439. assert len(ax.containers) == 1
  3440. assert len(ax.lines) == 5
  3441. assert len(ax.collections) == 2
  3442. ec.remove()
  3443. assert not ax.containers
  3444. assert not ax.lines
  3445. assert not ax.collections
  3446. def test_errorbar_line_specific_kwargs():
  3447. # Check that passing line-specific keyword arguments will not result in
  3448. # errors.
  3449. x = np.arange(5)
  3450. y = np.arange(5)
  3451. plotline, _, _ = plt.errorbar(x, y, xerr=1, yerr=1, ls='None',
  3452. marker='s', fillstyle='full',
  3453. drawstyle='steps-mid',
  3454. dash_capstyle='round',
  3455. dash_joinstyle='miter',
  3456. solid_capstyle='butt',
  3457. solid_joinstyle='bevel')
  3458. assert plotline.get_fillstyle() == 'full'
  3459. assert plotline.get_drawstyle() == 'steps-mid'
  3460. @check_figures_equal(extensions=['png'])
  3461. def test_errorbar_with_prop_cycle(fig_test, fig_ref):
  3462. ax = fig_ref.subplots()
  3463. ax.errorbar(x=[2, 4, 10], y=[0, 1, 2], yerr=0.5,
  3464. ls='--', marker='s', mfc='k')
  3465. ax.errorbar(x=[2, 4, 10], y=[2, 3, 4], yerr=0.5, color='tab:green',
  3466. ls=':', marker='s', mfc='y')
  3467. ax.errorbar(x=[2, 4, 10], y=[4, 5, 6], yerr=0.5, fmt='tab:blue',
  3468. ls='-.', marker='o', mfc='c')
  3469. ax.set_xlim(1, 11)
  3470. _cycle = cycler(ls=['--', ':', '-.'], marker=['s', 's', 'o'],
  3471. mfc=['k', 'y', 'c'], color=['b', 'g', 'r'])
  3472. plt.rc("axes", prop_cycle=_cycle)
  3473. ax = fig_test.subplots()
  3474. ax.errorbar(x=[2, 4, 10], y=[0, 1, 2], yerr=0.5)
  3475. ax.errorbar(x=[2, 4, 10], y=[2, 3, 4], yerr=0.5, color='tab:green')
  3476. ax.errorbar(x=[2, 4, 10], y=[4, 5, 6], yerr=0.5, fmt='tab:blue')
  3477. ax.set_xlim(1, 11)
  3478. def test_errorbar_every_invalid():
  3479. x = np.linspace(0, 1, 15)
  3480. y = x * (1-x)
  3481. yerr = y/6
  3482. ax = plt.figure().subplots()
  3483. with pytest.raises(ValueError, match='not a tuple of two integers'):
  3484. ax.errorbar(x, y, yerr, errorevery=(1, 2, 3))
  3485. with pytest.raises(ValueError, match='not a tuple of two integers'):
  3486. ax.errorbar(x, y, yerr, errorevery=(1.3, 3))
  3487. with pytest.raises(ValueError, match='not a valid NumPy fancy index'):
  3488. ax.errorbar(x, y, yerr, errorevery=[False, True])
  3489. with pytest.raises(ValueError, match='not a recognized value'):
  3490. ax.errorbar(x, y, yerr, errorevery='foobar')
  3491. def test_xerr_yerr_not_negative():
  3492. ax = plt.figure().subplots()
  3493. with pytest.raises(ValueError,
  3494. match="'xerr' must not contain negative values"):
  3495. ax.errorbar(x=[0], y=[0], xerr=[[-0.5], [1]], yerr=[[-0.5], [1]])
  3496. with pytest.raises(ValueError,
  3497. match="'xerr' must not contain negative values"):
  3498. ax.errorbar(x=[0], y=[0], xerr=[[-0.5], [1]])
  3499. with pytest.raises(ValueError,
  3500. match="'yerr' must not contain negative values"):
  3501. ax.errorbar(x=[0], y=[0], yerr=[[-0.5], [1]])
  3502. with pytest.raises(ValueError,
  3503. match="'yerr' must not contain negative values"):
  3504. x = np.arange(5)
  3505. y = [datetime.datetime(2021, 9, i * 2 + 1) for i in x]
  3506. ax.errorbar(x=x,
  3507. y=y,
  3508. yerr=datetime.timedelta(days=-10))
  3509. def test_xerr_yerr_not_none():
  3510. ax = plt.figure().subplots()
  3511. with pytest.raises(ValueError,
  3512. match="'xerr' must not contain None"):
  3513. ax.errorbar(x=[0], y=[0], xerr=[[None], [1]], yerr=[[None], [1]])
  3514. with pytest.raises(ValueError,
  3515. match="'xerr' must not contain None"):
  3516. ax.errorbar(x=[0], y=[0], xerr=[[None], [1]])
  3517. with pytest.raises(ValueError,
  3518. match="'yerr' must not contain None"):
  3519. ax.errorbar(x=[0], y=[0], yerr=[[None], [1]])
  3520. @check_figures_equal(extensions=['png'])
  3521. def test_errorbar_every(fig_test, fig_ref):
  3522. x = np.linspace(0, 1, 15)
  3523. y = x * (1-x)
  3524. yerr = y/6
  3525. ax_ref = fig_ref.subplots()
  3526. ax_test = fig_test.subplots()
  3527. for color, shift in zip('rgbk', [0, 0, 2, 7]):
  3528. y += .02
  3529. # Check errorevery using an explicit offset and step.
  3530. ax_test.errorbar(x, y, yerr, errorevery=(shift, 4),
  3531. capsize=4, c=color)
  3532. # Using manual errorbars
  3533. # n.b. errorbar draws the main plot at z=2.1 by default
  3534. ax_ref.plot(x, y, c=color, zorder=2.1)
  3535. ax_ref.errorbar(x[shift::4], y[shift::4], yerr[shift::4],
  3536. capsize=4, c=color, fmt='none')
  3537. # Check that markevery is propagated to line, without affecting errorbars.
  3538. ax_test.errorbar(x, y + 0.1, yerr, markevery=(1, 4), capsize=4, fmt='o')
  3539. ax_ref.plot(x[1::4], y[1::4] + 0.1, 'o', zorder=2.1)
  3540. ax_ref.errorbar(x, y + 0.1, yerr, capsize=4, fmt='none')
  3541. # Check that passing a slice to markevery/errorevery works.
  3542. ax_test.errorbar(x, y + 0.2, yerr, errorevery=slice(2, None, 3),
  3543. markevery=slice(2, None, 3),
  3544. capsize=4, c='C0', fmt='o')
  3545. ax_ref.plot(x[2::3], y[2::3] + 0.2, 'o', c='C0', zorder=2.1)
  3546. ax_ref.errorbar(x[2::3], y[2::3] + 0.2, yerr[2::3],
  3547. capsize=4, c='C0', fmt='none')
  3548. # Check that passing an iterable to markevery/errorevery works.
  3549. ax_test.errorbar(x, y + 0.2, yerr, errorevery=[False, True, False] * 5,
  3550. markevery=[False, True, False] * 5,
  3551. capsize=4, c='C1', fmt='o')
  3552. ax_ref.plot(x[1::3], y[1::3] + 0.2, 'o', c='C1', zorder=2.1)
  3553. ax_ref.errorbar(x[1::3], y[1::3] + 0.2, yerr[1::3],
  3554. capsize=4, c='C1', fmt='none')
  3555. @pytest.mark.parametrize('elinewidth', [[1, 2, 3],
  3556. np.array([1, 2, 3]),
  3557. 1])
  3558. def test_errorbar_linewidth_type(elinewidth):
  3559. plt.errorbar([1, 2, 3], [1, 2, 3], yerr=[1, 2, 3], elinewidth=elinewidth)
  3560. @check_figures_equal(extensions=["png"])
  3561. def test_errorbar_nan(fig_test, fig_ref):
  3562. ax = fig_test.add_subplot()
  3563. xs = range(5)
  3564. ys = np.array([1, 2, np.nan, np.nan, 3])
  3565. es = np.array([4, 5, np.nan, np.nan, 6])
  3566. ax.errorbar(xs, ys, yerr=es)
  3567. ax = fig_ref.add_subplot()
  3568. ax.errorbar([0, 1], [1, 2], yerr=[4, 5])
  3569. ax.errorbar([4], [3], yerr=[6], fmt="C0")
  3570. @check_figures_equal()
  3571. def test_errorbar_masked_negative(fig_test, fig_ref):
  3572. ax = fig_test.add_subplot()
  3573. xs = range(5)
  3574. mask = np.array([False, False, True, True, False])
  3575. ys = np.ma.array([1, 2, 2, 2, 3], mask=mask)
  3576. es = np.ma.array([4, 5, -1, -10, 6], mask=mask)
  3577. ax.errorbar(xs, ys, yerr=es)
  3578. ax = fig_ref.add_subplot()
  3579. ax.errorbar([0, 1], [1, 2], yerr=[4, 5])
  3580. ax.errorbar([4], [3], yerr=[6], fmt="C0")
  3581. @image_comparison(['hist_stacked_stepfilled.png', 'hist_stacked_stepfilled.png'])
  3582. def test_hist_stacked_stepfilled():
  3583. # make some data
  3584. d1 = np.linspace(1, 3, 20)
  3585. d2 = np.linspace(0, 10, 50)
  3586. fig, ax = plt.subplots()
  3587. ax.hist((d1, d2), histtype="stepfilled", stacked=True)
  3588. # Reuse testcase from above for a labeled data test
  3589. data = {"x": (d1, d2)}
  3590. fig, ax = plt.subplots()
  3591. ax.hist("x", histtype="stepfilled", stacked=True, data=data)
  3592. @image_comparison(['hist_offset.png'])
  3593. def test_hist_offset():
  3594. # make some data
  3595. d1 = np.linspace(0, 10, 50)
  3596. d2 = np.linspace(1, 3, 20)
  3597. fig, ax = plt.subplots()
  3598. ax.hist(d1, bottom=5)
  3599. ax.hist(d2, bottom=15)
  3600. @image_comparison(['hist_step.png'], remove_text=True)
  3601. def test_hist_step():
  3602. # make some data
  3603. d1 = np.linspace(1, 3, 20)
  3604. fig, ax = plt.subplots()
  3605. ax.hist(d1, histtype="step")
  3606. ax.set_ylim(0, 10)
  3607. ax.set_xlim(-1, 5)
  3608. @image_comparison(['hist_step_horiz.png'])
  3609. def test_hist_step_horiz():
  3610. # make some data
  3611. d1 = np.linspace(0, 10, 50)
  3612. d2 = np.linspace(1, 3, 20)
  3613. fig, ax = plt.subplots()
  3614. ax.hist((d1, d2), histtype="step", orientation="horizontal")
  3615. @image_comparison(['hist_stacked_weights.png'])
  3616. def test_hist_stacked_weighted():
  3617. # make some data
  3618. d1 = np.linspace(0, 10, 50)
  3619. d2 = np.linspace(1, 3, 20)
  3620. w1 = np.linspace(0.01, 3.5, 50)
  3621. w2 = np.linspace(0.05, 2., 20)
  3622. fig, ax = plt.subplots()
  3623. ax.hist((d1, d2), weights=(w1, w2), histtype="stepfilled", stacked=True)
  3624. @image_comparison(['stem.png'], style='mpl20', remove_text=True)
  3625. def test_stem():
  3626. x = np.linspace(0.1, 2 * np.pi, 100)
  3627. fig, ax = plt.subplots()
  3628. # Label is a single space to force a legend to be drawn, but to avoid any
  3629. # text being drawn
  3630. ax.stem(x, np.cos(x),
  3631. linefmt='C2-.', markerfmt='k+', basefmt='C1-.', label=' ')
  3632. ax.legend()
  3633. def test_stem_args():
  3634. """Test that stem() correctly identifies x and y values."""
  3635. def _assert_equal(stem_container, expected):
  3636. x, y = map(list, stem_container.markerline.get_data())
  3637. assert x == expected[0]
  3638. assert y == expected[1]
  3639. fig, ax = plt.subplots()
  3640. x = [1, 3, 5]
  3641. y = [9, 8, 7]
  3642. # Test the call signatures
  3643. _assert_equal(ax.stem(y), expected=([0, 1, 2], y))
  3644. _assert_equal(ax.stem(x, y), expected=(x, y))
  3645. _assert_equal(ax.stem(x, y, linefmt='r--'), expected=(x, y))
  3646. _assert_equal(ax.stem(x, y, 'r--'), expected=(x, y))
  3647. _assert_equal(ax.stem(x, y, linefmt='r--', basefmt='b--'), expected=(x, y))
  3648. _assert_equal(ax.stem(y, linefmt='r--'), expected=([0, 1, 2], y))
  3649. _assert_equal(ax.stem(y, 'r--'), expected=([0, 1, 2], y))
  3650. with pytest.raises(ValueError):
  3651. ax.stem([[y]])
  3652. with pytest.raises(ValueError):
  3653. ax.stem([[x]], y)
  3654. def test_stem_markerfmt():
  3655. """Test that stem(..., markerfmt=...) produces the intended markers."""
  3656. def _assert_equal(stem_container, linecolor=None, markercolor=None,
  3657. marker=None):
  3658. """
  3659. Check that the given StemContainer has the properties listed as
  3660. keyword-arguments.
  3661. """
  3662. if linecolor is not None:
  3663. assert mcolors.same_color(
  3664. stem_container.stemlines.get_color(),
  3665. linecolor)
  3666. if markercolor is not None:
  3667. assert mcolors.same_color(
  3668. stem_container.markerline.get_color(),
  3669. markercolor)
  3670. if marker is not None:
  3671. assert stem_container.markerline.get_marker() == marker
  3672. assert stem_container.markerline.get_linestyle() == 'None'
  3673. fig, ax = plt.subplots()
  3674. x = [1, 3, 5]
  3675. y = [9, 8, 7]
  3676. # no linefmt
  3677. _assert_equal(ax.stem(x, y), markercolor='C0', marker='o')
  3678. _assert_equal(ax.stem(x, y, markerfmt='x'), markercolor='C0', marker='x')
  3679. _assert_equal(ax.stem(x, y, markerfmt='rx'), markercolor='r', marker='x')
  3680. # positional linefmt
  3681. _assert_equal(
  3682. ax.stem(x, y, 'r'), # marker color follows linefmt if not given
  3683. linecolor='r', markercolor='r', marker='o')
  3684. _assert_equal(
  3685. ax.stem(x, y, 'rx'), # the marker is currently not taken from linefmt
  3686. linecolor='r', markercolor='r', marker='o')
  3687. _assert_equal(
  3688. ax.stem(x, y, 'r', markerfmt='x'), # only marker type specified
  3689. linecolor='r', markercolor='r', marker='x')
  3690. _assert_equal(
  3691. ax.stem(x, y, 'r', markerfmt='g'), # only marker color specified
  3692. linecolor='r', markercolor='g', marker='o')
  3693. _assert_equal(
  3694. ax.stem(x, y, 'r', markerfmt='gx'), # marker type and color specified
  3695. linecolor='r', markercolor='g', marker='x')
  3696. _assert_equal(
  3697. ax.stem(x, y, 'r', markerfmt=' '), # markerfmt=' ' for no marker
  3698. linecolor='r', markercolor='r', marker='None')
  3699. _assert_equal(
  3700. ax.stem(x, y, 'r', markerfmt=''), # markerfmt='' for no marker
  3701. linecolor='r', markercolor='r', marker='None')
  3702. # with linefmt kwarg
  3703. _assert_equal(
  3704. ax.stem(x, y, linefmt='r'),
  3705. linecolor='r', markercolor='r', marker='o')
  3706. _assert_equal(
  3707. ax.stem(x, y, linefmt='r', markerfmt='x'),
  3708. linecolor='r', markercolor='r', marker='x')
  3709. _assert_equal(
  3710. ax.stem(x, y, linefmt='r', markerfmt='gx'),
  3711. linecolor='r', markercolor='g', marker='x')
  3712. def test_stem_dates():
  3713. fig, ax = plt.subplots(1, 1)
  3714. xs = [dateutil.parser.parse("2013-9-28 11:00:00"),
  3715. dateutil.parser.parse("2013-9-28 12:00:00")]
  3716. ys = [100, 200]
  3717. ax.stem(xs, ys)
  3718. @image_comparison(['stem_orientation.png'], style='mpl20', remove_text=True)
  3719. def test_stem_orientation():
  3720. x = np.linspace(0.1, 2*np.pi, 50)
  3721. fig, ax = plt.subplots()
  3722. ax.stem(x, np.cos(x),
  3723. linefmt='C2-.', markerfmt='kx', basefmt='C1-.',
  3724. orientation='horizontal')
  3725. @image_comparison(['hist_stacked_stepfilled_alpha.png'])
  3726. def test_hist_stacked_stepfilled_alpha():
  3727. # make some data
  3728. d1 = np.linspace(1, 3, 20)
  3729. d2 = np.linspace(0, 10, 50)
  3730. fig, ax = plt.subplots()
  3731. ax.hist((d1, d2), histtype="stepfilled", stacked=True, alpha=0.5)
  3732. @image_comparison(['hist_stacked_step.png'])
  3733. def test_hist_stacked_step():
  3734. # make some data
  3735. d1 = np.linspace(1, 3, 20)
  3736. d2 = np.linspace(0, 10, 50)
  3737. fig, ax = plt.subplots()
  3738. ax.hist((d1, d2), histtype="step", stacked=True)
  3739. @image_comparison(['hist_stacked_normed.png'])
  3740. def test_hist_stacked_density():
  3741. # make some data
  3742. d1 = np.linspace(1, 3, 20)
  3743. d2 = np.linspace(0, 10, 50)
  3744. fig, ax = plt.subplots()
  3745. ax.hist((d1, d2), stacked=True, density=True)
  3746. @image_comparison(['hist_step_bottom.png'], remove_text=True)
  3747. def test_hist_step_bottom():
  3748. # make some data
  3749. d1 = np.linspace(1, 3, 20)
  3750. fig, ax = plt.subplots()
  3751. ax.hist(d1, bottom=np.arange(10), histtype="stepfilled")
  3752. def test_hist_step_geometry():
  3753. bins = [0, 1, 2, 3]
  3754. data = [0, 0, 1, 1, 1, 2]
  3755. top = [[0, 0], [0, 2], [1, 2], [1, 3], [2, 3], [2, 1], [3, 1], [3, 0]]
  3756. bottom = [[2, 0], [2, 0], [1, 0], [1, 0], [0, 0]]
  3757. for histtype, xy in [('step', top), ('stepfilled', top + bottom)]:
  3758. _, _, (polygon, ) = plt.hist(data, bins=bins, histtype=histtype)
  3759. assert_array_equal(polygon.get_xy(), xy)
  3760. def test_hist_step_bottom_geometry():
  3761. bins = [0, 1, 2, 3]
  3762. data = [0, 0, 1, 1, 1, 2]
  3763. top = [[0, 1], [0, 3], [1, 3], [1, 5], [2, 5], [2, 2.5], [3, 2.5], [3, 1.5]]
  3764. bottom = [[2, 1.5], [2, 2], [1, 2], [1, 1], [0, 1]]
  3765. for histtype, xy in [('step', top), ('stepfilled', top + bottom)]:
  3766. _, _, (polygon, ) = plt.hist(data, bins=bins, bottom=[1, 2, 1.5],
  3767. histtype=histtype)
  3768. assert_array_equal(polygon.get_xy(), xy)
  3769. def test_hist_stacked_step_geometry():
  3770. bins = [0, 1, 2, 3]
  3771. data_1 = [0, 0, 1, 1, 1, 2]
  3772. data_2 = [0, 1, 2]
  3773. tops = [
  3774. [[0, 0], [0, 2], [1, 2], [1, 3], [2, 3], [2, 1], [3, 1], [3, 0]],
  3775. [[0, 2], [0, 3], [1, 3], [1, 4], [2, 4], [2, 2], [3, 2], [3, 1]],
  3776. ]
  3777. bottoms = [
  3778. [[2, 0], [2, 0], [1, 0], [1, 0], [0, 0]],
  3779. [[2, 1], [2, 3], [1, 3], [1, 2], [0, 2]],
  3780. ]
  3781. combined = [t + b for t, b in zip(tops, bottoms)]
  3782. for histtype, xy in [('step', tops), ('stepfilled', combined)]:
  3783. _, _, patches = plt.hist([data_1, data_2], bins=bins, stacked=True,
  3784. histtype=histtype)
  3785. assert len(patches) == 2
  3786. polygon, = patches[0]
  3787. assert_array_equal(polygon.get_xy(), xy[0])
  3788. polygon, = patches[1]
  3789. assert_array_equal(polygon.get_xy(), xy[1])
  3790. def test_hist_stacked_step_bottom_geometry():
  3791. bins = [0, 1, 2, 3]
  3792. data_1 = [0, 0, 1, 1, 1, 2]
  3793. data_2 = [0, 1, 2]
  3794. tops = [
  3795. [[0, 1], [0, 3], [1, 3], [1, 5], [2, 5], [2, 2.5], [3, 2.5], [3, 1.5]],
  3796. [[0, 3], [0, 4], [1, 4], [1, 6], [2, 6], [2, 3.5], [3, 3.5], [3, 2.5]],
  3797. ]
  3798. bottoms = [
  3799. [[2, 1.5], [2, 2], [1, 2], [1, 1], [0, 1]],
  3800. [[2, 2.5], [2, 5], [1, 5], [1, 3], [0, 3]],
  3801. ]
  3802. combined = [t + b for t, b in zip(tops, bottoms)]
  3803. for histtype, xy in [('step', tops), ('stepfilled', combined)]:
  3804. _, _, patches = plt.hist([data_1, data_2], bins=bins, stacked=True,
  3805. bottom=[1, 2, 1.5], histtype=histtype)
  3806. assert len(patches) == 2
  3807. polygon, = patches[0]
  3808. assert_array_equal(polygon.get_xy(), xy[0])
  3809. polygon, = patches[1]
  3810. assert_array_equal(polygon.get_xy(), xy[1])
  3811. @image_comparison(['hist_stacked_bar.png'])
  3812. def test_hist_stacked_bar():
  3813. # make some data
  3814. d = [[100, 100, 100, 100, 200, 320, 450, 80, 20, 600, 310, 800],
  3815. [20, 23, 50, 11, 100, 420], [120, 120, 120, 140, 140, 150, 180],
  3816. [60, 60, 60, 60, 300, 300, 5, 5, 5, 5, 10, 300],
  3817. [555, 555, 555, 30, 30, 30, 30, 30, 100, 100, 100, 100, 30, 30],
  3818. [30, 30, 30, 30, 400, 400, 400, 400, 400, 400, 400, 400]]
  3819. colors = [(0.5759849696758961, 1.0, 0.0), (0.0, 1.0, 0.350624650815206),
  3820. (0.0, 1.0, 0.6549834156005998), (0.0, 0.6569064625276622, 1.0),
  3821. (0.28302699607823545, 0.0, 1.0), (0.6849123462299822, 0.0, 1.0)]
  3822. labels = ['green', 'orange', ' yellow', 'magenta', 'black']
  3823. fig, ax = plt.subplots()
  3824. ax.hist(d, bins=10, histtype='barstacked', align='mid', color=colors,
  3825. label=labels)
  3826. ax.legend(loc='upper right', bbox_to_anchor=(1.0, 1.0), ncols=1)
  3827. @pytest.mark.parametrize('kwargs', ({'facecolor': ["b", "g", "r"]},
  3828. {'edgecolor': ["b", "g", "r"]},
  3829. {'hatch': ["/", "\\", "."]},
  3830. {'linestyle': ["-", "--", ":"]},
  3831. {'linewidth': [1, 1.5, 2]},
  3832. {'color': ["b", "g", "r"]}))
  3833. @check_figures_equal(extensions=["png"])
  3834. def test_hist_vectorized_params(fig_test, fig_ref, kwargs):
  3835. np.random.seed(19680801)
  3836. xs = [np.random.randn(n) for n in [20, 50, 100]]
  3837. (axt1, axt2) = fig_test.subplots(2)
  3838. (axr1, axr2) = fig_ref.subplots(2)
  3839. for histtype, axt, axr in [("stepfilled", axt1, axr1), ("step", axt2, axr2)]:
  3840. _, bins, _ = axt.hist(xs, bins=10, histtype=histtype, **kwargs)
  3841. kw, values = next(iter(kwargs.items()))
  3842. for i, (x, value) in enumerate(zip(xs, values)):
  3843. axr.hist(x, bins=bins, histtype=histtype, **{kw: value},
  3844. zorder=(len(xs)-i)/2)
  3845. def test_hist_sequence_type_styles():
  3846. facecolor = ('r', 0.5)
  3847. edgecolor = [0.5, 0.5, 0.5]
  3848. linestyle = (0, (1, 1))
  3849. arr = np.random.uniform(size=50)
  3850. _, _, bars = plt.hist(arr, facecolor=facecolor, edgecolor=edgecolor,
  3851. linestyle=linestyle)
  3852. assert mcolors.same_color(bars[0].get_facecolor(), facecolor)
  3853. assert mcolors.same_color(bars[0].get_edgecolor(), edgecolor)
  3854. assert bars[0].get_linestyle() == linestyle
  3855. def test_hist_color_none():
  3856. arr = np.random.uniform(size=50)
  3857. # No edgecolor is the default but check that it can be explicitly passed.
  3858. _, _, bars = plt.hist(arr, facecolor='none', edgecolor='none')
  3859. assert bars[0].get_facecolor(), (0, 0, 0, 0)
  3860. assert bars[0].get_edgecolor(), (0, 0, 0, 0)
  3861. @pytest.mark.parametrize('kwargs, patch_face, patch_edge',
  3862. # 'C0'(blue) stands for the first color of the
  3863. # default color cycle as well as the patch.facecolor rcParam
  3864. # When the expected edgecolor is 'k'(black),
  3865. # it corresponds to the patch.edgecolor rcParam
  3866. [({'histtype': 'stepfilled', 'color': 'r',
  3867. 'facecolor': 'y', 'edgecolor': 'g'}, 'y', 'g'),
  3868. ({'histtype': 'step', 'color': 'r',
  3869. 'facecolor': 'y', 'edgecolor': 'g'}, ('y', 0), 'g'),
  3870. ({'histtype': 'stepfilled', 'color': 'r',
  3871. 'edgecolor': 'g'}, 'r', 'g'),
  3872. ({'histtype': 'step', 'color': 'r',
  3873. 'edgecolor': 'g'}, ('r', 0), 'g'),
  3874. ({'histtype': 'stepfilled', 'color': 'r',
  3875. 'facecolor': 'y'}, 'y', 'k'),
  3876. ({'histtype': 'step', 'color': 'r',
  3877. 'facecolor': 'y'}, ('y', 0), 'r'),
  3878. ({'histtype': 'stepfilled',
  3879. 'facecolor': 'y', 'edgecolor': 'g'}, 'y', 'g'),
  3880. ({'histtype': 'step', 'facecolor': 'y',
  3881. 'edgecolor': 'g'}, ('y', 0), 'g'),
  3882. ({'histtype': 'stepfilled', 'color': 'r'}, 'r', 'k'),
  3883. ({'histtype': 'step', 'color': 'r'}, ('r', 0), 'r'),
  3884. ({'histtype': 'stepfilled', 'facecolor': 'y'}, 'y', 'k'),
  3885. ({'histtype': 'step', 'facecolor': 'y'}, ('y', 0), 'C0'),
  3886. ({'histtype': 'stepfilled', 'edgecolor': 'g'}, 'C0', 'g'),
  3887. ({'histtype': 'step', 'edgecolor': 'g'}, ('C0', 0), 'g'),
  3888. ({'histtype': 'stepfilled'}, 'C0', 'k'),
  3889. ({'histtype': 'step'}, ('C0', 0), 'C0')])
  3890. def test_hist_color_semantics(kwargs, patch_face, patch_edge):
  3891. _, _, patches = plt.figure().subplots().hist([1, 2, 3], **kwargs)
  3892. assert all(mcolors.same_color([p.get_facecolor(), p.get_edgecolor()],
  3893. [patch_face, patch_edge]) for p in patches)
  3894. def test_hist_barstacked_bottom_unchanged():
  3895. b = np.array([10, 20])
  3896. plt.hist([[0, 1], [0, 1]], 2, histtype="barstacked", bottom=b)
  3897. assert b.tolist() == [10, 20]
  3898. def test_hist_emptydata():
  3899. fig, ax = plt.subplots()
  3900. ax.hist([[], range(10), range(10)], histtype="step")
  3901. def test_hist_unused_labels():
  3902. # When a list with one dataset and N elements is provided and N labels, ensure
  3903. # that the first label is used for the dataset and all other labels are ignored
  3904. fig, ax = plt.subplots()
  3905. ax.hist([[1, 2, 3]], label=["values", "unused", "also unused"])
  3906. _, labels = ax.get_legend_handles_labels()
  3907. assert labels == ["values"]
  3908. def test_hist_labels():
  3909. # test singleton labels OK
  3910. fig, ax = plt.subplots()
  3911. _, _, bars = ax.hist([0, 1], label=0)
  3912. assert bars[0].get_label() == '0'
  3913. _, _, bars = ax.hist([0, 1], label=[0])
  3914. assert bars[0].get_label() == '0'
  3915. _, _, bars = ax.hist([0, 1], label=None)
  3916. assert bars[0].get_label() == '_nolegend_'
  3917. _, _, bars = ax.hist([0, 1], label='0')
  3918. assert bars[0].get_label() == '0'
  3919. _, _, bars = ax.hist([0, 1], label='00')
  3920. assert bars[0].get_label() == '00'
  3921. @image_comparison(['transparent_markers'], remove_text=True)
  3922. def test_transparent_markers():
  3923. np.random.seed(0)
  3924. data = np.random.random(50)
  3925. fig, ax = plt.subplots()
  3926. ax.plot(data, 'D', mfc='none', markersize=100)
  3927. @image_comparison(['rgba_markers'], remove_text=True)
  3928. def test_rgba_markers():
  3929. fig, axs = plt.subplots(ncols=2)
  3930. rcolors = [(1, 0, 0, 1), (1, 0, 0, 0.5)]
  3931. bcolors = [(0, 0, 1, 1), (0, 0, 1, 0.5)]
  3932. alphas = [None, 0.2]
  3933. kw = dict(ms=100, mew=20)
  3934. for i, alpha in enumerate(alphas):
  3935. for j, rcolor in enumerate(rcolors):
  3936. for k, bcolor in enumerate(bcolors):
  3937. axs[i].plot(j+1, k+1, 'o', mfc=bcolor, mec=rcolor,
  3938. alpha=alpha, **kw)
  3939. axs[i].plot(j+1, k+3, 'x', mec=rcolor, alpha=alpha, **kw)
  3940. for ax in axs:
  3941. ax.axis([-1, 4, 0, 5])
  3942. @image_comparison(['mollweide_grid.png'], remove_text=True)
  3943. def test_mollweide_grid():
  3944. # test that both horizontal and vertical gridlines appear on the Mollweide
  3945. # projection
  3946. fig = plt.figure()
  3947. ax = fig.add_subplot(projection='mollweide')
  3948. ax.grid()
  3949. def test_mollweide_forward_inverse_closure():
  3950. # test that the round-trip Mollweide forward->inverse transformation is an
  3951. # approximate identity
  3952. fig = plt.figure()
  3953. ax = fig.add_subplot(projection='mollweide')
  3954. # set up 1-degree grid in longitude, latitude
  3955. lon = np.linspace(-np.pi, np.pi, 360)
  3956. # The poles are degenerate and thus sensitive to floating point precision errors
  3957. lat = np.linspace(-np.pi / 2.0, np.pi / 2.0, 180)[1:-1]
  3958. lon, lat = np.meshgrid(lon, lat)
  3959. ll = np.vstack((lon.flatten(), lat.flatten())).T
  3960. # perform forward transform
  3961. xy = ax.transProjection.transform(ll)
  3962. # perform inverse transform
  3963. ll2 = ax.transProjection.inverted().transform(xy)
  3964. # compare
  3965. np.testing.assert_array_almost_equal(ll, ll2, 3)
  3966. def test_mollweide_inverse_forward_closure():
  3967. # test that the round-trip Mollweide inverse->forward transformation is an
  3968. # approximate identity
  3969. fig = plt.figure()
  3970. ax = fig.add_subplot(projection='mollweide')
  3971. # set up grid in x, y
  3972. x = np.linspace(0, 1, 500)
  3973. x, y = np.meshgrid(x, x)
  3974. xy = np.vstack((x.flatten(), y.flatten())).T
  3975. # perform inverse transform
  3976. ll = ax.transProjection.inverted().transform(xy)
  3977. # perform forward transform
  3978. xy2 = ax.transProjection.transform(ll)
  3979. # compare
  3980. np.testing.assert_array_almost_equal(xy, xy2, 3)
  3981. @image_comparison(['test_alpha'], remove_text=True)
  3982. def test_alpha():
  3983. np.random.seed(0)
  3984. data = np.random.random(50)
  3985. fig, ax = plt.subplots()
  3986. # alpha=.5 markers, solid line
  3987. ax.plot(data, '-D', color=[1, 0, 0], mfc=[1, 0, 0, .5],
  3988. markersize=20, lw=10)
  3989. # everything solid by kwarg
  3990. ax.plot(data + 2, '-D', color=[1, 0, 0, .5], mfc=[1, 0, 0, .5],
  3991. markersize=20, lw=10,
  3992. alpha=1)
  3993. # everything alpha=.5 by kwarg
  3994. ax.plot(data + 4, '-D', color=[1, 0, 0], mfc=[1, 0, 0],
  3995. markersize=20, lw=10,
  3996. alpha=.5)
  3997. # everything alpha=.5 by colors
  3998. ax.plot(data + 6, '-D', color=[1, 0, 0, .5], mfc=[1, 0, 0, .5],
  3999. markersize=20, lw=10)
  4000. # alpha=.5 line, solid markers
  4001. ax.plot(data + 8, '-D', color=[1, 0, 0, .5], mfc=[1, 0, 0],
  4002. markersize=20, lw=10)
  4003. @image_comparison(['eventplot.png', 'eventplot.png'], remove_text=True)
  4004. def test_eventplot():
  4005. np.random.seed(0)
  4006. data1 = np.random.random([32, 20]).tolist()
  4007. data2 = np.random.random([6, 20]).tolist()
  4008. data = data1 + data2
  4009. num_datasets = len(data)
  4010. colors1 = [[0, 1, .7]] * len(data1)
  4011. colors2 = [[1, 0, 0],
  4012. [0, 1, 0],
  4013. [0, 0, 1],
  4014. [1, .75, 0],
  4015. [1, 0, 1],
  4016. [0, 1, 1]]
  4017. colors = colors1 + colors2
  4018. lineoffsets1 = 12 + np.arange(0, len(data1)) * .33
  4019. lineoffsets2 = [-15, -3, 1, 1.5, 6, 10]
  4020. lineoffsets = lineoffsets1.tolist() + lineoffsets2
  4021. linelengths1 = [.33] * len(data1)
  4022. linelengths2 = [5, 2, 1, 1, 3, 1.5]
  4023. linelengths = linelengths1 + linelengths2
  4024. fig = plt.figure()
  4025. axobj = fig.add_subplot()
  4026. colls = axobj.eventplot(data, colors=colors, lineoffsets=lineoffsets,
  4027. linelengths=linelengths)
  4028. num_collections = len(colls)
  4029. assert num_collections == num_datasets
  4030. # Reuse testcase from above for a labeled data test
  4031. data = {"pos": data, "c": colors, "lo": lineoffsets, "ll": linelengths}
  4032. fig = plt.figure()
  4033. axobj = fig.add_subplot()
  4034. colls = axobj.eventplot("pos", colors="c", lineoffsets="lo",
  4035. linelengths="ll", data=data)
  4036. num_collections = len(colls)
  4037. assert num_collections == num_datasets
  4038. @image_comparison(['test_eventplot_defaults.png'], remove_text=True)
  4039. def test_eventplot_defaults():
  4040. """
  4041. test that eventplot produces the correct output given the default params
  4042. (see bug #3728)
  4043. """
  4044. np.random.seed(0)
  4045. data1 = np.random.random([32, 20]).tolist()
  4046. data2 = np.random.random([6, 20]).tolist()
  4047. data = data1 + data2
  4048. fig = plt.figure()
  4049. axobj = fig.add_subplot()
  4050. axobj.eventplot(data)
  4051. @pytest.mark.parametrize(('colors'), [
  4052. ('0.5',), # string color with multiple characters: not OK before #8193 fix
  4053. ('tab:orange', 'tab:pink', 'tab:cyan', 'bLacK'), # case-insensitive
  4054. ('red', (0, 1, 0), None, (1, 0, 1, 0.5)), # a tricky case mixing types
  4055. ])
  4056. def test_eventplot_colors(colors):
  4057. """Test the *colors* parameter of eventplot. Inspired by issue #8193."""
  4058. data = [[0], [1], [2], [3]] # 4 successive events of different nature
  4059. # Build the list of the expected colors
  4060. expected = [c if c is not None else 'C0' for c in colors]
  4061. # Convert the list into an array of RGBA values
  4062. # NB: ['rgbk'] is not a valid argument for to_rgba_array, while 'rgbk' is.
  4063. if len(expected) == 1:
  4064. expected = expected[0]
  4065. expected = np.broadcast_to(mcolors.to_rgba_array(expected), (len(data), 4))
  4066. fig, ax = plt.subplots()
  4067. if len(colors) == 1: # tuple with a single string (like '0.5' or 'rgbk')
  4068. colors = colors[0]
  4069. collections = ax.eventplot(data, colors=colors)
  4070. for coll, color in zip(collections, expected):
  4071. assert_allclose(coll.get_color(), color)
  4072. def test_eventplot_alpha():
  4073. fig, ax = plt.subplots()
  4074. # one alpha for all
  4075. collections = ax.eventplot([[0, 2, 4], [1, 3, 5, 7]], alpha=0.7)
  4076. assert collections[0].get_alpha() == 0.7
  4077. assert collections[1].get_alpha() == 0.7
  4078. # one alpha per collection
  4079. collections = ax.eventplot([[0, 2, 4], [1, 3, 5, 7]], alpha=[0.5, 0.7])
  4080. assert collections[0].get_alpha() == 0.5
  4081. assert collections[1].get_alpha() == 0.7
  4082. with pytest.raises(ValueError, match="alpha and positions are unequal"):
  4083. ax.eventplot([[0, 2, 4], [1, 3, 5, 7]], alpha=[0.5, 0.7, 0.9])
  4084. with pytest.raises(ValueError, match="alpha and positions are unequal"):
  4085. ax.eventplot([0, 2, 4], alpha=[0.5, 0.7])
  4086. @image_comparison(['test_eventplot_problem_kwargs.png'], remove_text=True)
  4087. def test_eventplot_problem_kwargs(recwarn):
  4088. """
  4089. test that 'singular' versions of LineCollection props raise an
  4090. MatplotlibDeprecationWarning rather than overriding the 'plural' versions
  4091. (e.g., to prevent 'color' from overriding 'colors', see issue #4297)
  4092. """
  4093. np.random.seed(0)
  4094. data1 = np.random.random([20]).tolist()
  4095. data2 = np.random.random([10]).tolist()
  4096. data = [data1, data2]
  4097. fig = plt.figure()
  4098. axobj = fig.add_subplot()
  4099. axobj.eventplot(data,
  4100. colors=['r', 'b'],
  4101. color=['c', 'm'],
  4102. linewidths=[2, 1],
  4103. linewidth=[1, 2],
  4104. linestyles=['solid', 'dashed'],
  4105. linestyle=['dashdot', 'dotted'])
  4106. assert len(recwarn) == 3
  4107. assert all(issubclass(wi.category, mpl.MatplotlibDeprecationWarning)
  4108. for wi in recwarn)
  4109. def test_empty_eventplot():
  4110. fig, ax = plt.subplots(1, 1)
  4111. ax.eventplot([[]], colors=[(0.0, 0.0, 0.0, 0.0)])
  4112. plt.draw()
  4113. @pytest.mark.parametrize('data', [[[]], [[], [0, 1]], [[0, 1], []]])
  4114. @pytest.mark.parametrize('orientation', [None, 'vertical', 'horizontal'])
  4115. def test_eventplot_orientation(data, orientation):
  4116. """Introduced when fixing issue #6412."""
  4117. opts = {} if orientation is None else {'orientation': orientation}
  4118. fig, ax = plt.subplots(1, 1)
  4119. ax.eventplot(data, **opts)
  4120. plt.draw()
  4121. @check_figures_equal(extensions=['png'])
  4122. def test_eventplot_units_list(fig_test, fig_ref):
  4123. # test that list of lists converted properly:
  4124. ts_1 = [datetime.datetime(2021, 1, 1), datetime.datetime(2021, 1, 2),
  4125. datetime.datetime(2021, 1, 3)]
  4126. ts_2 = [datetime.datetime(2021, 1, 15), datetime.datetime(2021, 1, 16)]
  4127. ax = fig_ref.subplots()
  4128. ax.eventplot(ts_1, lineoffsets=0)
  4129. ax.eventplot(ts_2, lineoffsets=1)
  4130. ax = fig_test.subplots()
  4131. ax.eventplot([ts_1, ts_2])
  4132. @image_comparison(['marker_styles.png'], remove_text=True)
  4133. def test_marker_styles():
  4134. fig, ax = plt.subplots()
  4135. # Since generation of the test image, None was removed but 'none' was
  4136. # added. By moving 'none' to the front (=former sorted place of None)
  4137. # we can avoid regenerating the test image. This can be removed if the
  4138. # test image has to be regenerated for other reasons.
  4139. markers = sorted(matplotlib.markers.MarkerStyle.markers,
  4140. key=lambda x: str(type(x))+str(x))
  4141. markers.remove('none')
  4142. markers = ['none', *markers]
  4143. for y, marker in enumerate(markers):
  4144. ax.plot((y % 2)*5 + np.arange(10)*10, np.ones(10)*10*y, linestyle='',
  4145. marker=marker, markersize=10+y/5, label=marker)
  4146. @image_comparison(['rc_markerfill.png'],
  4147. tol=0 if platform.machine() == 'x86_64' else 0.037)
  4148. def test_markers_fillstyle_rcparams():
  4149. fig, ax = plt.subplots()
  4150. x = np.arange(7)
  4151. for idx, (style, marker) in enumerate(
  4152. [('top', 's'), ('bottom', 'o'), ('none', '^')]):
  4153. matplotlib.rcParams['markers.fillstyle'] = style
  4154. ax.plot(x+idx, marker=marker)
  4155. @image_comparison(['vertex_markers.png'], remove_text=True)
  4156. def test_vertex_markers():
  4157. data = list(range(10))
  4158. marker_as_tuple = ((-1, -1), (1, -1), (1, 1), (-1, 1))
  4159. marker_as_list = [(-1, -1), (1, -1), (1, 1), (-1, 1)]
  4160. fig, ax = plt.subplots()
  4161. ax.plot(data, linestyle='', marker=marker_as_tuple, mfc='k')
  4162. ax.plot(data[::-1], linestyle='', marker=marker_as_list, mfc='b')
  4163. ax.set_xlim([-1, 10])
  4164. ax.set_ylim([-1, 10])
  4165. @image_comparison(['vline_hline_zorder.png', 'errorbar_zorder.png'],
  4166. tol=0 if platform.machine() == 'x86_64' else 0.026)
  4167. def test_eb_line_zorder():
  4168. x = list(range(10))
  4169. # First illustrate basic pyplot interface, using defaults where possible.
  4170. fig = plt.figure()
  4171. ax = fig.gca()
  4172. ax.plot(x, lw=10, zorder=5)
  4173. ax.axhline(1, color='red', lw=10, zorder=1)
  4174. ax.axhline(5, color='green', lw=10, zorder=10)
  4175. ax.axvline(7, color='m', lw=10, zorder=7)
  4176. ax.axvline(2, color='k', lw=10, zorder=3)
  4177. ax.set_title("axvline and axhline zorder test")
  4178. # Now switch to a more OO interface to exercise more features.
  4179. fig = plt.figure()
  4180. ax = fig.gca()
  4181. x = list(range(10))
  4182. y = np.zeros(10)
  4183. yerr = list(range(10))
  4184. ax.errorbar(x, y, yerr=yerr, zorder=5, lw=5, color='r')
  4185. for j in range(10):
  4186. ax.axhline(j, lw=5, color='k', zorder=j)
  4187. ax.axhline(-j, lw=5, color='k', zorder=j)
  4188. ax.set_title("errorbar zorder test")
  4189. @check_figures_equal(extensions=['png'])
  4190. def test_axline_loglog(fig_test, fig_ref):
  4191. ax = fig_test.subplots()
  4192. ax.set(xlim=(0.1, 10), ylim=(1e-3, 1))
  4193. ax.loglog([.3, .6], [.3, .6], ".-")
  4194. ax.axline((1, 1e-3), (10, 1e-2), c="k")
  4195. ax = fig_ref.subplots()
  4196. ax.set(xlim=(0.1, 10), ylim=(1e-3, 1))
  4197. ax.loglog([.3, .6], [.3, .6], ".-")
  4198. ax.loglog([1, 10], [1e-3, 1e-2], c="k")
  4199. @check_figures_equal(extensions=['png'])
  4200. def test_axline(fig_test, fig_ref):
  4201. ax = fig_test.subplots()
  4202. ax.set(xlim=(-1, 1), ylim=(-1, 1))
  4203. ax.axline((0, 0), (1, 1))
  4204. ax.axline((0, 0), (1, 0), color='C1')
  4205. ax.axline((0, 0.5), (1, 0.5), color='C2')
  4206. # slopes
  4207. ax.axline((-0.7, -0.5), slope=0, color='C3')
  4208. ax.axline((1, -0.5), slope=-0.5, color='C4')
  4209. ax.axline((-0.5, 1), slope=float('inf'), color='C5')
  4210. ax = fig_ref.subplots()
  4211. ax.set(xlim=(-1, 1), ylim=(-1, 1))
  4212. ax.plot([-1, 1], [-1, 1])
  4213. ax.axhline(0, color='C1')
  4214. ax.axhline(0.5, color='C2')
  4215. # slopes
  4216. ax.axhline(-0.5, color='C3')
  4217. ax.plot([-1, 1], [0.5, -0.5], color='C4')
  4218. ax.axvline(-0.5, color='C5')
  4219. @check_figures_equal(extensions=['png'])
  4220. def test_axline_transaxes(fig_test, fig_ref):
  4221. ax = fig_test.subplots()
  4222. ax.set(xlim=(-1, 1), ylim=(-1, 1))
  4223. ax.axline((0, 0), slope=1, transform=ax.transAxes)
  4224. ax.axline((1, 0.5), slope=1, color='C1', transform=ax.transAxes)
  4225. ax.axline((0.5, 0.5), slope=0, color='C2', transform=ax.transAxes)
  4226. ax.axline((0.5, 0), (0.5, 1), color='C3', transform=ax.transAxes)
  4227. ax = fig_ref.subplots()
  4228. ax.set(xlim=(-1, 1), ylim=(-1, 1))
  4229. ax.plot([-1, 1], [-1, 1])
  4230. ax.plot([0, 1], [-1, 0], color='C1')
  4231. ax.plot([-1, 1], [0, 0], color='C2')
  4232. ax.plot([0, 0], [-1, 1], color='C3')
  4233. @check_figures_equal(extensions=['png'])
  4234. def test_axline_transaxes_panzoom(fig_test, fig_ref):
  4235. # test that it is robust against pan/zoom and
  4236. # figure resize after plotting
  4237. ax = fig_test.subplots()
  4238. ax.set(xlim=(-1, 1), ylim=(-1, 1))
  4239. ax.axline((0, 0), slope=1, transform=ax.transAxes)
  4240. ax.axline((0.5, 0.5), slope=2, color='C1', transform=ax.transAxes)
  4241. ax.axline((0.5, 0.5), slope=0, color='C2', transform=ax.transAxes)
  4242. ax.set(xlim=(0, 5), ylim=(0, 10))
  4243. fig_test.set_size_inches(3, 3)
  4244. ax = fig_ref.subplots()
  4245. ax.set(xlim=(0, 5), ylim=(0, 10))
  4246. fig_ref.set_size_inches(3, 3)
  4247. ax.plot([0, 5], [0, 5])
  4248. ax.plot([0, 5], [0, 10], color='C1')
  4249. ax.plot([0, 5], [5, 5], color='C2')
  4250. def test_axline_args():
  4251. """Exactly one of *xy2* and *slope* must be specified."""
  4252. fig, ax = plt.subplots()
  4253. with pytest.raises(TypeError):
  4254. ax.axline((0, 0)) # missing second parameter
  4255. with pytest.raises(TypeError):
  4256. ax.axline((0, 0), (1, 1), slope=1) # redundant parameters
  4257. ax.set_xscale('log')
  4258. with pytest.raises(TypeError):
  4259. ax.axline((0, 0), slope=1)
  4260. ax.set_xscale('linear')
  4261. ax.set_yscale('log')
  4262. with pytest.raises(TypeError):
  4263. ax.axline((0, 0), slope=1)
  4264. ax.set_yscale('linear')
  4265. with pytest.raises(ValueError):
  4266. ax.axline((0, 0), (0, 0)) # two identical points are not allowed
  4267. plt.draw()
  4268. @image_comparison(['vlines_basic', 'vlines_with_nan', 'vlines_masked'],
  4269. extensions=['png'])
  4270. def test_vlines():
  4271. # normal
  4272. x1 = [2, 3, 4, 5, 7]
  4273. y1 = [2, -6, 3, 8, 2]
  4274. fig1, ax1 = plt.subplots()
  4275. ax1.vlines(x1, 0, y1, colors='g', linewidth=5)
  4276. # GH #7406
  4277. x2 = [2, 3, 4, 5, 6, 7]
  4278. y2 = [2, -6, 3, 8, np.nan, 2]
  4279. fig2, (ax2, ax3, ax4) = plt.subplots(nrows=3, figsize=(4, 8))
  4280. ax2.vlines(x2, 0, y2, colors='g', linewidth=5)
  4281. x3 = [2, 3, 4, 5, 6, 7]
  4282. y3 = [np.nan, 2, -6, 3, 8, 2]
  4283. ax3.vlines(x3, 0, y3, colors='r', linewidth=3, linestyle='--')
  4284. x4 = [2, 3, 4, 5, 6, 7]
  4285. y4 = [np.nan, 2, -6, 3, 8, np.nan]
  4286. ax4.vlines(x4, 0, y4, colors='k', linewidth=2)
  4287. # tweak the x-axis so we can see the lines better
  4288. for ax in [ax1, ax2, ax3, ax4]:
  4289. ax.set_xlim(0, 10)
  4290. # check that the y-lims are all automatically the same
  4291. assert ax1.get_ylim() == ax2.get_ylim()
  4292. assert ax1.get_ylim() == ax3.get_ylim()
  4293. assert ax1.get_ylim() == ax4.get_ylim()
  4294. fig3, ax5 = plt.subplots()
  4295. x5 = np.ma.masked_equal([2, 4, 6, 8, 10, 12], 8)
  4296. ymin5 = np.ma.masked_equal([0, 1, -1, 0, 2, 1], 2)
  4297. ymax5 = np.ma.masked_equal([13, 14, 15, 16, 17, 18], 18)
  4298. ax5.vlines(x5, ymin5, ymax5, colors='k', linewidth=2)
  4299. ax5.set_xlim(0, 15)
  4300. def test_vlines_default():
  4301. fig, ax = plt.subplots()
  4302. with mpl.rc_context({'lines.color': 'red'}):
  4303. lines = ax.vlines(0.5, 0, 1)
  4304. assert mpl.colors.same_color(lines.get_color(), 'red')
  4305. @image_comparison(['hlines_basic', 'hlines_with_nan', 'hlines_masked'],
  4306. extensions=['png'])
  4307. def test_hlines():
  4308. # normal
  4309. y1 = [2, 3, 4, 5, 7]
  4310. x1 = [2, -6, 3, 8, 2]
  4311. fig1, ax1 = plt.subplots()
  4312. ax1.hlines(y1, 0, x1, colors='g', linewidth=5)
  4313. # GH #7406
  4314. y2 = [2, 3, 4, 5, 6, 7]
  4315. x2 = [2, -6, 3, 8, np.nan, 2]
  4316. fig2, (ax2, ax3, ax4) = plt.subplots(nrows=3, figsize=(4, 8))
  4317. ax2.hlines(y2, 0, x2, colors='g', linewidth=5)
  4318. y3 = [2, 3, 4, 5, 6, 7]
  4319. x3 = [np.nan, 2, -6, 3, 8, 2]
  4320. ax3.hlines(y3, 0, x3, colors='r', linewidth=3, linestyle='--')
  4321. y4 = [2, 3, 4, 5, 6, 7]
  4322. x4 = [np.nan, 2, -6, 3, 8, np.nan]
  4323. ax4.hlines(y4, 0, x4, colors='k', linewidth=2)
  4324. # tweak the y-axis so we can see the lines better
  4325. for ax in [ax1, ax2, ax3, ax4]:
  4326. ax.set_ylim(0, 10)
  4327. # check that the x-lims are all automatically the same
  4328. assert ax1.get_xlim() == ax2.get_xlim()
  4329. assert ax1.get_xlim() == ax3.get_xlim()
  4330. assert ax1.get_xlim() == ax4.get_xlim()
  4331. fig3, ax5 = plt.subplots()
  4332. y5 = np.ma.masked_equal([2, 4, 6, 8, 10, 12], 8)
  4333. xmin5 = np.ma.masked_equal([0, 1, -1, 0, 2, 1], 2)
  4334. xmax5 = np.ma.masked_equal([13, 14, 15, 16, 17, 18], 18)
  4335. ax5.hlines(y5, xmin5, xmax5, colors='k', linewidth=2)
  4336. ax5.set_ylim(0, 15)
  4337. def test_hlines_default():
  4338. fig, ax = plt.subplots()
  4339. with mpl.rc_context({'lines.color': 'red'}):
  4340. lines = ax.hlines(0.5, 0, 1)
  4341. assert mpl.colors.same_color(lines.get_color(), 'red')
  4342. @pytest.mark.parametrize('data', [[1, 2, 3, np.nan, 5],
  4343. np.ma.masked_equal([1, 2, 3, 4, 5], 4)])
  4344. @check_figures_equal(extensions=["png"])
  4345. def test_lines_with_colors(fig_test, fig_ref, data):
  4346. test_colors = ['red', 'green', 'blue', 'purple', 'orange']
  4347. fig_test.add_subplot(2, 1, 1).vlines(data, 0, 1,
  4348. colors=test_colors, linewidth=5)
  4349. fig_test.add_subplot(2, 1, 2).hlines(data, 0, 1,
  4350. colors=test_colors, linewidth=5)
  4351. expect_xy = [1, 2, 3, 5]
  4352. expect_color = ['red', 'green', 'blue', 'orange']
  4353. fig_ref.add_subplot(2, 1, 1).vlines(expect_xy, 0, 1,
  4354. colors=expect_color, linewidth=5)
  4355. fig_ref.add_subplot(2, 1, 2).hlines(expect_xy, 0, 1,
  4356. colors=expect_color, linewidth=5)
  4357. @image_comparison(['vlines_hlines_blended_transform'],
  4358. extensions=['png'], style='mpl20')
  4359. def test_vlines_hlines_blended_transform():
  4360. t = np.arange(5.0, 10.0, 0.1)
  4361. s = np.exp(-t) + np.sin(2 * np.pi * t) + 10
  4362. fig, (hax, vax) = plt.subplots(2, 1, figsize=(6, 6))
  4363. hax.plot(t, s, '^')
  4364. hax.hlines([10, 9], xmin=0, xmax=0.5,
  4365. transform=hax.get_yaxis_transform(), colors='r')
  4366. vax.plot(t, s, '^')
  4367. vax.vlines([6, 7], ymin=0, ymax=0.15, transform=vax.get_xaxis_transform(),
  4368. colors='r')
  4369. @image_comparison(['step_linestyle', 'step_linestyle'], remove_text=True,
  4370. tol=0.2)
  4371. def test_step_linestyle():
  4372. # Tolerance caused by reordering of floating-point operations
  4373. # Remove when regenerating the images
  4374. x = y = np.arange(10)
  4375. # First illustrate basic pyplot interface, using defaults where possible.
  4376. fig, ax_lst = plt.subplots(2, 2)
  4377. ax_lst = ax_lst.flatten()
  4378. ln_styles = ['-', '--', '-.', ':']
  4379. for ax, ls in zip(ax_lst, ln_styles):
  4380. ax.step(x, y, lw=5, linestyle=ls, where='pre')
  4381. ax.step(x, y + 1, lw=5, linestyle=ls, where='mid')
  4382. ax.step(x, y + 2, lw=5, linestyle=ls, where='post')
  4383. ax.set_xlim([-1, 5])
  4384. ax.set_ylim([-1, 7])
  4385. # Reuse testcase from above for a labeled data test
  4386. data = {"X": x, "Y0": y, "Y1": y+1, "Y2": y+2}
  4387. fig, ax_lst = plt.subplots(2, 2)
  4388. ax_lst = ax_lst.flatten()
  4389. ln_styles = ['-', '--', '-.', ':']
  4390. for ax, ls in zip(ax_lst, ln_styles):
  4391. ax.step("X", "Y0", lw=5, linestyle=ls, where='pre', data=data)
  4392. ax.step("X", "Y1", lw=5, linestyle=ls, where='mid', data=data)
  4393. ax.step("X", "Y2", lw=5, linestyle=ls, where='post', data=data)
  4394. ax.set_xlim([-1, 5])
  4395. ax.set_ylim([-1, 7])
  4396. @image_comparison(['mixed_collection'], remove_text=True)
  4397. def test_mixed_collection():
  4398. # First illustrate basic pyplot interface, using defaults where possible.
  4399. fig, ax = plt.subplots()
  4400. c = mpatches.Circle((8, 8), radius=4, facecolor='none', edgecolor='green')
  4401. # PDF can optimize this one
  4402. p1 = mpl.collections.PatchCollection([c], match_original=True)
  4403. p1.set_offsets([[0, 0], [24, 24]])
  4404. p1.set_linewidths([1, 5])
  4405. # PDF can't optimize this one, because the alpha of the edge changes
  4406. p2 = mpl.collections.PatchCollection([c], match_original=True)
  4407. p2.set_offsets([[48, 0], [-32, -16]])
  4408. p2.set_linewidths([1, 5])
  4409. p2.set_edgecolors([[0, 0, 0.1, 1.0], [0, 0, 0.1, 0.5]])
  4410. ax.patch.set_color('0.5')
  4411. ax.add_collection(p1)
  4412. ax.add_collection(p2)
  4413. ax.set_xlim(0, 16)
  4414. ax.set_ylim(0, 16)
  4415. def test_subplot_key_hash():
  4416. ax = plt.subplot(np.int32(5), np.int64(1), 1)
  4417. ax.twinx()
  4418. assert ax.get_subplotspec().get_geometry() == (5, 1, 0, 0)
  4419. @image_comparison(
  4420. ["specgram_freqs.png", "specgram_freqs_linear.png",
  4421. "specgram_noise.png", "specgram_noise_linear.png"],
  4422. remove_text=True, tol=0.07, style="default")
  4423. def test_specgram():
  4424. """Test axes.specgram in default (psd) mode."""
  4425. # use former defaults to match existing baseline image
  4426. matplotlib.rcParams['image.interpolation'] = 'nearest'
  4427. n = 1000
  4428. Fs = 10.
  4429. fstims = [[Fs/4, Fs/5, Fs/11], [Fs/4.7, Fs/5.6, Fs/11.9]]
  4430. NFFT_freqs = int(10 * Fs / np.min(fstims))
  4431. x = np.arange(0, n, 1/Fs)
  4432. y_freqs = np.concatenate(
  4433. np.sin(2 * np.pi * np.multiply.outer(fstims, x)).sum(axis=1))
  4434. NFFT_noise = int(10 * Fs / 11)
  4435. np.random.seed(0)
  4436. y_noise = np.concatenate([np.random.standard_normal(n), np.random.rand(n)])
  4437. all_sides = ["default", "onesided", "twosided"]
  4438. for y, NFFT in [(y_freqs, NFFT_freqs), (y_noise, NFFT_noise)]:
  4439. noverlap = NFFT // 2
  4440. pad_to = int(2 ** np.ceil(np.log2(NFFT)))
  4441. for ax, sides in zip(plt.figure().subplots(3), all_sides):
  4442. ax.specgram(y, NFFT=NFFT, Fs=Fs, noverlap=noverlap,
  4443. pad_to=pad_to, sides=sides)
  4444. for ax, sides in zip(plt.figure().subplots(3), all_sides):
  4445. ax.specgram(y, NFFT=NFFT, Fs=Fs, noverlap=noverlap,
  4446. pad_to=pad_to, sides=sides,
  4447. scale="linear", norm=matplotlib.colors.LogNorm())
  4448. @image_comparison(
  4449. ["specgram_magnitude_freqs.png", "specgram_magnitude_freqs_linear.png",
  4450. "specgram_magnitude_noise.png", "specgram_magnitude_noise_linear.png"],
  4451. remove_text=True, tol=0.07, style="default")
  4452. def test_specgram_magnitude():
  4453. """Test axes.specgram in magnitude mode."""
  4454. # use former defaults to match existing baseline image
  4455. matplotlib.rcParams['image.interpolation'] = 'nearest'
  4456. n = 1000
  4457. Fs = 10.
  4458. fstims = [[Fs/4, Fs/5, Fs/11], [Fs/4.7, Fs/5.6, Fs/11.9]]
  4459. NFFT_freqs = int(100 * Fs / np.min(fstims))
  4460. x = np.arange(0, n, 1/Fs)
  4461. y = np.sin(2 * np.pi * np.multiply.outer(fstims, x)).sum(axis=1)
  4462. y[:, -1] = 1
  4463. y_freqs = np.hstack(y)
  4464. NFFT_noise = int(10 * Fs / 11)
  4465. np.random.seed(0)
  4466. y_noise = np.concatenate([np.random.standard_normal(n), np.random.rand(n)])
  4467. all_sides = ["default", "onesided", "twosided"]
  4468. for y, NFFT in [(y_freqs, NFFT_freqs), (y_noise, NFFT_noise)]:
  4469. noverlap = NFFT // 2
  4470. pad_to = int(2 ** np.ceil(np.log2(NFFT)))
  4471. for ax, sides in zip(plt.figure().subplots(3), all_sides):
  4472. ax.specgram(y, NFFT=NFFT, Fs=Fs, noverlap=noverlap,
  4473. pad_to=pad_to, sides=sides, mode="magnitude")
  4474. for ax, sides in zip(plt.figure().subplots(3), all_sides):
  4475. ax.specgram(y, NFFT=NFFT, Fs=Fs, noverlap=noverlap,
  4476. pad_to=pad_to, sides=sides, mode="magnitude",
  4477. scale="linear", norm=matplotlib.colors.LogNorm())
  4478. @image_comparison(
  4479. ["specgram_angle_freqs.png", "specgram_phase_freqs.png",
  4480. "specgram_angle_noise.png", "specgram_phase_noise.png"],
  4481. remove_text=True, tol=0.07, style="default")
  4482. def test_specgram_angle():
  4483. """Test axes.specgram in angle and phase modes."""
  4484. # use former defaults to match existing baseline image
  4485. matplotlib.rcParams['image.interpolation'] = 'nearest'
  4486. n = 1000
  4487. Fs = 10.
  4488. fstims = [[Fs/4, Fs/5, Fs/11], [Fs/4.7, Fs/5.6, Fs/11.9]]
  4489. NFFT_freqs = int(10 * Fs / np.min(fstims))
  4490. x = np.arange(0, n, 1/Fs)
  4491. y = np.sin(2 * np.pi * np.multiply.outer(fstims, x)).sum(axis=1)
  4492. y[:, -1] = 1
  4493. y_freqs = np.hstack(y)
  4494. NFFT_noise = int(10 * Fs / 11)
  4495. np.random.seed(0)
  4496. y_noise = np.concatenate([np.random.standard_normal(n), np.random.rand(n)])
  4497. all_sides = ["default", "onesided", "twosided"]
  4498. for y, NFFT in [(y_freqs, NFFT_freqs), (y_noise, NFFT_noise)]:
  4499. noverlap = NFFT // 2
  4500. pad_to = int(2 ** np.ceil(np.log2(NFFT)))
  4501. for mode in ["angle", "phase"]:
  4502. for ax, sides in zip(plt.figure().subplots(3), all_sides):
  4503. ax.specgram(y, NFFT=NFFT, Fs=Fs, noverlap=noverlap,
  4504. pad_to=pad_to, sides=sides, mode=mode)
  4505. with pytest.raises(ValueError):
  4506. ax.specgram(y, NFFT=NFFT, Fs=Fs, noverlap=noverlap,
  4507. pad_to=pad_to, sides=sides, mode=mode,
  4508. scale="dB")
  4509. def test_specgram_fs_none():
  4510. """Test axes.specgram when Fs is None, should not throw error."""
  4511. spec, freqs, t, im = plt.specgram(np.ones(300), Fs=None, scale='linear')
  4512. xmin, xmax, freq0, freq1 = im.get_extent()
  4513. assert xmin == 32 and xmax == 96
  4514. @check_figures_equal(extensions=["png"])
  4515. def test_specgram_origin_rcparam(fig_test, fig_ref):
  4516. """Test specgram ignores image.origin rcParam and uses origin 'upper'."""
  4517. t = np.arange(500)
  4518. signal = np.sin(t)
  4519. plt.rcParams["image.origin"] = 'upper'
  4520. # Reference: First graph using default origin in imshow (upper),
  4521. fig_ref.subplots().specgram(signal)
  4522. # Try to overwrite the setting trying to flip the specgram
  4523. plt.rcParams["image.origin"] = 'lower'
  4524. # Test: origin='lower' should be ignored
  4525. fig_test.subplots().specgram(signal)
  4526. def test_specgram_origin_kwarg():
  4527. """Ensure passing origin as a kwarg raises a TypeError."""
  4528. t = np.arange(500)
  4529. signal = np.sin(t)
  4530. with pytest.raises(TypeError):
  4531. plt.specgram(signal, origin='lower')
  4532. @image_comparison(
  4533. ["psd_freqs.png", "csd_freqs.png", "psd_noise.png", "csd_noise.png"],
  4534. remove_text=True, tol=0.002)
  4535. def test_psd_csd():
  4536. n = 10000
  4537. Fs = 100.
  4538. fstims = [[Fs/4, Fs/5, Fs/11], [Fs/4.7, Fs/5.6, Fs/11.9]]
  4539. NFFT_freqs = int(1000 * Fs / np.min(fstims))
  4540. x = np.arange(0, n, 1/Fs)
  4541. ys_freqs = np.sin(2 * np.pi * np.multiply.outer(fstims, x)).sum(axis=1)
  4542. NFFT_noise = int(1000 * Fs / 11)
  4543. np.random.seed(0)
  4544. ys_noise = [np.random.standard_normal(n), np.random.rand(n)]
  4545. all_kwargs = [{"sides": "default"},
  4546. {"sides": "onesided", "return_line": False},
  4547. {"sides": "twosided", "return_line": True}]
  4548. for ys, NFFT in [(ys_freqs, NFFT_freqs), (ys_noise, NFFT_noise)]:
  4549. noverlap = NFFT // 2
  4550. pad_to = int(2 ** np.ceil(np.log2(NFFT)))
  4551. for ax, kwargs in zip(plt.figure().subplots(3), all_kwargs):
  4552. ret = ax.psd(np.concatenate(ys), NFFT=NFFT, Fs=Fs,
  4553. noverlap=noverlap, pad_to=pad_to, **kwargs)
  4554. assert len(ret) == 2 + kwargs.get("return_line", False)
  4555. ax.set(xlabel="", ylabel="")
  4556. for ax, kwargs in zip(plt.figure().subplots(3), all_kwargs):
  4557. ret = ax.csd(*ys, NFFT=NFFT, Fs=Fs,
  4558. noverlap=noverlap, pad_to=pad_to, **kwargs)
  4559. assert len(ret) == 2 + kwargs.get("return_line", False)
  4560. ax.set(xlabel="", ylabel="")
  4561. @image_comparison(
  4562. ["magnitude_spectrum_freqs_linear.png",
  4563. "magnitude_spectrum_freqs_dB.png",
  4564. "angle_spectrum_freqs.png",
  4565. "phase_spectrum_freqs.png",
  4566. "magnitude_spectrum_noise_linear.png",
  4567. "magnitude_spectrum_noise_dB.png",
  4568. "angle_spectrum_noise.png",
  4569. "phase_spectrum_noise.png"],
  4570. remove_text=True)
  4571. def test_spectrum():
  4572. n = 10000
  4573. Fs = 100.
  4574. fstims1 = [Fs/4, Fs/5, Fs/11]
  4575. NFFT = int(1000 * Fs / min(fstims1))
  4576. pad_to = int(2 ** np.ceil(np.log2(NFFT)))
  4577. x = np.arange(0, n, 1/Fs)
  4578. y_freqs = ((np.sin(2 * np.pi * np.outer(x, fstims1)) * 10**np.arange(3))
  4579. .sum(axis=1))
  4580. np.random.seed(0)
  4581. y_noise = np.hstack([np.random.standard_normal(n), np.random.rand(n)]) - .5
  4582. all_sides = ["default", "onesided", "twosided"]
  4583. kwargs = {"Fs": Fs, "pad_to": pad_to}
  4584. for y in [y_freqs, y_noise]:
  4585. for ax, sides in zip(plt.figure().subplots(3), all_sides):
  4586. spec, freqs, line = ax.magnitude_spectrum(y, sides=sides, **kwargs)
  4587. ax.set(xlabel="", ylabel="")
  4588. for ax, sides in zip(plt.figure().subplots(3), all_sides):
  4589. spec, freqs, line = ax.magnitude_spectrum(y, sides=sides, **kwargs,
  4590. scale="dB")
  4591. ax.set(xlabel="", ylabel="")
  4592. for ax, sides in zip(plt.figure().subplots(3), all_sides):
  4593. spec, freqs, line = ax.angle_spectrum(y, sides=sides, **kwargs)
  4594. ax.set(xlabel="", ylabel="")
  4595. for ax, sides in zip(plt.figure().subplots(3), all_sides):
  4596. spec, freqs, line = ax.phase_spectrum(y, sides=sides, **kwargs)
  4597. ax.set(xlabel="", ylabel="")
  4598. def test_psd_csd_edge_cases():
  4599. # Inverted yaxis or fully zero inputs used to throw exceptions.
  4600. axs = plt.figure().subplots(2)
  4601. for ax in axs:
  4602. ax.yaxis.set(inverted=True)
  4603. with np.errstate(divide="ignore"):
  4604. axs[0].psd(np.zeros(5))
  4605. axs[1].csd(np.zeros(5), np.zeros(5))
  4606. @check_figures_equal(extensions=['png'])
  4607. def test_twin_remove(fig_test, fig_ref):
  4608. ax_test = fig_test.add_subplot()
  4609. ax_twinx = ax_test.twinx()
  4610. ax_twiny = ax_test.twiny()
  4611. ax_twinx.remove()
  4612. ax_twiny.remove()
  4613. ax_ref = fig_ref.add_subplot()
  4614. # Ideally we also undo tick changes when calling ``remove()``, but for now
  4615. # manually set the ticks of the reference image to match the test image
  4616. ax_ref.xaxis.tick_bottom()
  4617. ax_ref.yaxis.tick_left()
  4618. @image_comparison(['twin_spines.png'], remove_text=True,
  4619. tol=0 if platform.machine() == 'x86_64' else 0.022)
  4620. def test_twin_spines():
  4621. def make_patch_spines_invisible(ax):
  4622. ax.set_frame_on(True)
  4623. ax.patch.set_visible(False)
  4624. ax.spines[:].set_visible(False)
  4625. fig = plt.figure(figsize=(4, 3))
  4626. fig.subplots_adjust(right=0.75)
  4627. host = fig.add_subplot()
  4628. par1 = host.twinx()
  4629. par2 = host.twinx()
  4630. # Offset the right spine of par2. The ticks and label have already been
  4631. # placed on the right by twinx above.
  4632. par2.spines.right.set_position(("axes", 1.2))
  4633. # Having been created by twinx, par2 has its frame off, so the line of
  4634. # its detached spine is invisible. First, activate the frame but make
  4635. # the patch and spines invisible.
  4636. make_patch_spines_invisible(par2)
  4637. # Second, show the right spine.
  4638. par2.spines.right.set_visible(True)
  4639. p1, = host.plot([0, 1, 2], [0, 1, 2], "b-")
  4640. p2, = par1.plot([0, 1, 2], [0, 3, 2], "r-")
  4641. p3, = par2.plot([0, 1, 2], [50, 30, 15], "g-")
  4642. host.set_xlim(0, 2)
  4643. host.set_ylim(0, 2)
  4644. par1.set_ylim(0, 4)
  4645. par2.set_ylim(1, 65)
  4646. host.yaxis.label.set_color(p1.get_color())
  4647. par1.yaxis.label.set_color(p2.get_color())
  4648. par2.yaxis.label.set_color(p3.get_color())
  4649. tkw = dict(size=4, width=1.5)
  4650. host.tick_params(axis='y', colors=p1.get_color(), **tkw)
  4651. par1.tick_params(axis='y', colors=p2.get_color(), **tkw)
  4652. par2.tick_params(axis='y', colors=p3.get_color(), **tkw)
  4653. host.tick_params(axis='x', **tkw)
  4654. @image_comparison(['twin_spines_on_top.png', 'twin_spines_on_top.png'],
  4655. remove_text=True)
  4656. def test_twin_spines_on_top():
  4657. matplotlib.rcParams['axes.linewidth'] = 48.0
  4658. matplotlib.rcParams['lines.linewidth'] = 48.0
  4659. fig = plt.figure()
  4660. ax1 = fig.add_subplot(1, 1, 1)
  4661. data = np.array([[1000, 1100, 1200, 1250],
  4662. [310, 301, 360, 400]])
  4663. ax2 = ax1.twinx()
  4664. ax1.plot(data[0], data[1]/1E3, color='#BEAED4')
  4665. ax1.fill_between(data[0], data[1]/1E3, color='#BEAED4', alpha=.8)
  4666. ax2.plot(data[0], data[1]/1E3, color='#7FC97F')
  4667. ax2.fill_between(data[0], data[1]/1E3, color='#7FC97F', alpha=.5)
  4668. # Reuse testcase from above for a labeled data test
  4669. data = {"i": data[0], "j": data[1]/1E3}
  4670. fig = plt.figure()
  4671. ax1 = fig.add_subplot(1, 1, 1)
  4672. ax2 = ax1.twinx()
  4673. ax1.plot("i", "j", color='#BEAED4', data=data)
  4674. ax1.fill_between("i", "j", color='#BEAED4', alpha=.8, data=data)
  4675. ax2.plot("i", "j", color='#7FC97F', data=data)
  4676. ax2.fill_between("i", "j", color='#7FC97F', alpha=.5, data=data)
  4677. @pytest.mark.parametrize("grid_which, major_visible, minor_visible", [
  4678. ("both", True, True),
  4679. ("major", True, False),
  4680. ("minor", False, True),
  4681. ])
  4682. def test_rcparam_grid_minor(grid_which, major_visible, minor_visible):
  4683. mpl.rcParams.update({"axes.grid": True, "axes.grid.which": grid_which})
  4684. fig, ax = plt.subplots()
  4685. fig.canvas.draw()
  4686. assert all(tick.gridline.get_visible() == major_visible
  4687. for tick in ax.xaxis.majorTicks)
  4688. assert all(tick.gridline.get_visible() == minor_visible
  4689. for tick in ax.xaxis.minorTicks)
  4690. def test_grid():
  4691. fig, ax = plt.subplots()
  4692. ax.grid()
  4693. fig.canvas.draw()
  4694. assert ax.xaxis.majorTicks[0].gridline.get_visible()
  4695. ax.grid(visible=False)
  4696. fig.canvas.draw()
  4697. assert not ax.xaxis.majorTicks[0].gridline.get_visible()
  4698. ax.grid(visible=True)
  4699. fig.canvas.draw()
  4700. assert ax.xaxis.majorTicks[0].gridline.get_visible()
  4701. ax.grid()
  4702. fig.canvas.draw()
  4703. assert not ax.xaxis.majorTicks[0].gridline.get_visible()
  4704. def test_reset_grid():
  4705. fig, ax = plt.subplots()
  4706. ax.tick_params(reset=True, which='major', labelsize=10)
  4707. assert not ax.xaxis.majorTicks[0].gridline.get_visible()
  4708. ax.grid(color='red') # enables grid
  4709. assert ax.xaxis.majorTicks[0].gridline.get_visible()
  4710. with plt.rc_context({'axes.grid': True}):
  4711. ax.clear()
  4712. ax.tick_params(reset=True, which='major', labelsize=10)
  4713. assert ax.xaxis.majorTicks[0].gridline.get_visible()
  4714. @check_figures_equal(extensions=['png'])
  4715. def test_reset_ticks(fig_test, fig_ref):
  4716. for fig in [fig_ref, fig_test]:
  4717. ax = fig.add_subplot()
  4718. ax.grid(True)
  4719. ax.tick_params(
  4720. direction='in', length=10, width=5, color='C0', pad=12,
  4721. labelsize=14, labelcolor='C1', labelrotation=45,
  4722. grid_color='C2', grid_alpha=0.8, grid_linewidth=3,
  4723. grid_linestyle='--')
  4724. fig.draw_without_rendering()
  4725. # After we've changed any setting on ticks, reset_ticks will mean
  4726. # re-creating them from scratch. This *should* appear the same as not
  4727. # resetting them.
  4728. for ax in fig_test.axes:
  4729. ax.xaxis.reset_ticks()
  4730. ax.yaxis.reset_ticks()
  4731. @mpl.style.context('mpl20')
  4732. def test_context_ticks():
  4733. with plt.rc_context({
  4734. 'xtick.direction': 'in', 'xtick.major.size': 30, 'xtick.major.width': 5,
  4735. 'xtick.color': 'C0', 'xtick.major.pad': 12,
  4736. 'xtick.bottom': True, 'xtick.top': True,
  4737. 'xtick.labelsize': 14, 'xtick.labelcolor': 'C1'}):
  4738. fig, ax = plt.subplots()
  4739. # Draw outside the context so that all-but-first tick are generated with the normal
  4740. # mpl20 style in place.
  4741. fig.draw_without_rendering()
  4742. first_tick = ax.xaxis.majorTicks[0]
  4743. for tick in ax.xaxis.majorTicks[1:]:
  4744. assert tick._size == first_tick._size
  4745. assert tick._width == first_tick._width
  4746. assert tick._base_pad == first_tick._base_pad
  4747. assert tick._labelrotation == first_tick._labelrotation
  4748. assert tick._zorder == first_tick._zorder
  4749. assert tick._tickdir == first_tick._tickdir
  4750. def test_vline_limit():
  4751. fig = plt.figure()
  4752. ax = fig.gca()
  4753. ax.axvline(0.5)
  4754. ax.plot([-0.1, 0, 0.2, 0.1])
  4755. assert_allclose(ax.get_ylim(), (-.1, .2))
  4756. @pytest.mark.parametrize('fv, fh, args', [[plt.axvline, plt.axhline, (1,)],
  4757. [plt.axvspan, plt.axhspan, (1, 1)]])
  4758. def test_axline_minmax(fv, fh, args):
  4759. bad_lim = matplotlib.dates.num2date(1)
  4760. # Check vertical functions
  4761. with pytest.raises(ValueError, match='ymin must be a single scalar value'):
  4762. fv(*args, ymin=bad_lim, ymax=1)
  4763. with pytest.raises(ValueError, match='ymax must be a single scalar value'):
  4764. fv(*args, ymin=1, ymax=bad_lim)
  4765. # Check horizontal functions
  4766. with pytest.raises(ValueError, match='xmin must be a single scalar value'):
  4767. fh(*args, xmin=bad_lim, xmax=1)
  4768. with pytest.raises(ValueError, match='xmax must be a single scalar value'):
  4769. fh(*args, xmin=1, xmax=bad_lim)
  4770. def test_empty_shared_subplots():
  4771. # empty plots with shared axes inherit limits from populated plots
  4772. fig, axs = plt.subplots(nrows=1, ncols=2, sharex=True, sharey=True)
  4773. axs[0].plot([1, 2, 3], [2, 4, 6])
  4774. x0, x1 = axs[1].get_xlim()
  4775. y0, y1 = axs[1].get_ylim()
  4776. assert x0 <= 1
  4777. assert x1 >= 3
  4778. assert y0 <= 2
  4779. assert y1 >= 6
  4780. def test_shared_with_aspect_1():
  4781. # allow sharing one axis
  4782. for adjustable in ['box', 'datalim']:
  4783. fig, axs = plt.subplots(nrows=2, sharex=True)
  4784. axs[0].set_aspect(2, adjustable=adjustable, share=True)
  4785. assert axs[1].get_aspect() == 2
  4786. assert axs[1].get_adjustable() == adjustable
  4787. fig, axs = plt.subplots(nrows=2, sharex=True)
  4788. axs[0].set_aspect(2, adjustable=adjustable)
  4789. assert axs[1].get_aspect() == 'auto'
  4790. def test_shared_with_aspect_2():
  4791. # Share 2 axes only with 'box':
  4792. fig, axs = plt.subplots(nrows=2, sharex=True, sharey=True)
  4793. axs[0].set_aspect(2, share=True)
  4794. axs[0].plot([1, 2], [3, 4])
  4795. axs[1].plot([3, 4], [1, 2])
  4796. plt.draw() # Trigger apply_aspect().
  4797. assert axs[0].get_xlim() == axs[1].get_xlim()
  4798. assert axs[0].get_ylim() == axs[1].get_ylim()
  4799. def test_shared_with_aspect_3():
  4800. # Different aspect ratios:
  4801. for adjustable in ['box', 'datalim']:
  4802. fig, axs = plt.subplots(nrows=2, sharey=True)
  4803. axs[0].set_aspect(2, adjustable=adjustable)
  4804. axs[1].set_aspect(0.5, adjustable=adjustable)
  4805. axs[0].plot([1, 2], [3, 4])
  4806. axs[1].plot([3, 4], [1, 2])
  4807. plt.draw() # Trigger apply_aspect().
  4808. assert axs[0].get_xlim() != axs[1].get_xlim()
  4809. assert axs[0].get_ylim() == axs[1].get_ylim()
  4810. fig_aspect = fig.bbox_inches.height / fig.bbox_inches.width
  4811. for ax in axs:
  4812. p = ax.get_position()
  4813. box_aspect = p.height / p.width
  4814. lim_aspect = ax.viewLim.height / ax.viewLim.width
  4815. expected = fig_aspect * box_aspect / lim_aspect
  4816. assert round(expected, 4) == round(ax.get_aspect(), 4)
  4817. def test_shared_aspect_error():
  4818. fig, axes = plt.subplots(1, 2, sharex=True, sharey=True)
  4819. axes[0].axis("equal")
  4820. with pytest.raises(RuntimeError, match=r"set_aspect\(..., adjustable="):
  4821. fig.draw_without_rendering()
  4822. @pytest.mark.parametrize('err, args, kwargs, match',
  4823. ((TypeError, (1, 2), {},
  4824. r"axis\(\) takes from 0 to 1 positional arguments "
  4825. "but 2 were given"),
  4826. (ValueError, ('foo', ), {},
  4827. "Unrecognized string 'foo' to axis; try 'on' or "
  4828. "'off'"),
  4829. (TypeError, ([1, 2], ), {},
  4830. "The first argument to axis*"),
  4831. (TypeError, tuple(), {'foo': None},
  4832. r"axis\(\) got an unexpected keyword argument "
  4833. "'foo'"),
  4834. ))
  4835. def test_axis_errors(err, args, kwargs, match):
  4836. with pytest.raises(err, match=match):
  4837. plt.axis(*args, **kwargs)
  4838. def test_axis_method_errors():
  4839. ax = plt.gca()
  4840. with pytest.raises(ValueError, match="unknown value for which: 'foo'"):
  4841. ax.get_xaxis_transform('foo')
  4842. with pytest.raises(ValueError, match="unknown value for which: 'foo'"):
  4843. ax.get_yaxis_transform('foo')
  4844. with pytest.raises(TypeError, match="Cannot supply both positional and"):
  4845. ax.set_prop_cycle('foo', label='bar')
  4846. with pytest.raises(ValueError, match="argument must be among"):
  4847. ax.set_anchor('foo')
  4848. with pytest.raises(ValueError, match="scilimits must be a sequence"):
  4849. ax.ticklabel_format(scilimits=1)
  4850. with pytest.raises(TypeError, match="Specifying 'loc' is disallowed"):
  4851. ax.set_xlabel('foo', loc='left', x=1)
  4852. with pytest.raises(TypeError, match="Specifying 'loc' is disallowed"):
  4853. ax.set_ylabel('foo', loc='top', y=1)
  4854. with pytest.raises(TypeError, match="Cannot pass both 'left'"):
  4855. ax.set_xlim(left=0, xmin=1)
  4856. with pytest.raises(TypeError, match="Cannot pass both 'right'"):
  4857. ax.set_xlim(right=0, xmax=1)
  4858. with pytest.raises(TypeError, match="Cannot pass both 'bottom'"):
  4859. ax.set_ylim(bottom=0, ymin=1)
  4860. with pytest.raises(TypeError, match="Cannot pass both 'top'"):
  4861. ax.set_ylim(top=0, ymax=1)
  4862. @pytest.mark.parametrize('twin', ('x', 'y'))
  4863. def test_twin_with_aspect(twin):
  4864. fig, ax = plt.subplots()
  4865. # test twinx or twiny
  4866. ax_twin = getattr(ax, f'twin{twin}')()
  4867. ax.set_aspect(5)
  4868. ax_twin.set_aspect(2)
  4869. assert_array_equal(ax.bbox.extents,
  4870. ax_twin.bbox.extents)
  4871. def test_relim_visible_only():
  4872. x1 = (0., 10.)
  4873. y1 = (0., 10.)
  4874. x2 = (-10., 20.)
  4875. y2 = (-10., 30.)
  4876. fig = matplotlib.figure.Figure()
  4877. ax = fig.add_subplot()
  4878. ax.plot(x1, y1)
  4879. assert ax.get_xlim() == x1
  4880. assert ax.get_ylim() == y1
  4881. line, = ax.plot(x2, y2)
  4882. assert ax.get_xlim() == x2
  4883. assert ax.get_ylim() == y2
  4884. line.set_visible(False)
  4885. assert ax.get_xlim() == x2
  4886. assert ax.get_ylim() == y2
  4887. ax.relim(visible_only=True)
  4888. ax.autoscale_view()
  4889. assert ax.get_xlim() == x1
  4890. assert ax.get_ylim() == y1
  4891. def test_text_labelsize():
  4892. """
  4893. tests for issue #1172
  4894. """
  4895. fig = plt.figure()
  4896. ax = fig.gca()
  4897. ax.tick_params(labelsize='large')
  4898. ax.tick_params(direction='out')
  4899. # Note: The `pie` image tests were affected by Numpy 2.0 changing promotions
  4900. # (NEP 50). While the changes were only marginal, tolerances were introduced.
  4901. # These tolerances could likely go away when numpy 2.0 is the minimum supported
  4902. # numpy and the images are regenerated.
  4903. @image_comparison(['pie_default.png'], tol=0.01)
  4904. def test_pie_default():
  4905. # The slices will be ordered and plotted counter-clockwise.
  4906. labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
  4907. sizes = [15, 30, 45, 10]
  4908. colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
  4909. explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
  4910. fig1, ax1 = plt.subplots(figsize=(8, 6))
  4911. ax1.pie(sizes, explode=explode, labels=labels, colors=colors,
  4912. autopct='%1.1f%%', shadow=True, startangle=90)
  4913. @image_comparison(['pie_linewidth_0', 'pie_linewidth_0', 'pie_linewidth_0'],
  4914. extensions=['png'], style='mpl20', tol=0.01)
  4915. def test_pie_linewidth_0():
  4916. # The slices will be ordered and plotted counter-clockwise.
  4917. labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
  4918. sizes = [15, 30, 45, 10]
  4919. colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
  4920. explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
  4921. plt.pie(sizes, explode=explode, labels=labels, colors=colors,
  4922. autopct='%1.1f%%', shadow=True, startangle=90,
  4923. wedgeprops={'linewidth': 0})
  4924. # Set aspect ratio to be equal so that pie is drawn as a circle.
  4925. plt.axis('equal')
  4926. # Reuse testcase from above for a labeled data test
  4927. data = {"l": labels, "s": sizes, "c": colors, "ex": explode}
  4928. fig = plt.figure()
  4929. ax = fig.gca()
  4930. ax.pie("s", explode="ex", labels="l", colors="c",
  4931. autopct='%1.1f%%', shadow=True, startangle=90,
  4932. wedgeprops={'linewidth': 0}, data=data)
  4933. ax.axis('equal')
  4934. # And again to test the pyplot functions which should also be able to be
  4935. # called with a data kwarg
  4936. plt.figure()
  4937. plt.pie("s", explode="ex", labels="l", colors="c",
  4938. autopct='%1.1f%%', shadow=True, startangle=90,
  4939. wedgeprops={'linewidth': 0}, data=data)
  4940. plt.axis('equal')
  4941. @image_comparison(['pie_center_radius.png'], style='mpl20', tol=0.01)
  4942. def test_pie_center_radius():
  4943. # The slices will be ordered and plotted counter-clockwise.
  4944. labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
  4945. sizes = [15, 30, 45, 10]
  4946. colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
  4947. explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
  4948. plt.pie(sizes, explode=explode, labels=labels, colors=colors,
  4949. autopct='%1.1f%%', shadow=True, startangle=90,
  4950. wedgeprops={'linewidth': 0}, center=(1, 2), radius=1.5)
  4951. plt.annotate("Center point", xy=(1, 2), xytext=(1, 1.3),
  4952. arrowprops=dict(arrowstyle="->",
  4953. connectionstyle="arc3"),
  4954. bbox=dict(boxstyle="square", facecolor="lightgrey"))
  4955. # Set aspect ratio to be equal so that pie is drawn as a circle.
  4956. plt.axis('equal')
  4957. @image_comparison(['pie_linewidth_2.png'], style='mpl20', tol=0.01)
  4958. def test_pie_linewidth_2():
  4959. # The slices will be ordered and plotted counter-clockwise.
  4960. labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
  4961. sizes = [15, 30, 45, 10]
  4962. colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
  4963. explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
  4964. plt.pie(sizes, explode=explode, labels=labels, colors=colors,
  4965. autopct='%1.1f%%', shadow=True, startangle=90,
  4966. wedgeprops={'linewidth': 2})
  4967. # Set aspect ratio to be equal so that pie is drawn as a circle.
  4968. plt.axis('equal')
  4969. @image_comparison(['pie_ccw_true.png'], style='mpl20', tol=0.01)
  4970. def test_pie_ccw_true():
  4971. # The slices will be ordered and plotted counter-clockwise.
  4972. labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
  4973. sizes = [15, 30, 45, 10]
  4974. colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
  4975. explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
  4976. plt.pie(sizes, explode=explode, labels=labels, colors=colors,
  4977. autopct='%1.1f%%', shadow=True, startangle=90,
  4978. counterclock=True)
  4979. # Set aspect ratio to be equal so that pie is drawn as a circle.
  4980. plt.axis('equal')
  4981. @image_comparison(['pie_frame_grid.png'], style='mpl20', tol=0.002)
  4982. def test_pie_frame_grid():
  4983. # The slices will be ordered and plotted counter-clockwise.
  4984. labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
  4985. sizes = [15, 30, 45, 10]
  4986. colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
  4987. # only "explode" the 2nd slice (i.e. 'Hogs')
  4988. explode = (0, 0.1, 0, 0)
  4989. plt.pie(sizes, explode=explode, labels=labels, colors=colors,
  4990. autopct='%1.1f%%', shadow=True, startangle=90,
  4991. wedgeprops={'linewidth': 0},
  4992. frame=True, center=(2, 2))
  4993. plt.pie(sizes[::-1], explode=explode, labels=labels, colors=colors,
  4994. autopct='%1.1f%%', shadow=True, startangle=90,
  4995. wedgeprops={'linewidth': 0},
  4996. frame=True, center=(5, 2))
  4997. plt.pie(sizes, explode=explode[::-1], labels=labels, colors=colors,
  4998. autopct='%1.1f%%', shadow=True, startangle=90,
  4999. wedgeprops={'linewidth': 0},
  5000. frame=True, center=(3, 5))
  5001. # Set aspect ratio to be equal so that pie is drawn as a circle.
  5002. plt.axis('equal')
  5003. @image_comparison(['pie_rotatelabels_true.png'], style='mpl20', tol=0.009)
  5004. def test_pie_rotatelabels_true():
  5005. # The slices will be ordered and plotted counter-clockwise.
  5006. labels = 'Hogwarts', 'Frogs', 'Dogs', 'Logs'
  5007. sizes = [15, 30, 45, 10]
  5008. colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
  5009. explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
  5010. plt.pie(sizes, explode=explode, labels=labels, colors=colors,
  5011. autopct='%1.1f%%', shadow=True, startangle=90,
  5012. rotatelabels=True)
  5013. # Set aspect ratio to be equal so that pie is drawn as a circle.
  5014. plt.axis('equal')
  5015. @image_comparison(['pie_no_label.png'], tol=0.01)
  5016. def test_pie_nolabel_but_legend():
  5017. labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
  5018. sizes = [15, 30, 45, 10]
  5019. colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
  5020. explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
  5021. plt.pie(sizes, explode=explode, labels=labels, colors=colors,
  5022. autopct='%1.1f%%', shadow=True, startangle=90, labeldistance=None,
  5023. rotatelabels=True)
  5024. plt.axis('equal')
  5025. plt.ylim(-1.2, 1.2)
  5026. plt.legend()
  5027. @image_comparison(['pie_shadow.png'], style='mpl20', tol=0.002)
  5028. def test_pie_shadow():
  5029. # Also acts as a test for the shade argument of Shadow
  5030. sizes = [15, 30, 45, 10]
  5031. colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
  5032. explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice
  5033. _, axes = plt.subplots(2, 2)
  5034. axes[0][0].pie(sizes, explode=explode, colors=colors,
  5035. shadow=True, startangle=90,
  5036. wedgeprops={'linewidth': 0})
  5037. axes[0][1].pie(sizes, explode=explode, colors=colors,
  5038. shadow=False, startangle=90,
  5039. wedgeprops={'linewidth': 0})
  5040. axes[1][0].pie(sizes, explode=explode, colors=colors,
  5041. shadow={'ox': -0.05, 'oy': -0.05, 'shade': 0.9, 'edgecolor': 'none'},
  5042. startangle=90, wedgeprops={'linewidth': 0})
  5043. axes[1][1].pie(sizes, explode=explode, colors=colors,
  5044. shadow={'ox': 0.05, 'linewidth': 2, 'shade': 0.2},
  5045. startangle=90, wedgeprops={'linewidth': 0})
  5046. def test_pie_textprops():
  5047. data = [23, 34, 45]
  5048. labels = ["Long name 1", "Long name 2", "Long name 3"]
  5049. textprops = dict(horizontalalignment="center",
  5050. verticalalignment="top",
  5051. rotation=90,
  5052. rotation_mode="anchor",
  5053. size=12, color="red")
  5054. _, texts, autopct = plt.gca().pie(data, labels=labels, autopct='%.2f',
  5055. textprops=textprops)
  5056. for labels in [texts, autopct]:
  5057. for tx in labels:
  5058. assert tx.get_ha() == textprops["horizontalalignment"]
  5059. assert tx.get_va() == textprops["verticalalignment"]
  5060. assert tx.get_rotation() == textprops["rotation"]
  5061. assert tx.get_rotation_mode() == textprops["rotation_mode"]
  5062. assert tx.get_size() == textprops["size"]
  5063. assert tx.get_color() == textprops["color"]
  5064. def test_pie_get_negative_values():
  5065. # Test the ValueError raised when feeding negative values into axes.pie
  5066. fig, ax = plt.subplots()
  5067. with pytest.raises(ValueError):
  5068. ax.pie([5, 5, -3], explode=[0, .1, .2])
  5069. def test_pie_invalid_explode():
  5070. # Test ValueError raised when feeding short explode list to axes.pie
  5071. fig, ax = plt.subplots()
  5072. with pytest.raises(ValueError):
  5073. ax.pie([1, 2, 3], explode=[0.1, 0.1])
  5074. def test_pie_invalid_labels():
  5075. # Test ValueError raised when feeding short labels list to axes.pie
  5076. fig, ax = plt.subplots()
  5077. with pytest.raises(ValueError):
  5078. ax.pie([1, 2, 3], labels=["One", "Two"])
  5079. def test_pie_invalid_radius():
  5080. # Test ValueError raised when feeding negative radius to axes.pie
  5081. fig, ax = plt.subplots()
  5082. with pytest.raises(ValueError):
  5083. ax.pie([1, 2, 3], radius=-5)
  5084. def test_normalize_kwarg_pie():
  5085. fig, ax = plt.subplots()
  5086. x = [0.3, 0.3, 0.1]
  5087. t1 = ax.pie(x=x, normalize=True)
  5088. assert abs(t1[0][-1].theta2 - 360.) < 1e-3
  5089. t2 = ax.pie(x=x, normalize=False)
  5090. assert abs(t2[0][-1].theta2 - 360.) > 1e-3
  5091. @check_figures_equal(extensions=['png'])
  5092. def test_pie_hatch_single(fig_test, fig_ref):
  5093. x = [0.3, 0.3, 0.1]
  5094. hatch = '+'
  5095. fig_test.subplots().pie(x, hatch=hatch)
  5096. wedges, _ = fig_ref.subplots().pie(x)
  5097. [w.set_hatch(hatch) for w in wedges]
  5098. @check_figures_equal(extensions=['png'])
  5099. def test_pie_hatch_multi(fig_test, fig_ref):
  5100. x = [0.3, 0.3, 0.1]
  5101. hatch = ['/', '+', '.']
  5102. fig_test.subplots().pie(x, hatch=hatch)
  5103. wedges, _ = fig_ref.subplots().pie(x)
  5104. [w.set_hatch(hp) for w, hp in zip(wedges, hatch)]
  5105. @image_comparison(['set_get_ticklabels.png'],
  5106. tol=0 if platform.machine() == 'x86_64' else 0.025)
  5107. def test_set_get_ticklabels():
  5108. # test issue 2246
  5109. fig, ax = plt.subplots(2)
  5110. ha = ['normal', 'set_x/yticklabels']
  5111. ax[0].plot(np.arange(10))
  5112. ax[0].set_title(ha[0])
  5113. ax[1].plot(np.arange(10))
  5114. ax[1].set_title(ha[1])
  5115. # set ticklabel to 1 plot in normal way
  5116. ax[0].set_xticks(range(10))
  5117. ax[0].set_yticks(range(10))
  5118. ax[0].set_xticklabels(['a', 'b', 'c', 'd'] + 6 * [''])
  5119. ax[0].set_yticklabels(['11', '12', '13', '14'] + 6 * [''])
  5120. # set ticklabel to the other plot, expect the 2 plots have same label
  5121. # setting pass get_ticklabels return value as ticklabels argument
  5122. ax[1].set_xticks(ax[0].get_xticks())
  5123. ax[1].set_yticks(ax[0].get_yticks())
  5124. ax[1].set_xticklabels(ax[0].get_xticklabels())
  5125. ax[1].set_yticklabels(ax[0].get_yticklabels())
  5126. def test_set_ticks_kwargs_raise_error_without_labels():
  5127. """
  5128. When labels=None and any kwarg is passed, axis.set_ticks() raises a
  5129. ValueError.
  5130. """
  5131. fig, ax = plt.subplots()
  5132. ticks = [1, 2, 3]
  5133. with pytest.raises(ValueError, match="Incorrect use of keyword argument 'alpha'"):
  5134. ax.xaxis.set_ticks(ticks, alpha=0.5)
  5135. @check_figures_equal(extensions=["png"])
  5136. def test_set_ticks_with_labels(fig_test, fig_ref):
  5137. """
  5138. Test that these two are identical::
  5139. set_xticks(ticks); set_xticklabels(labels, **kwargs)
  5140. set_xticks(ticks, labels, **kwargs)
  5141. """
  5142. ax = fig_ref.subplots()
  5143. ax.set_xticks([1, 2, 4, 6])
  5144. ax.set_xticklabels(['a', 'b', 'c', 'd'], fontweight='bold')
  5145. ax.set_yticks([1, 3, 5])
  5146. ax.set_yticks([2, 4], minor=True)
  5147. ax.set_yticklabels(['A', 'B'], minor=True)
  5148. ax = fig_test.subplots()
  5149. ax.set_xticks([1, 2, 4, 6], ['a', 'b', 'c', 'd'], fontweight='bold')
  5150. ax.set_yticks([1, 3, 5])
  5151. ax.set_yticks([2, 4], ['A', 'B'], minor=True)
  5152. def test_xticks_bad_args():
  5153. ax = plt.figure().add_subplot()
  5154. with pytest.raises(TypeError, match='must be a sequence'):
  5155. ax.set_xticks([2, 9], 3.1)
  5156. with pytest.raises(ValueError, match='must be 1D'):
  5157. plt.xticks(np.arange(4).reshape((-1, 1)))
  5158. with pytest.raises(ValueError, match='must be 1D'):
  5159. plt.xticks(np.arange(4).reshape((1, -1)))
  5160. with pytest.raises(ValueError, match='must be 1D'):
  5161. plt.xticks(np.arange(4).reshape((-1, 1)), labels=range(4))
  5162. with pytest.raises(ValueError, match='must be 1D'):
  5163. plt.xticks(np.arange(4).reshape((1, -1)), labels=range(4))
  5164. def test_subsampled_ticklabels():
  5165. # test issue 11937
  5166. fig, ax = plt.subplots()
  5167. ax.plot(np.arange(10))
  5168. ax.xaxis.set_ticks(np.arange(10) + 0.1)
  5169. ax.locator_params(nbins=5)
  5170. ax.xaxis.set_ticklabels([c for c in "bcdefghijk"])
  5171. plt.draw()
  5172. labels = [t.get_text() for t in ax.xaxis.get_ticklabels()]
  5173. assert labels == ['b', 'd', 'f', 'h', 'j']
  5174. def test_mismatched_ticklabels():
  5175. fig, ax = plt.subplots()
  5176. ax.plot(np.arange(10))
  5177. ax.xaxis.set_ticks([1.5, 2.5])
  5178. with pytest.raises(ValueError):
  5179. ax.xaxis.set_ticklabels(['a', 'b', 'c'])
  5180. def test_empty_ticks_fixed_loc():
  5181. # Smoke test that [] can be used to unset all tick labels
  5182. fig, ax = plt.subplots()
  5183. ax.bar([1, 2], [1, 2])
  5184. ax.set_xticks([1, 2])
  5185. ax.set_xticklabels([])
  5186. @image_comparison(['retain_tick_visibility.png'])
  5187. def test_retain_tick_visibility():
  5188. fig, ax = plt.subplots()
  5189. plt.plot([0, 1, 2], [0, -1, 4])
  5190. plt.setp(ax.get_yticklabels(), visible=False)
  5191. ax.tick_params(axis="y", which="both", length=0)
  5192. def test_warn_too_few_labels():
  5193. # note that the axis is still using an AutoLocator:
  5194. fig, ax = plt.subplots()
  5195. with pytest.warns(
  5196. UserWarning,
  5197. match=r'set_ticklabels\(\) should only be used with a fixed number'):
  5198. ax.set_xticklabels(['0', '0.1'])
  5199. # note that the axis is still using a FixedLocator:
  5200. fig, ax = plt.subplots()
  5201. ax.set_xticks([0, 0.5, 1])
  5202. with pytest.raises(ValueError,
  5203. match='The number of FixedLocator locations'):
  5204. ax.set_xticklabels(['0', '0.1'])
  5205. def test_tick_label_update():
  5206. # test issue 9397
  5207. fig, ax = plt.subplots()
  5208. # Set up a dummy formatter
  5209. def formatter_func(x, pos):
  5210. return "unit value" if x == 1 else ""
  5211. ax.xaxis.set_major_formatter(plt.FuncFormatter(formatter_func))
  5212. # Force some of the x-axis ticks to be outside of the drawn range
  5213. ax.set_xticks([-1, 0, 1, 2, 3])
  5214. ax.set_xlim(-0.5, 2.5)
  5215. fig.canvas.draw()
  5216. tick_texts = [tick.get_text() for tick in ax.xaxis.get_ticklabels()]
  5217. assert tick_texts == ["", "", "unit value", "", ""]
  5218. @image_comparison(['o_marker_path_snap.png'], savefig_kwarg={'dpi': 72})
  5219. def test_o_marker_path_snap():
  5220. fig, ax = plt.subplots()
  5221. ax.margins(.1)
  5222. for ms in range(1, 15):
  5223. ax.plot([1, 2, ], np.ones(2) + ms, 'o', ms=ms)
  5224. for ms in np.linspace(1, 10, 25):
  5225. ax.plot([3, 4, ], np.ones(2) + ms, 'o', ms=ms)
  5226. def test_margins():
  5227. # test all ways margins can be called
  5228. data = [1, 10]
  5229. xmin = 0.0
  5230. xmax = len(data) - 1.0
  5231. ymin = min(data)
  5232. ymax = max(data)
  5233. fig1, ax1 = plt.subplots(1, 1)
  5234. ax1.plot(data)
  5235. ax1.margins(1)
  5236. assert ax1.margins() == (1, 1)
  5237. assert ax1.get_xlim() == (xmin - (xmax - xmin) * 1,
  5238. xmax + (xmax - xmin) * 1)
  5239. assert ax1.get_ylim() == (ymin - (ymax - ymin) * 1,
  5240. ymax + (ymax - ymin) * 1)
  5241. fig2, ax2 = plt.subplots(1, 1)
  5242. ax2.plot(data)
  5243. ax2.margins(0.5, 2)
  5244. assert ax2.margins() == (0.5, 2)
  5245. assert ax2.get_xlim() == (xmin - (xmax - xmin) * 0.5,
  5246. xmax + (xmax - xmin) * 0.5)
  5247. assert ax2.get_ylim() == (ymin - (ymax - ymin) * 2,
  5248. ymax + (ymax - ymin) * 2)
  5249. fig3, ax3 = plt.subplots(1, 1)
  5250. ax3.plot(data)
  5251. ax3.margins(x=-0.2, y=0.5)
  5252. assert ax3.margins() == (-0.2, 0.5)
  5253. assert ax3.get_xlim() == (xmin - (xmax - xmin) * -0.2,
  5254. xmax + (xmax - xmin) * -0.2)
  5255. assert ax3.get_ylim() == (ymin - (ymax - ymin) * 0.5,
  5256. ymax + (ymax - ymin) * 0.5)
  5257. def test_margin_getters():
  5258. fig = plt.figure()
  5259. ax = fig.add_subplot()
  5260. ax.margins(0.2, 0.3)
  5261. assert ax.get_xmargin() == 0.2
  5262. assert ax.get_ymargin() == 0.3
  5263. def test_set_margin_updates_limits():
  5264. mpl.style.use("default")
  5265. fig, ax = plt.subplots()
  5266. ax.plot([1, 2], [1, 2])
  5267. ax.set(xscale="log", xmargin=0)
  5268. assert ax.get_xlim() == (1, 2)
  5269. @pytest.mark.parametrize('err, args, kwargs, match', (
  5270. (ValueError, (-1,), {}, r'margin must be greater than -0\.5'),
  5271. (ValueError, (1, -1), {}, r'margin must be greater than -0\.5'),
  5272. (ValueError, tuple(), {'x': -1}, r'margin must be greater than -0\.5'),
  5273. (ValueError, tuple(), {'y': -1}, r'margin must be greater than -0\.5'),
  5274. (TypeError, (1, ), {'x': 1, 'y': 1},
  5275. 'Cannot pass both positional and keyword arguments for x and/or y'),
  5276. (TypeError, (1, ), {'x': 1},
  5277. 'Cannot pass both positional and keyword arguments for x and/or y'),
  5278. (TypeError, (1, 1, 1), {}, 'Must pass a single positional argument'),
  5279. ))
  5280. def test_margins_errors(err, args, kwargs, match):
  5281. with pytest.raises(err, match=match):
  5282. fig = plt.figure()
  5283. ax = fig.add_subplot()
  5284. ax.margins(*args, **kwargs)
  5285. def test_length_one_hist():
  5286. fig, ax = plt.subplots()
  5287. ax.hist(1)
  5288. ax.hist([1])
  5289. def test_set_xy_bound():
  5290. fig = plt.figure()
  5291. ax = fig.add_subplot()
  5292. ax.set_xbound(2.0, 3.0)
  5293. assert ax.get_xbound() == (2.0, 3.0)
  5294. assert ax.get_xlim() == (2.0, 3.0)
  5295. ax.set_xbound(upper=4.0)
  5296. assert ax.get_xbound() == (2.0, 4.0)
  5297. assert ax.get_xlim() == (2.0, 4.0)
  5298. ax.set_xbound(lower=3.0)
  5299. assert ax.get_xbound() == (3.0, 4.0)
  5300. assert ax.get_xlim() == (3.0, 4.0)
  5301. ax.set_ybound(2.0, 3.0)
  5302. assert ax.get_ybound() == (2.0, 3.0)
  5303. assert ax.get_ylim() == (2.0, 3.0)
  5304. ax.set_ybound(upper=4.0)
  5305. assert ax.get_ybound() == (2.0, 4.0)
  5306. assert ax.get_ylim() == (2.0, 4.0)
  5307. ax.set_ybound(lower=3.0)
  5308. assert ax.get_ybound() == (3.0, 4.0)
  5309. assert ax.get_ylim() == (3.0, 4.0)
  5310. def test_pathological_hexbin():
  5311. # issue #2863
  5312. mylist = [10] * 100
  5313. fig, ax = plt.subplots(1, 1)
  5314. ax.hexbin(mylist, mylist)
  5315. fig.savefig(io.BytesIO()) # Check that no warning is emitted.
  5316. def test_color_None():
  5317. # issue 3855
  5318. fig, ax = plt.subplots()
  5319. ax.plot([1, 2], [1, 2], color=None)
  5320. def test_color_alias():
  5321. # issues 4157 and 4162
  5322. fig, ax = plt.subplots()
  5323. line = ax.plot([0, 1], c='lime')[0]
  5324. assert 'lime' == line.get_color()
  5325. def test_numerical_hist_label():
  5326. fig, ax = plt.subplots()
  5327. ax.hist([range(15)] * 5, label=range(5))
  5328. ax.legend()
  5329. def test_unicode_hist_label():
  5330. fig, ax = plt.subplots()
  5331. a = (b'\xe5\xbe\x88\xe6\xbc\x82\xe4\xba\xae, ' +
  5332. b'r\xc3\xb6m\xc3\xa4n ch\xc3\xa4r\xc3\xa1ct\xc3\xa8rs')
  5333. b = b'\xd7\xa9\xd7\x9c\xd7\x95\xd7\x9d'
  5334. labels = [a.decode('utf-8'),
  5335. 'hi aardvark',
  5336. b.decode('utf-8'),
  5337. ]
  5338. ax.hist([range(15)] * 3, label=labels)
  5339. ax.legend()
  5340. def test_move_offsetlabel():
  5341. data = np.random.random(10) * 1e-22
  5342. fig, ax = plt.subplots()
  5343. ax.plot(data)
  5344. fig.canvas.draw()
  5345. before = ax.yaxis.offsetText.get_position()
  5346. assert ax.yaxis.offsetText.get_horizontalalignment() == 'left'
  5347. ax.yaxis.tick_right()
  5348. fig.canvas.draw()
  5349. after = ax.yaxis.offsetText.get_position()
  5350. assert after[0] > before[0] and after[1] == before[1]
  5351. assert ax.yaxis.offsetText.get_horizontalalignment() == 'right'
  5352. fig, ax = plt.subplots()
  5353. ax.plot(data)
  5354. fig.canvas.draw()
  5355. before = ax.xaxis.offsetText.get_position()
  5356. assert ax.xaxis.offsetText.get_verticalalignment() == 'top'
  5357. ax.xaxis.tick_top()
  5358. fig.canvas.draw()
  5359. after = ax.xaxis.offsetText.get_position()
  5360. assert after[0] == before[0] and after[1] > before[1]
  5361. assert ax.xaxis.offsetText.get_verticalalignment() == 'bottom'
  5362. @image_comparison(['rc_spines.png'], savefig_kwarg={'dpi': 40})
  5363. def test_rc_spines():
  5364. rc_dict = {
  5365. 'axes.spines.left': False,
  5366. 'axes.spines.right': False,
  5367. 'axes.spines.top': False,
  5368. 'axes.spines.bottom': False}
  5369. with matplotlib.rc_context(rc_dict):
  5370. plt.subplots() # create a figure and axes with the spine properties
  5371. @image_comparison(['rc_grid.png'], savefig_kwarg={'dpi': 40})
  5372. def test_rc_grid():
  5373. fig = plt.figure()
  5374. rc_dict0 = {
  5375. 'axes.grid': True,
  5376. 'axes.grid.axis': 'both'
  5377. }
  5378. rc_dict1 = {
  5379. 'axes.grid': True,
  5380. 'axes.grid.axis': 'x'
  5381. }
  5382. rc_dict2 = {
  5383. 'axes.grid': True,
  5384. 'axes.grid.axis': 'y'
  5385. }
  5386. dict_list = [rc_dict0, rc_dict1, rc_dict2]
  5387. for i, rc_dict in enumerate(dict_list, 1):
  5388. with matplotlib.rc_context(rc_dict):
  5389. fig.add_subplot(3, 1, i)
  5390. def test_rc_tick():
  5391. d = {'xtick.bottom': False, 'xtick.top': True,
  5392. 'ytick.left': True, 'ytick.right': False}
  5393. with plt.rc_context(rc=d):
  5394. fig = plt.figure()
  5395. ax1 = fig.add_subplot(1, 1, 1)
  5396. xax = ax1.xaxis
  5397. yax = ax1.yaxis
  5398. # tick1On bottom/left
  5399. assert not xax._major_tick_kw['tick1On']
  5400. assert xax._major_tick_kw['tick2On']
  5401. assert not xax._minor_tick_kw['tick1On']
  5402. assert xax._minor_tick_kw['tick2On']
  5403. assert yax._major_tick_kw['tick1On']
  5404. assert not yax._major_tick_kw['tick2On']
  5405. assert yax._minor_tick_kw['tick1On']
  5406. assert not yax._minor_tick_kw['tick2On']
  5407. def test_rc_major_minor_tick():
  5408. d = {'xtick.top': True, 'ytick.right': True, # Enable all ticks
  5409. 'xtick.bottom': True, 'ytick.left': True,
  5410. # Selectively disable
  5411. 'xtick.minor.bottom': False, 'xtick.major.bottom': False,
  5412. 'ytick.major.left': False, 'ytick.minor.left': False}
  5413. with plt.rc_context(rc=d):
  5414. fig = plt.figure()
  5415. ax1 = fig.add_subplot(1, 1, 1)
  5416. xax = ax1.xaxis
  5417. yax = ax1.yaxis
  5418. # tick1On bottom/left
  5419. assert not xax._major_tick_kw['tick1On']
  5420. assert xax._major_tick_kw['tick2On']
  5421. assert not xax._minor_tick_kw['tick1On']
  5422. assert xax._minor_tick_kw['tick2On']
  5423. assert not yax._major_tick_kw['tick1On']
  5424. assert yax._major_tick_kw['tick2On']
  5425. assert not yax._minor_tick_kw['tick1On']
  5426. assert yax._minor_tick_kw['tick2On']
  5427. def test_square_plot():
  5428. x = np.arange(4)
  5429. y = np.array([1., 3., 5., 7.])
  5430. fig, ax = plt.subplots()
  5431. ax.plot(x, y, 'mo')
  5432. ax.axis('square')
  5433. xlim, ylim = ax.get_xlim(), ax.get_ylim()
  5434. assert np.diff(xlim) == np.diff(ylim)
  5435. assert ax.get_aspect() == 1
  5436. assert_array_almost_equal(
  5437. ax.get_position(original=True).extents, (0.125, 0.1, 0.9, 0.9))
  5438. assert_array_almost_equal(
  5439. ax.get_position(original=False).extents, (0.2125, 0.1, 0.8125, 0.9))
  5440. def test_bad_plot_args():
  5441. with pytest.raises(ValueError):
  5442. plt.plot(None)
  5443. with pytest.raises(ValueError):
  5444. plt.plot(None, None)
  5445. with pytest.raises(ValueError):
  5446. plt.plot(np.zeros((2, 2)), np.zeros((2, 3)))
  5447. with pytest.raises(ValueError):
  5448. plt.plot((np.arange(5).reshape((1, -1)), np.arange(5).reshape(-1, 1)))
  5449. @pytest.mark.parametrize(
  5450. "xy, cls", [
  5451. ((), mpl.image.AxesImage), # (0, N)
  5452. (((3, 7), (2, 6)), mpl.image.AxesImage), # (xmin, xmax)
  5453. ((range(5), range(4)), mpl.image.AxesImage), # regular grid
  5454. (([1, 2, 4, 8, 16], [0, 1, 2, 3]), # irregular grid
  5455. mpl.image.PcolorImage),
  5456. ((np.random.random((4, 5)), np.random.random((4, 5))), # 2D coords
  5457. mpl.collections.QuadMesh),
  5458. ]
  5459. )
  5460. @pytest.mark.parametrize(
  5461. "data", [np.arange(12).reshape((3, 4)), np.random.rand(3, 4, 3)]
  5462. )
  5463. def test_pcolorfast(xy, data, cls):
  5464. fig, ax = plt.subplots()
  5465. assert type(ax.pcolorfast(*xy, data)) == cls
  5466. def test_pcolorfast_bad_dims():
  5467. fig, ax = plt.subplots()
  5468. with pytest.raises(
  5469. TypeError, match=("the given X was 1D and the given Y was 2D")):
  5470. ax.pcolorfast(np.empty(6), np.empty((4, 7)), np.empty((8, 8)))
  5471. def test_pcolorfast_regular_xy_incompatible_size():
  5472. """
  5473. Test that the sizes of X, Y, C are compatible for regularly spaced X, Y.
  5474. Note that after the regualar-spacing check, pcolorfast may go into the
  5475. fast "image" mode, where the individual X, Y positions are not used anymore.
  5476. Therefore, the algorithm had worked with any regularly number of regularly
  5477. spaced values, but discarded their values.
  5478. """
  5479. fig, ax = plt.subplots()
  5480. with pytest.raises(
  5481. ValueError, match=r"Length of X \(5\) must be one larger than the "
  5482. r"number of columns in C \(20\)"):
  5483. ax.pcolorfast(np.arange(5), np.arange(11), np.random.rand(10, 20))
  5484. with pytest.raises(
  5485. ValueError, match=r"Length of Y \(5\) must be one larger than the "
  5486. r"number of rows in C \(10\)"):
  5487. ax.pcolorfast(np.arange(21), np.arange(5), np.random.rand(10, 20))
  5488. def test_shared_scale():
  5489. fig, axs = plt.subplots(2, 2, sharex=True, sharey=True)
  5490. axs[0, 0].set_xscale("log")
  5491. axs[0, 0].set_yscale("log")
  5492. for ax in axs.flat:
  5493. assert ax.get_yscale() == 'log'
  5494. assert ax.get_xscale() == 'log'
  5495. axs[1, 1].set_xscale("linear")
  5496. axs[1, 1].set_yscale("linear")
  5497. for ax in axs.flat:
  5498. assert ax.get_yscale() == 'linear'
  5499. assert ax.get_xscale() == 'linear'
  5500. def test_shared_bool():
  5501. with pytest.raises(TypeError):
  5502. plt.subplot(sharex=True)
  5503. with pytest.raises(TypeError):
  5504. plt.subplot(sharey=True)
  5505. def test_violin_point_mass():
  5506. """Violin plot should handle point mass pdf gracefully."""
  5507. plt.violinplot(np.array([0, 0]))
  5508. def generate_errorbar_inputs():
  5509. base_xy = cycler('x', [np.arange(5)]) + cycler('y', [np.ones(5)])
  5510. err_cycler = cycler('err', [1,
  5511. [1, 1, 1, 1, 1],
  5512. [[1, 1, 1, 1, 1],
  5513. [1, 1, 1, 1, 1]],
  5514. np.ones(5),
  5515. np.ones((2, 5)),
  5516. None
  5517. ])
  5518. xerr_cy = cycler('xerr', err_cycler)
  5519. yerr_cy = cycler('yerr', err_cycler)
  5520. empty = ((cycler('x', [[]]) + cycler('y', [[]])) *
  5521. cycler('xerr', [[], None]) * cycler('yerr', [[], None]))
  5522. xerr_only = base_xy * xerr_cy
  5523. yerr_only = base_xy * yerr_cy
  5524. both_err = base_xy * yerr_cy * xerr_cy
  5525. return [*xerr_only, *yerr_only, *both_err, *empty]
  5526. @pytest.mark.parametrize('kwargs', generate_errorbar_inputs())
  5527. def test_errorbar_inputs_shotgun(kwargs):
  5528. ax = plt.gca()
  5529. eb = ax.errorbar(**kwargs)
  5530. eb.remove()
  5531. @image_comparison(["dash_offset"], remove_text=True)
  5532. def test_dash_offset():
  5533. fig, ax = plt.subplots()
  5534. x = np.linspace(0, 10)
  5535. y = np.ones_like(x)
  5536. for j in range(0, 100, 2):
  5537. ax.plot(x, j*y, ls=(j, (10, 10)), lw=5, color='k')
  5538. def test_title_pad():
  5539. # check that title padding puts the title in the right
  5540. # place...
  5541. fig, ax = plt.subplots()
  5542. ax.set_title('aardvark', pad=30.)
  5543. m = ax.titleOffsetTrans.get_matrix()
  5544. assert m[1, -1] == (30. / 72. * fig.dpi)
  5545. ax.set_title('aardvark', pad=0.)
  5546. m = ax.titleOffsetTrans.get_matrix()
  5547. assert m[1, -1] == 0.
  5548. # check that it is reverted...
  5549. ax.set_title('aardvark', pad=None)
  5550. m = ax.titleOffsetTrans.get_matrix()
  5551. assert m[1, -1] == (matplotlib.rcParams['axes.titlepad'] / 72. * fig.dpi)
  5552. def test_title_location_roundtrip():
  5553. fig, ax = plt.subplots()
  5554. # set default title location
  5555. plt.rcParams['axes.titlelocation'] = 'center'
  5556. ax.set_title('aardvark')
  5557. ax.set_title('left', loc='left')
  5558. ax.set_title('right', loc='right')
  5559. assert 'left' == ax.get_title(loc='left')
  5560. assert 'right' == ax.get_title(loc='right')
  5561. assert 'aardvark' == ax.get_title(loc='center')
  5562. with pytest.raises(ValueError):
  5563. ax.get_title(loc='foo')
  5564. with pytest.raises(ValueError):
  5565. ax.set_title('fail', loc='foo')
  5566. @pytest.mark.parametrize('sharex', [True, False])
  5567. def test_title_location_shared(sharex):
  5568. fig, axs = plt.subplots(2, 1, sharex=sharex)
  5569. axs[0].set_title('A', pad=-40)
  5570. axs[1].set_title('B', pad=-40)
  5571. fig.draw_without_rendering()
  5572. x, y1 = axs[0].title.get_position()
  5573. x, y2 = axs[1].title.get_position()
  5574. assert y1 == y2 == 1.0
  5575. @image_comparison(["loglog.png"], remove_text=True, tol=0.02)
  5576. def test_loglog():
  5577. fig, ax = plt.subplots()
  5578. x = np.arange(1, 11)
  5579. ax.loglog(x, x**3, lw=5)
  5580. ax.tick_params(length=25, width=2)
  5581. ax.tick_params(length=15, width=2, which='minor')
  5582. @image_comparison(["test_loglog_nonpos.png"], remove_text=True, style='mpl20',
  5583. tol=0 if platform.machine() == 'x86_64' else 0.029)
  5584. def test_loglog_nonpos():
  5585. fig, axs = plt.subplots(3, 3)
  5586. x = np.arange(1, 11)
  5587. y = x**3
  5588. y[7] = -3.
  5589. x[4] = -10
  5590. for (mcy, mcx), ax in zip(product(['mask', 'clip', ''], repeat=2),
  5591. axs.flat):
  5592. if mcx == mcy:
  5593. if mcx:
  5594. ax.loglog(x, y**3, lw=2, nonpositive=mcx)
  5595. else:
  5596. ax.loglog(x, y**3, lw=2)
  5597. else:
  5598. ax.loglog(x, y**3, lw=2)
  5599. if mcx:
  5600. ax.set_xscale("log", nonpositive=mcx)
  5601. if mcy:
  5602. ax.set_yscale("log", nonpositive=mcy)
  5603. @mpl.style.context('default')
  5604. def test_axes_margins():
  5605. fig, ax = plt.subplots()
  5606. ax.plot([0, 1, 2, 3])
  5607. assert ax.get_ybound()[0] != 0
  5608. fig, ax = plt.subplots()
  5609. ax.bar([0, 1, 2, 3], [1, 1, 1, 1])
  5610. assert ax.get_ybound()[0] == 0
  5611. fig, ax = plt.subplots()
  5612. ax.barh([0, 1, 2, 3], [1, 1, 1, 1])
  5613. assert ax.get_xbound()[0] == 0
  5614. fig, ax = plt.subplots()
  5615. ax.pcolor(np.zeros((10, 10)))
  5616. assert ax.get_xbound() == (0, 10)
  5617. assert ax.get_ybound() == (0, 10)
  5618. fig, ax = plt.subplots()
  5619. ax.pcolorfast(np.zeros((10, 10)))
  5620. assert ax.get_xbound() == (0, 10)
  5621. assert ax.get_ybound() == (0, 10)
  5622. fig, ax = plt.subplots()
  5623. ax.hist(np.arange(10))
  5624. assert ax.get_ybound()[0] == 0
  5625. fig, ax = plt.subplots()
  5626. ax.imshow(np.zeros((10, 10)))
  5627. assert ax.get_xbound() == (-0.5, 9.5)
  5628. assert ax.get_ybound() == (-0.5, 9.5)
  5629. @pytest.fixture(params=['x', 'y'])
  5630. def shared_axis_remover(request):
  5631. def _helper_x(ax):
  5632. ax2 = ax.twinx()
  5633. ax2.remove()
  5634. ax.set_xlim(0, 15)
  5635. r = ax.xaxis.get_major_locator()()
  5636. assert r[-1] > 14
  5637. def _helper_y(ax):
  5638. ax2 = ax.twiny()
  5639. ax2.remove()
  5640. ax.set_ylim(0, 15)
  5641. r = ax.yaxis.get_major_locator()()
  5642. assert r[-1] > 14
  5643. return {"x": _helper_x, "y": _helper_y}[request.param]
  5644. @pytest.fixture(params=['gca', 'subplots', 'subplots_shared', 'add_axes'])
  5645. def shared_axes_generator(request):
  5646. # test all of the ways to get fig/ax sets
  5647. if request.param == 'gca':
  5648. fig = plt.figure()
  5649. ax = fig.gca()
  5650. elif request.param == 'subplots':
  5651. fig, ax = plt.subplots()
  5652. elif request.param == 'subplots_shared':
  5653. fig, ax_lst = plt.subplots(2, 2, sharex='all', sharey='all')
  5654. ax = ax_lst[0][0]
  5655. elif request.param == 'add_axes':
  5656. fig = plt.figure()
  5657. ax = fig.add_axes([.1, .1, .8, .8])
  5658. return fig, ax
  5659. def test_remove_shared_axes(shared_axes_generator, shared_axis_remover):
  5660. # test all of the ways to get fig/ax sets
  5661. fig, ax = shared_axes_generator
  5662. shared_axis_remover(ax)
  5663. def test_remove_shared_axes_relim():
  5664. fig, ax_lst = plt.subplots(2, 2, sharex='all', sharey='all')
  5665. ax = ax_lst[0][0]
  5666. orig_xlim = ax_lst[0][1].get_xlim()
  5667. ax.remove()
  5668. ax.set_xlim(0, 5)
  5669. assert_array_equal(ax_lst[0][1].get_xlim(), orig_xlim)
  5670. def test_shared_axes_autoscale():
  5671. l = np.arange(-80, 90, 40)
  5672. t = np.random.random_sample((l.size, l.size))
  5673. fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, sharey=True)
  5674. ax1.set_xlim(-1000, 1000)
  5675. ax1.set_ylim(-1000, 1000)
  5676. ax1.contour(l, l, t)
  5677. ax2.contour(l, l, t)
  5678. assert not ax1.get_autoscalex_on() and not ax2.get_autoscalex_on()
  5679. assert not ax1.get_autoscaley_on() and not ax2.get_autoscaley_on()
  5680. assert ax1.get_xlim() == ax2.get_xlim() == (-1000, 1000)
  5681. assert ax1.get_ylim() == ax2.get_ylim() == (-1000, 1000)
  5682. def test_adjust_numtick_aspect():
  5683. fig, ax = plt.subplots()
  5684. ax.yaxis.get_major_locator().set_params(nbins='auto')
  5685. ax.set_xlim(0, 1000)
  5686. ax.set_aspect('equal')
  5687. fig.canvas.draw()
  5688. assert len(ax.yaxis.get_major_locator()()) == 2
  5689. ax.set_ylim(0, 1000)
  5690. fig.canvas.draw()
  5691. assert len(ax.yaxis.get_major_locator()()) > 2
  5692. @mpl.style.context("default")
  5693. def test_auto_numticks():
  5694. axs = plt.figure().subplots(4, 4)
  5695. for ax in axs.flat: # Tiny, empty subplots have only 3 ticks.
  5696. assert [*ax.get_xticks()] == [*ax.get_yticks()] == [0, 0.5, 1]
  5697. @mpl.style.context("default")
  5698. def test_auto_numticks_log():
  5699. # Verify that there are not too many ticks with a large log range.
  5700. fig, ax = plt.subplots()
  5701. mpl.rcParams['axes.autolimit_mode'] = 'round_numbers'
  5702. ax.loglog([1e-20, 1e5], [1e-16, 10])
  5703. assert (np.log10(ax.get_xticks()) == np.arange(-26, 18, 4)).all()
  5704. assert (np.log10(ax.get_yticks()) == np.arange(-20, 10, 3)).all()
  5705. def test_broken_barh_empty():
  5706. fig, ax = plt.subplots()
  5707. ax.broken_barh([], (.1, .5))
  5708. def test_broken_barh_timedelta():
  5709. """Check that timedelta works as x, dx pair for this method."""
  5710. fig, ax = plt.subplots()
  5711. d0 = datetime.datetime(2018, 11, 9, 0, 0, 0)
  5712. pp = ax.broken_barh([(d0, datetime.timedelta(hours=1))], [1, 2])
  5713. assert pp.get_paths()[0].vertices[0, 0] == mdates.date2num(d0)
  5714. assert pp.get_paths()[0].vertices[2, 0] == mdates.date2num(d0) + 1 / 24
  5715. def test_pandas_pcolormesh(pd):
  5716. time = pd.date_range('2000-01-01', periods=10)
  5717. depth = np.arange(20)
  5718. data = np.random.rand(19, 9)
  5719. fig, ax = plt.subplots()
  5720. ax.pcolormesh(time, depth, data)
  5721. def test_pandas_indexing_dates(pd):
  5722. dates = np.arange('2005-02', '2005-03', dtype='datetime64[D]')
  5723. values = np.sin(range(len(dates)))
  5724. df = pd.DataFrame({'dates': dates, 'values': values})
  5725. ax = plt.gca()
  5726. without_zero_index = df[np.array(df.index) % 2 == 1].copy()
  5727. ax.plot('dates', 'values', data=without_zero_index)
  5728. def test_pandas_errorbar_indexing(pd):
  5729. df = pd.DataFrame(np.random.uniform(size=(5, 4)),
  5730. columns=['x', 'y', 'xe', 'ye'],
  5731. index=[1, 2, 3, 4, 5])
  5732. fig, ax = plt.subplots()
  5733. ax.errorbar('x', 'y', xerr='xe', yerr='ye', data=df)
  5734. def test_pandas_index_shape(pd):
  5735. df = pd.DataFrame({"XX": [4, 5, 6], "YY": [7, 1, 2]})
  5736. fig, ax = plt.subplots()
  5737. ax.plot(df.index, df['YY'])
  5738. def test_pandas_indexing_hist(pd):
  5739. ser_1 = pd.Series(data=[1, 2, 2, 3, 3, 4, 4, 4, 4, 5])
  5740. ser_2 = ser_1.iloc[1:]
  5741. fig, ax = plt.subplots()
  5742. ax.hist(ser_2)
  5743. def test_pandas_bar_align_center(pd):
  5744. # Tests fix for issue 8767
  5745. df = pd.DataFrame({'a': range(2), 'b': range(2)})
  5746. fig, ax = plt.subplots(1)
  5747. ax.bar(df.loc[df['a'] == 1, 'b'],
  5748. df.loc[df['a'] == 1, 'b'],
  5749. align='center')
  5750. fig.canvas.draw()
  5751. def test_axis_get_tick_params():
  5752. axis = plt.subplot().yaxis
  5753. initial_major_style_translated = {**axis.get_tick_params(which='major')}
  5754. initial_minor_style_translated = {**axis.get_tick_params(which='minor')}
  5755. translated_major_kw = axis._translate_tick_params(
  5756. axis._major_tick_kw, reverse=True
  5757. )
  5758. translated_minor_kw = axis._translate_tick_params(
  5759. axis._minor_tick_kw, reverse=True
  5760. )
  5761. assert translated_major_kw == initial_major_style_translated
  5762. assert translated_minor_kw == initial_minor_style_translated
  5763. axis.set_tick_params(labelsize=30, labelcolor='red',
  5764. direction='out', which='both')
  5765. new_major_style_translated = {**axis.get_tick_params(which='major')}
  5766. new_minor_style_translated = {**axis.get_tick_params(which='minor')}
  5767. new_major_style = axis._translate_tick_params(new_major_style_translated)
  5768. new_minor_style = axis._translate_tick_params(new_minor_style_translated)
  5769. assert initial_major_style_translated != new_major_style_translated
  5770. assert axis._major_tick_kw == new_major_style
  5771. assert initial_minor_style_translated != new_minor_style_translated
  5772. assert axis._minor_tick_kw == new_minor_style
  5773. def test_axis_set_tick_params_labelsize_labelcolor():
  5774. # Tests fix for issue 4346
  5775. axis_1 = plt.subplot()
  5776. axis_1.yaxis.set_tick_params(labelsize=30, labelcolor='red',
  5777. direction='out')
  5778. # Expected values after setting the ticks
  5779. assert axis_1.yaxis.majorTicks[0]._size == 4.0
  5780. assert axis_1.yaxis.majorTicks[0].tick1line.get_color() == 'k'
  5781. assert axis_1.yaxis.majorTicks[0].label1.get_size() == 30.0
  5782. assert axis_1.yaxis.majorTicks[0].label1.get_color() == 'red'
  5783. def test_axes_tick_params_gridlines():
  5784. # Now treating grid params like other Tick params
  5785. ax = plt.subplot()
  5786. ax.tick_params(grid_color='b', grid_linewidth=5, grid_alpha=0.5,
  5787. grid_linestyle='dashdot')
  5788. for axis in ax.xaxis, ax.yaxis:
  5789. assert axis.majorTicks[0].gridline.get_color() == 'b'
  5790. assert axis.majorTicks[0].gridline.get_linewidth() == 5
  5791. assert axis.majorTicks[0].gridline.get_alpha() == 0.5
  5792. assert axis.majorTicks[0].gridline.get_linestyle() == '-.'
  5793. def test_axes_tick_params_ylabelside():
  5794. # Tests fix for issue 10267
  5795. ax = plt.subplot()
  5796. ax.tick_params(labelleft=False, labelright=True,
  5797. which='major')
  5798. ax.tick_params(labelleft=False, labelright=True,
  5799. which='minor')
  5800. # expects left false, right true
  5801. assert ax.yaxis.majorTicks[0].label1.get_visible() is False
  5802. assert ax.yaxis.majorTicks[0].label2.get_visible() is True
  5803. assert ax.yaxis.minorTicks[0].label1.get_visible() is False
  5804. assert ax.yaxis.minorTicks[0].label2.get_visible() is True
  5805. def test_axes_tick_params_xlabelside():
  5806. # Tests fix for issue 10267
  5807. ax = plt.subplot()
  5808. ax.tick_params(labeltop=True, labelbottom=False,
  5809. which='major')
  5810. ax.tick_params(labeltop=True, labelbottom=False,
  5811. which='minor')
  5812. # expects top True, bottom False
  5813. # label1.get_visible() mapped to labelbottom
  5814. # label2.get_visible() mapped to labeltop
  5815. assert ax.xaxis.majorTicks[0].label1.get_visible() is False
  5816. assert ax.xaxis.majorTicks[0].label2.get_visible() is True
  5817. assert ax.xaxis.minorTicks[0].label1.get_visible() is False
  5818. assert ax.xaxis.minorTicks[0].label2.get_visible() is True
  5819. def test_none_kwargs():
  5820. ax = plt.figure().subplots()
  5821. ln, = ax.plot(range(32), linestyle=None)
  5822. assert ln.get_linestyle() == '-'
  5823. def test_bar_uint8():
  5824. xs = [0, 1, 2, 3]
  5825. b = plt.bar(np.array(xs, dtype=np.uint8), [2, 3, 4, 5], align="edge")
  5826. for (patch, x) in zip(b.patches, xs):
  5827. assert patch.xy[0] == x
  5828. @image_comparison(['date_timezone_x.png'], tol=1.0)
  5829. def test_date_timezone_x():
  5830. # Tests issue 5575
  5831. time_index = [datetime.datetime(2016, 2, 22, hour=x,
  5832. tzinfo=dateutil.tz.gettz('Canada/Eastern'))
  5833. for x in range(3)]
  5834. # Same Timezone
  5835. plt.figure(figsize=(20, 12))
  5836. plt.subplot(2, 1, 1)
  5837. with pytest.warns(mpl.MatplotlibDeprecationWarning):
  5838. plt.plot_date(time_index, [3] * 3, tz='Canada/Eastern')
  5839. # Different Timezone
  5840. plt.subplot(2, 1, 2)
  5841. with pytest.warns(mpl.MatplotlibDeprecationWarning):
  5842. plt.plot_date(time_index, [3] * 3, tz='UTC')
  5843. @image_comparison(['date_timezone_y.png'])
  5844. def test_date_timezone_y():
  5845. # Tests issue 5575
  5846. time_index = [datetime.datetime(2016, 2, 22, hour=x,
  5847. tzinfo=dateutil.tz.gettz('Canada/Eastern'))
  5848. for x in range(3)]
  5849. # Same Timezone
  5850. plt.figure(figsize=(20, 12))
  5851. plt.subplot(2, 1, 1)
  5852. with pytest.warns(mpl.MatplotlibDeprecationWarning):
  5853. plt.plot_date([3] * 3, time_index, tz='Canada/Eastern', xdate=False, ydate=True)
  5854. # Different Timezone
  5855. plt.subplot(2, 1, 2)
  5856. with pytest.warns(mpl.MatplotlibDeprecationWarning):
  5857. plt.plot_date([3] * 3, time_index, tz='UTC', xdate=False, ydate=True)
  5858. @image_comparison(['date_timezone_x_and_y.png'], tol=1.0)
  5859. def test_date_timezone_x_and_y():
  5860. # Tests issue 5575
  5861. UTC = datetime.timezone.utc
  5862. time_index = [datetime.datetime(2016, 2, 22, hour=x, tzinfo=UTC)
  5863. for x in range(3)]
  5864. # Same Timezone
  5865. plt.figure(figsize=(20, 12))
  5866. plt.subplot(2, 1, 1)
  5867. with pytest.warns(mpl.MatplotlibDeprecationWarning):
  5868. plt.plot_date(time_index, time_index, tz='UTC', ydate=True)
  5869. # Different Timezone
  5870. plt.subplot(2, 1, 2)
  5871. with pytest.warns(mpl.MatplotlibDeprecationWarning):
  5872. plt.plot_date(time_index, time_index, tz='US/Eastern', ydate=True)
  5873. @image_comparison(['axisbelow.png'], remove_text=True)
  5874. def test_axisbelow():
  5875. # Test 'line' setting added in 6287.
  5876. # Show only grids, not frame or ticks, to make this test
  5877. # independent of future change to drawing order of those elements.
  5878. axs = plt.figure().subplots(ncols=3, sharex=True, sharey=True)
  5879. settings = (False, 'line', True)
  5880. for ax, setting in zip(axs, settings):
  5881. ax.plot((0, 10), (0, 10), lw=10, color='m')
  5882. circ = mpatches.Circle((3, 3), color='r')
  5883. ax.add_patch(circ)
  5884. ax.grid(color='c', linestyle='-', linewidth=3)
  5885. ax.tick_params(top=False, bottom=False,
  5886. left=False, right=False)
  5887. ax.spines[:].set_visible(False)
  5888. ax.set_axisbelow(setting)
  5889. assert ax.get_axisbelow() == setting
  5890. def test_titletwiny():
  5891. plt.style.use('mpl20')
  5892. fig, ax = plt.subplots(dpi=72)
  5893. ax2 = ax.twiny()
  5894. xlabel2 = ax2.set_xlabel('Xlabel2')
  5895. title = ax.set_title('Title')
  5896. fig.canvas.draw()
  5897. renderer = fig.canvas.get_renderer()
  5898. # ------- Test that title is put above Xlabel2 (Xlabel2 at top) ----------
  5899. bbox_y0_title = title.get_window_extent(renderer).y0 # bottom of title
  5900. bbox_y1_xlabel2 = xlabel2.get_window_extent(renderer).y1 # top of xlabel2
  5901. y_diff = bbox_y0_title - bbox_y1_xlabel2
  5902. assert np.isclose(y_diff, 3)
  5903. def test_titlesetpos():
  5904. # Test that title stays put if we set it manually
  5905. fig, ax = plt.subplots()
  5906. fig.subplots_adjust(top=0.8)
  5907. ax2 = ax.twiny()
  5908. ax.set_xlabel('Xlabel')
  5909. ax2.set_xlabel('Xlabel2')
  5910. ax.set_title('Title')
  5911. pos = (0.5, 1.11)
  5912. ax.title.set_position(pos)
  5913. renderer = fig.canvas.get_renderer()
  5914. ax._update_title_position(renderer)
  5915. assert ax.title.get_position() == pos
  5916. def test_title_xticks_top():
  5917. # Test that title moves if xticks on top of axes.
  5918. mpl.rcParams['axes.titley'] = None
  5919. fig, ax = plt.subplots()
  5920. ax.xaxis.set_ticks_position('top')
  5921. ax.set_title('xlabel top')
  5922. fig.canvas.draw()
  5923. assert ax.title.get_position()[1] > 1.04
  5924. def test_title_xticks_top_both():
  5925. # Test that title moves if xticks on top of axes.
  5926. mpl.rcParams['axes.titley'] = None
  5927. fig, ax = plt.subplots()
  5928. ax.tick_params(axis="x",
  5929. bottom=True, top=True, labelbottom=True, labeltop=True)
  5930. ax.set_title('xlabel top')
  5931. fig.canvas.draw()
  5932. assert ax.title.get_position()[1] > 1.04
  5933. @pytest.mark.parametrize(
  5934. 'left, center', [
  5935. ('left', ''),
  5936. ('', 'center'),
  5937. ('left', 'center')
  5938. ], ids=[
  5939. 'left title moved',
  5940. 'center title kept',
  5941. 'both titles aligned'
  5942. ]
  5943. )
  5944. def test_title_above_offset(left, center):
  5945. # Test that title moves if overlaps with yaxis offset text.
  5946. mpl.rcParams['axes.titley'] = None
  5947. fig, ax = plt.subplots()
  5948. ax.set_ylim(1e11)
  5949. ax.set_title(left, loc='left')
  5950. ax.set_title(center)
  5951. fig.draw_without_rendering()
  5952. if left and not center:
  5953. assert ax._left_title.get_position()[1] > 1.0
  5954. elif not left and center:
  5955. assert ax.title.get_position()[1] == 1.0
  5956. else:
  5957. yleft = ax._left_title.get_position()[1]
  5958. ycenter = ax.title.get_position()[1]
  5959. assert yleft > 1.0
  5960. assert ycenter == yleft
  5961. def test_title_no_move_off_page():
  5962. # If an Axes is off the figure (ie. if it is cropped during a save)
  5963. # make sure that the automatic title repositioning does not get done.
  5964. mpl.rcParams['axes.titley'] = None
  5965. fig = plt.figure()
  5966. ax = fig.add_axes([0.1, -0.5, 0.8, 0.2])
  5967. ax.tick_params(axis="x",
  5968. bottom=True, top=True, labelbottom=True, labeltop=True)
  5969. tt = ax.set_title('Boo')
  5970. fig.canvas.draw()
  5971. assert tt.get_position()[1] == 1.0
  5972. def test_title_inset_ax():
  5973. # Title should be above any child axes
  5974. mpl.rcParams['axes.titley'] = None
  5975. fig, ax = plt.subplots()
  5976. ax.set_title('Title')
  5977. fig.draw_without_rendering()
  5978. assert ax.title.get_position()[1] == 1
  5979. ax.inset_axes([0, 1, 1, 0.1])
  5980. fig.draw_without_rendering()
  5981. assert ax.title.get_position()[1] == 1.1
  5982. def test_offset_label_color():
  5983. # Tests issue 6440
  5984. fig, ax = plt.subplots()
  5985. ax.plot([1.01e9, 1.02e9, 1.03e9])
  5986. ax.yaxis.set_tick_params(labelcolor='red')
  5987. assert ax.yaxis.get_offset_text().get_color() == 'red'
  5988. def test_offset_text_visible():
  5989. fig, ax = plt.subplots()
  5990. ax.plot([1.01e9, 1.02e9, 1.03e9])
  5991. ax.yaxis.set_tick_params(label1On=False, label2On=True)
  5992. assert ax.yaxis.get_offset_text().get_visible()
  5993. ax.yaxis.set_tick_params(label2On=False)
  5994. assert not ax.yaxis.get_offset_text().get_visible()
  5995. def test_large_offset():
  5996. fig, ax = plt.subplots()
  5997. ax.plot((1 + np.array([0, 1.e-12])) * 1.e27)
  5998. fig.canvas.draw()
  5999. def test_barb_units():
  6000. fig, ax = plt.subplots()
  6001. dates = [datetime.datetime(2017, 7, 15, 18, i) for i in range(0, 60, 10)]
  6002. y = np.linspace(0, 5, len(dates))
  6003. u = v = np.linspace(0, 50, len(dates))
  6004. ax.barbs(dates, y, u, v)
  6005. def test_quiver_units():
  6006. fig, ax = plt.subplots()
  6007. dates = [datetime.datetime(2017, 7, 15, 18, i) for i in range(0, 60, 10)]
  6008. y = np.linspace(0, 5, len(dates))
  6009. u = v = np.linspace(0, 50, len(dates))
  6010. ax.quiver(dates, y, u, v)
  6011. def test_bar_color_cycle():
  6012. to_rgb = mcolors.to_rgb
  6013. fig, ax = plt.subplots()
  6014. for j in range(5):
  6015. ln, = ax.plot(range(3))
  6016. brs = ax.bar(range(3), range(3))
  6017. for br in brs:
  6018. assert to_rgb(ln.get_color()) == to_rgb(br.get_facecolor())
  6019. def test_tick_param_label_rotation():
  6020. fix, (ax, ax2) = plt.subplots(1, 2)
  6021. ax.plot([0, 1], [0, 1])
  6022. ax2.plot([0, 1], [0, 1])
  6023. ax.xaxis.set_tick_params(which='both', rotation=75)
  6024. ax.yaxis.set_tick_params(which='both', rotation=90)
  6025. for text in ax.get_xticklabels(which='both'):
  6026. assert text.get_rotation() == 75
  6027. for text in ax.get_yticklabels(which='both'):
  6028. assert text.get_rotation() == 90
  6029. ax2.tick_params(axis='x', labelrotation=53)
  6030. ax2.tick_params(axis='y', rotation=35)
  6031. for text in ax2.get_xticklabels(which='major'):
  6032. assert text.get_rotation() == 53
  6033. for text in ax2.get_yticklabels(which='major'):
  6034. assert text.get_rotation() == 35
  6035. @mpl.style.context('default')
  6036. def test_fillbetween_cycle():
  6037. fig, ax = plt.subplots()
  6038. for j in range(3):
  6039. cc = ax.fill_between(range(3), range(3))
  6040. target = mcolors.to_rgba(f'C{j}')
  6041. assert tuple(cc.get_facecolors().squeeze()) == tuple(target)
  6042. for j in range(3, 6):
  6043. cc = ax.fill_betweenx(range(3), range(3))
  6044. target = mcolors.to_rgba(f'C{j}')
  6045. assert tuple(cc.get_facecolors().squeeze()) == tuple(target)
  6046. target = mcolors.to_rgba('k')
  6047. for al in ['facecolor', 'facecolors', 'color']:
  6048. cc = ax.fill_between(range(3), range(3), **{al: 'k'})
  6049. assert tuple(cc.get_facecolors().squeeze()) == tuple(target)
  6050. edge_target = mcolors.to_rgba('k')
  6051. for j, el in enumerate(['edgecolor', 'edgecolors'], start=6):
  6052. cc = ax.fill_between(range(3), range(3), **{el: 'k'})
  6053. face_target = mcolors.to_rgba(f'C{j}')
  6054. assert tuple(cc.get_facecolors().squeeze()) == tuple(face_target)
  6055. assert tuple(cc.get_edgecolors().squeeze()) == tuple(edge_target)
  6056. def test_log_margins():
  6057. plt.rcParams['axes.autolimit_mode'] = 'data'
  6058. fig, ax = plt.subplots()
  6059. margin = 0.05
  6060. ax.set_xmargin(margin)
  6061. ax.semilogx([10, 100], [10, 100])
  6062. xlim0, xlim1 = ax.get_xlim()
  6063. transform = ax.xaxis.get_transform()
  6064. xlim0t, xlim1t = transform.transform([xlim0, xlim1])
  6065. x0t, x1t = transform.transform([10, 100])
  6066. delta = (x1t - x0t) * margin
  6067. assert_allclose([xlim0t + delta, xlim1t - delta], [x0t, x1t])
  6068. def test_color_length_mismatch():
  6069. N = 5
  6070. x, y = np.arange(N), np.arange(N)
  6071. colors = np.arange(N+1)
  6072. fig, ax = plt.subplots()
  6073. with pytest.raises(ValueError):
  6074. ax.scatter(x, y, c=colors)
  6075. with pytest.warns(match="argument looks like a single numeric RGB"):
  6076. ax.scatter(x, y, c=(0.5, 0.5, 0.5))
  6077. ax.scatter(x, y, c=[(0.5, 0.5, 0.5)] * N)
  6078. def test_eventplot_legend():
  6079. plt.eventplot([1.0], label='Label')
  6080. plt.legend()
  6081. @pytest.mark.parametrize('err, args, kwargs, match', (
  6082. (ValueError, [[1]], {'lineoffsets': []}, 'lineoffsets cannot be empty'),
  6083. (ValueError, [[1]], {'linelengths': []}, 'linelengths cannot be empty'),
  6084. (ValueError, [[1]], {'linewidths': []}, 'linewidths cannot be empty'),
  6085. (ValueError, [[1]], {'linestyles': []}, 'linestyles cannot be empty'),
  6086. (ValueError, [[1]], {'alpha': []}, 'alpha cannot be empty'),
  6087. (ValueError, [1], {}, 'positions must be one-dimensional'),
  6088. (ValueError, [[1]], {'lineoffsets': [1, 2]},
  6089. 'lineoffsets and positions are unequal sized sequences'),
  6090. (ValueError, [[1]], {'linelengths': [1, 2]},
  6091. 'linelengths and positions are unequal sized sequences'),
  6092. (ValueError, [[1]], {'linewidths': [1, 2]},
  6093. 'linewidths and positions are unequal sized sequences'),
  6094. (ValueError, [[1]], {'linestyles': [1, 2]},
  6095. 'linestyles and positions are unequal sized sequences'),
  6096. (ValueError, [[1]], {'alpha': [1, 2]},
  6097. 'alpha and positions are unequal sized sequences'),
  6098. (ValueError, [[1]], {'colors': [1, 2]},
  6099. 'colors and positions are unequal sized sequences'),
  6100. ))
  6101. def test_eventplot_errors(err, args, kwargs, match):
  6102. with pytest.raises(err, match=match):
  6103. plt.eventplot(*args, **kwargs)
  6104. def test_bar_broadcast_args():
  6105. fig, ax = plt.subplots()
  6106. # Check that a bar chart with a single height for all bars works.
  6107. ax.bar(range(4), 1)
  6108. # Check that a horizontal chart with one width works.
  6109. ax.barh(0, 1, left=range(4), height=1)
  6110. # Check that edgecolor gets broadcast.
  6111. rect1, rect2 = ax.bar([0, 1], [0, 1], edgecolor=(.1, .2, .3, .4))
  6112. assert rect1.get_edgecolor() == rect2.get_edgecolor() == (.1, .2, .3, .4)
  6113. def test_invalid_axis_limits():
  6114. plt.plot([0, 1], [0, 1])
  6115. with pytest.raises(ValueError):
  6116. plt.xlim(np.nan)
  6117. with pytest.raises(ValueError):
  6118. plt.xlim(np.inf)
  6119. with pytest.raises(ValueError):
  6120. plt.ylim(np.nan)
  6121. with pytest.raises(ValueError):
  6122. plt.ylim(np.inf)
  6123. # Test all 4 combinations of logs/symlogs for minorticks_on()
  6124. @pytest.mark.parametrize('xscale', ['symlog', 'log'])
  6125. @pytest.mark.parametrize('yscale', ['symlog', 'log'])
  6126. def test_minorticks_on(xscale, yscale):
  6127. ax = plt.subplot()
  6128. ax.plot([1, 2, 3, 4])
  6129. ax.set_xscale(xscale)
  6130. ax.set_yscale(yscale)
  6131. ax.minorticks_on()
  6132. def test_twinx_knows_limits():
  6133. fig, ax = plt.subplots()
  6134. ax.axvspan(1, 2)
  6135. xtwin = ax.twinx()
  6136. xtwin.plot([0, 0.5], [1, 2])
  6137. # control axis
  6138. fig2, ax2 = plt.subplots()
  6139. ax2.axvspan(1, 2)
  6140. ax2.plot([0, 0.5], [1, 2])
  6141. assert_array_equal(xtwin.viewLim.intervalx, ax2.viewLim.intervalx)
  6142. def test_zero_linewidth():
  6143. # Check that setting a zero linewidth doesn't error
  6144. plt.plot([0, 1], [0, 1], ls='--', lw=0)
  6145. def test_empty_errorbar_legend():
  6146. fig, ax = plt.subplots()
  6147. ax.errorbar([], [], xerr=[], label='empty y')
  6148. ax.errorbar([], [], yerr=[], label='empty x')
  6149. ax.legend()
  6150. @check_figures_equal(extensions=["png"])
  6151. def test_plot_decimal(fig_test, fig_ref):
  6152. x0 = np.arange(-10, 10, 0.3)
  6153. y0 = [5.2 * x ** 3 - 2.1 * x ** 2 + 7.34 * x + 4.5 for x in x0]
  6154. x = [Decimal(i) for i in x0]
  6155. y = [Decimal(i) for i in y0]
  6156. # Test image - line plot with Decimal input
  6157. fig_test.subplots().plot(x, y)
  6158. # Reference image
  6159. fig_ref.subplots().plot(x0, y0)
  6160. # pdf and svg tests fail using travis' old versions of gs and inkscape.
  6161. @check_figures_equal(extensions=["png"])
  6162. def test_markerfacecolor_none_alpha(fig_test, fig_ref):
  6163. fig_test.subplots().plot(0, "o", mfc="none", alpha=.5)
  6164. fig_ref.subplots().plot(0, "o", mfc="w", alpha=.5)
  6165. def test_tick_padding_tightbbox():
  6166. """Test that tick padding gets turned off if axis is off"""
  6167. plt.rcParams["xtick.direction"] = "out"
  6168. plt.rcParams["ytick.direction"] = "out"
  6169. fig, ax = plt.subplots()
  6170. bb = ax.get_tightbbox(fig.canvas.get_renderer())
  6171. ax.axis('off')
  6172. bb2 = ax.get_tightbbox(fig.canvas.get_renderer())
  6173. assert bb.x0 < bb2.x0
  6174. assert bb.y0 < bb2.y0
  6175. def test_inset():
  6176. """
  6177. Ensure that inset_ax argument is indeed optional
  6178. """
  6179. dx, dy = 0.05, 0.05
  6180. # generate 2 2d grids for the x & y bounds
  6181. y, x = np.mgrid[slice(1, 5 + dy, dy),
  6182. slice(1, 5 + dx, dx)]
  6183. z = np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
  6184. fig, ax = plt.subplots()
  6185. ax.pcolormesh(x, y, z[:-1, :-1])
  6186. ax.set_aspect(1.)
  6187. ax.apply_aspect()
  6188. # we need to apply_aspect to make the drawing below work.
  6189. xlim = [1.5, 2.15]
  6190. ylim = [2, 2.5]
  6191. rect = [xlim[0], ylim[0], xlim[1] - xlim[0], ylim[1] - ylim[0]]
  6192. inset = ax.indicate_inset(bounds=rect)
  6193. assert inset.connectors is None
  6194. fig.canvas.draw()
  6195. xx = np.array([[1.5, 2.],
  6196. [2.15, 2.5]])
  6197. assert np.all(inset.rectangle.get_bbox().get_points() == xx)
  6198. def test_zoom_inset():
  6199. dx, dy = 0.05, 0.05
  6200. # generate 2 2d grids for the x & y bounds
  6201. y, x = np.mgrid[slice(1, 5 + dy, dy),
  6202. slice(1, 5 + dx, dx)]
  6203. z = np.sin(x)**10 + np.cos(10 + y*x) * np.cos(x)
  6204. fig, ax = plt.subplots()
  6205. ax.pcolormesh(x, y, z[:-1, :-1])
  6206. ax.set_aspect(1.)
  6207. ax.apply_aspect()
  6208. # we need to apply_aspect to make the drawing below work.
  6209. # Make the inset_axes... Position axes coordinates...
  6210. axin1 = ax.inset_axes([0.7, 0.7, 0.35, 0.35])
  6211. # redraw the data in the inset axes...
  6212. axin1.pcolormesh(x, y, z[:-1, :-1])
  6213. axin1.set_xlim([1.5, 2.15])
  6214. axin1.set_ylim([2, 2.5])
  6215. axin1.set_aspect(ax.get_aspect())
  6216. with pytest.warns(mpl.MatplotlibDeprecationWarning):
  6217. rec, connectors = ax.indicate_inset_zoom(axin1)
  6218. fig.canvas.draw()
  6219. assert len(connectors) == 4
  6220. xx = np.array([[1.5, 2.],
  6221. [2.15, 2.5]])
  6222. assert np.all(rec.get_bbox().get_points() == xx)
  6223. xx = np.array([[0.6325, 0.692308],
  6224. [0.8425, 0.907692]])
  6225. np.testing.assert_allclose(
  6226. axin1.get_position().get_points(), xx, rtol=1e-4)
  6227. @image_comparison(['inset_polar.png'], remove_text=True, style='mpl20')
  6228. def test_inset_polar():
  6229. _, ax = plt.subplots()
  6230. axins = ax.inset_axes([0.5, 0.1, 0.45, 0.45], polar=True)
  6231. assert isinstance(axins, PolarAxes)
  6232. r = np.arange(0, 2, 0.01)
  6233. theta = 2 * np.pi * r
  6234. ax.plot(theta, r)
  6235. axins.plot(theta, r)
  6236. def test_inset_projection():
  6237. _, ax = plt.subplots()
  6238. axins = ax.inset_axes([0.2, 0.2, 0.3, 0.3], projection="hammer")
  6239. assert isinstance(axins, HammerAxes)
  6240. def test_inset_subclass():
  6241. _, ax = plt.subplots()
  6242. axins = ax.inset_axes([0.2, 0.2, 0.3, 0.3], axes_class=AA.Axes)
  6243. assert isinstance(axins, AA.Axes)
  6244. @pytest.mark.parametrize('x_inverted', [False, True])
  6245. @pytest.mark.parametrize('y_inverted', [False, True])
  6246. def test_indicate_inset_inverted(x_inverted, y_inverted):
  6247. """
  6248. Test that the inset lines are correctly located with inverted data axes.
  6249. """
  6250. fig, (ax1, ax2) = plt.subplots(1, 2)
  6251. x = np.arange(10)
  6252. ax1.plot(x, x, 'o')
  6253. if x_inverted:
  6254. ax1.invert_xaxis()
  6255. if y_inverted:
  6256. ax1.invert_yaxis()
  6257. inset = ax1.indicate_inset([2, 2, 5, 4], ax2)
  6258. lower_left, upper_left, lower_right, upper_right = inset.connectors
  6259. sign_x = -1 if x_inverted else 1
  6260. sign_y = -1 if y_inverted else 1
  6261. assert sign_x * (lower_right.xy2[0] - lower_left.xy2[0]) > 0
  6262. assert sign_x * (upper_right.xy2[0] - upper_left.xy2[0]) > 0
  6263. assert sign_y * (upper_left.xy2[1] - lower_left.xy2[1]) > 0
  6264. assert sign_y * (upper_right.xy2[1] - lower_right.xy2[1]) > 0
  6265. def test_set_position():
  6266. fig, ax = plt.subplots()
  6267. ax.set_aspect(3.)
  6268. ax.set_position([0.1, 0.1, 0.4, 0.4], which='both')
  6269. assert np.allclose(ax.get_position().width, 0.1)
  6270. ax.set_aspect(2.)
  6271. ax.set_position([0.1, 0.1, 0.4, 0.4], which='original')
  6272. assert np.allclose(ax.get_position().width, 0.15)
  6273. ax.set_aspect(3.)
  6274. ax.set_position([0.1, 0.1, 0.4, 0.4], which='active')
  6275. assert np.allclose(ax.get_position().width, 0.1)
  6276. def test_spines_properbbox_after_zoom():
  6277. fig, ax = plt.subplots()
  6278. bb = ax.spines.bottom.get_window_extent(fig.canvas.get_renderer())
  6279. # this is what zoom calls:
  6280. ax._set_view_from_bbox((320, 320, 500, 500), 'in',
  6281. None, False, False)
  6282. bb2 = ax.spines.bottom.get_window_extent(fig.canvas.get_renderer())
  6283. np.testing.assert_allclose(bb.get_points(), bb2.get_points(), rtol=1e-6)
  6284. def test_limits_after_scroll_zoom():
  6285. fig, ax = plt.subplots()
  6286. #
  6287. xlim = (-0.5, 0.5)
  6288. ylim = (-1, 2)
  6289. ax.set_xlim(xlim)
  6290. ax.set_ylim(ymin=ylim[0], ymax=ylim[1])
  6291. # This is what scroll zoom calls:
  6292. # Zoom with factor 1, small numerical change
  6293. ax._set_view_from_bbox((200, 200, 1.))
  6294. np.testing.assert_allclose(xlim, ax.get_xlim(), atol=1e-16)
  6295. np.testing.assert_allclose(ylim, ax.get_ylim(), atol=1e-16)
  6296. # Zoom in
  6297. ax._set_view_from_bbox((200, 200, 2.))
  6298. # Hard-coded values
  6299. new_xlim = (-0.3790322580645161, 0.12096774193548387)
  6300. new_ylim = (-0.40625, 1.09375)
  6301. res_xlim = ax.get_xlim()
  6302. res_ylim = ax.get_ylim()
  6303. np.testing.assert_allclose(res_xlim[1] - res_xlim[0], 0.5)
  6304. np.testing.assert_allclose(res_ylim[1] - res_ylim[0], 1.5)
  6305. np.testing.assert_allclose(new_xlim, res_xlim, atol=1e-16)
  6306. np.testing.assert_allclose(new_ylim, res_ylim)
  6307. # Zoom out, should be same as before, except for numerical issues
  6308. ax._set_view_from_bbox((200, 200, 0.5))
  6309. res_xlim = ax.get_xlim()
  6310. res_ylim = ax.get_ylim()
  6311. np.testing.assert_allclose(res_xlim[1] - res_xlim[0], 1)
  6312. np.testing.assert_allclose(res_ylim[1] - res_ylim[0], 3)
  6313. np.testing.assert_allclose(xlim, res_xlim, atol=1e-16)
  6314. np.testing.assert_allclose(ylim, res_ylim, atol=1e-16)
  6315. def test_gettightbbox_ignore_nan():
  6316. fig, ax = plt.subplots()
  6317. remove_ticks_and_titles(fig)
  6318. ax.text(np.nan, 1, 'Boo')
  6319. renderer = fig.canvas.get_renderer()
  6320. np.testing.assert_allclose(ax.get_tightbbox(renderer).width, 496)
  6321. def test_scatter_series_non_zero_index(pd):
  6322. # create non-zero index
  6323. ids = range(10, 18)
  6324. x = pd.Series(np.random.uniform(size=8), index=ids)
  6325. y = pd.Series(np.random.uniform(size=8), index=ids)
  6326. c = pd.Series([1, 1, 1, 1, 1, 0, 0, 0], index=ids)
  6327. plt.scatter(x, y, c)
  6328. def test_scatter_empty_data():
  6329. # making sure this does not raise an exception
  6330. plt.scatter([], [])
  6331. plt.scatter([], [], s=[], c=[])
  6332. @image_comparison(['annotate_across_transforms.png'], style='mpl20', remove_text=True,
  6333. tol=0 if platform.machine() == 'x86_64' else 0.025)
  6334. def test_annotate_across_transforms():
  6335. x = np.linspace(0, 10, 200)
  6336. y = np.exp(-x) * np.sin(x)
  6337. fig, ax = plt.subplots(figsize=(3.39, 3))
  6338. ax.plot(x, y)
  6339. axins = ax.inset_axes([0.4, 0.5, 0.3, 0.3])
  6340. axins.set_aspect(0.2)
  6341. axins.xaxis.set_visible(False)
  6342. axins.yaxis.set_visible(False)
  6343. ax.annotate("", xy=(x[150], y[150]), xycoords=ax.transData,
  6344. xytext=(1, 0), textcoords=axins.transAxes,
  6345. arrowprops=dict(arrowstyle="->"))
  6346. class _Translation(mtransforms.Transform):
  6347. input_dims = 1
  6348. output_dims = 1
  6349. def __init__(self, dx):
  6350. self.dx = dx
  6351. def transform(self, values):
  6352. return values + self.dx
  6353. def inverted(self):
  6354. return _Translation(-self.dx)
  6355. @image_comparison(['secondary_xy.png'], style='mpl20',
  6356. tol=0 if platform.machine() == 'x86_64' else 0.027)
  6357. def test_secondary_xy():
  6358. fig, axs = plt.subplots(1, 2, figsize=(10, 5), constrained_layout=True)
  6359. def invert(x):
  6360. with np.errstate(divide='ignore'):
  6361. return 1 / x
  6362. for nn, ax in enumerate(axs):
  6363. ax.plot(np.arange(2, 11), np.arange(2, 11))
  6364. if nn == 0:
  6365. secax = ax.secondary_xaxis
  6366. else:
  6367. secax = ax.secondary_yaxis
  6368. secax(0.2, functions=(invert, invert))
  6369. secax(0.4, functions=(lambda x: 2 * x, lambda x: x / 2))
  6370. secax(0.6, functions=(lambda x: x**2, lambda x: x**(1/2)))
  6371. secax(0.8)
  6372. secax("top" if nn == 0 else "right", functions=_Translation(2))
  6373. secax(6.25, transform=ax.transData)
  6374. def test_secondary_fail():
  6375. fig, ax = plt.subplots()
  6376. ax.plot(np.arange(2, 11), np.arange(2, 11))
  6377. with pytest.raises(ValueError):
  6378. ax.secondary_xaxis(0.2, functions=(lambda x: 1 / x))
  6379. with pytest.raises(ValueError):
  6380. ax.secondary_xaxis('right')
  6381. with pytest.raises(ValueError):
  6382. ax.secondary_yaxis('bottom')
  6383. with pytest.raises(TypeError):
  6384. ax.secondary_xaxis(0.2, transform='error')
  6385. def test_secondary_resize():
  6386. fig, ax = plt.subplots(figsize=(10, 5))
  6387. ax.plot(np.arange(2, 11), np.arange(2, 11))
  6388. def invert(x):
  6389. with np.errstate(divide='ignore'):
  6390. return 1 / x
  6391. ax.secondary_xaxis('top', functions=(invert, invert))
  6392. fig.canvas.draw()
  6393. fig.set_size_inches((7, 4))
  6394. assert_allclose(ax.get_position().extents, [0.125, 0.1, 0.9, 0.9])
  6395. def test_secondary_minorloc():
  6396. fig, ax = plt.subplots(figsize=(10, 5))
  6397. ax.plot(np.arange(2, 11), np.arange(2, 11))
  6398. def invert(x):
  6399. with np.errstate(divide='ignore'):
  6400. return 1 / x
  6401. secax = ax.secondary_xaxis('top', functions=(invert, invert))
  6402. assert isinstance(secax._axis.get_minor_locator(),
  6403. mticker.NullLocator)
  6404. secax.minorticks_on()
  6405. assert isinstance(secax._axis.get_minor_locator(),
  6406. mticker.AutoMinorLocator)
  6407. ax.set_xscale('log')
  6408. plt.draw()
  6409. assert isinstance(secax._axis.get_minor_locator(),
  6410. mticker.LogLocator)
  6411. ax.set_xscale('linear')
  6412. plt.draw()
  6413. assert isinstance(secax._axis.get_minor_locator(),
  6414. mticker.NullLocator)
  6415. def test_secondary_formatter():
  6416. fig, ax = plt.subplots()
  6417. ax.set_xscale("log")
  6418. secax = ax.secondary_xaxis("top")
  6419. secax.xaxis.set_major_formatter(mticker.ScalarFormatter())
  6420. fig.canvas.draw()
  6421. assert isinstance(
  6422. secax.xaxis.get_major_formatter(), mticker.ScalarFormatter)
  6423. def test_secondary_repr():
  6424. fig, ax = plt.subplots()
  6425. secax = ax.secondary_xaxis("top")
  6426. assert repr(secax) == '<SecondaryAxis: >'
  6427. @image_comparison(['axis_options.png'], remove_text=True, style='mpl20')
  6428. def test_axis_options():
  6429. fig, axes = plt.subplots(2, 3)
  6430. for i, option in enumerate(('scaled', 'tight', 'image')):
  6431. # Draw a line and a circle fitting within the boundaries of the line
  6432. # The circle should look like a circle for 'scaled' and 'image'
  6433. # High/narrow aspect ratio
  6434. axes[0, i].plot((1, 2), (1, 3.2))
  6435. axes[0, i].axis(option)
  6436. axes[0, i].add_artist(mpatches.Circle((1.5, 1.5), radius=0.5,
  6437. facecolor='none', edgecolor='k'))
  6438. # Low/wide aspect ratio
  6439. axes[1, i].plot((1, 2.25), (1, 1.75))
  6440. axes[1, i].axis(option)
  6441. axes[1, i].add_artist(mpatches.Circle((1.5, 1.25), radius=0.25,
  6442. facecolor='none', edgecolor='k'))
  6443. def color_boxes(fig, ax):
  6444. """
  6445. Helper for the tests below that test the extents of various Axes elements
  6446. """
  6447. fig.canvas.draw()
  6448. renderer = fig.canvas.get_renderer()
  6449. bbaxis = []
  6450. for nn, axx in enumerate([ax.xaxis, ax.yaxis]):
  6451. bb = axx.get_tightbbox(renderer)
  6452. if bb:
  6453. axisr = mpatches.Rectangle(
  6454. (bb.x0, bb.y0), width=bb.width, height=bb.height,
  6455. linewidth=0.7, edgecolor='y', facecolor="none", transform=None,
  6456. zorder=3)
  6457. fig.add_artist(axisr)
  6458. bbaxis += [bb]
  6459. bbspines = []
  6460. for nn, a in enumerate(['bottom', 'top', 'left', 'right']):
  6461. bb = ax.spines[a].get_window_extent(renderer)
  6462. spiner = mpatches.Rectangle(
  6463. (bb.x0, bb.y0), width=bb.width, height=bb.height,
  6464. linewidth=0.7, edgecolor="green", facecolor="none", transform=None,
  6465. zorder=3)
  6466. fig.add_artist(spiner)
  6467. bbspines += [bb]
  6468. bb = ax.get_window_extent()
  6469. rect2 = mpatches.Rectangle(
  6470. (bb.x0, bb.y0), width=bb.width, height=bb.height,
  6471. linewidth=1.5, edgecolor="magenta", facecolor="none", transform=None,
  6472. zorder=2)
  6473. fig.add_artist(rect2)
  6474. bbax = bb
  6475. bb2 = ax.get_tightbbox(renderer)
  6476. rect2 = mpatches.Rectangle(
  6477. (bb2.x0, bb2.y0), width=bb2.width, height=bb2.height,
  6478. linewidth=3, edgecolor="red", facecolor="none", transform=None,
  6479. zorder=1)
  6480. fig.add_artist(rect2)
  6481. bbtb = bb2
  6482. return bbaxis, bbspines, bbax, bbtb
  6483. def test_normal_axes():
  6484. with rc_context({'_internal.classic_mode': False}):
  6485. fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
  6486. fig.canvas.draw()
  6487. plt.close(fig)
  6488. bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
  6489. # test the axis bboxes
  6490. target = [
  6491. [123.375, 75.88888888888886, 983.25, 33.0],
  6492. [85.51388888888889, 99.99999999999997, 53.375, 993.0]
  6493. ]
  6494. for nn, b in enumerate(bbaxis):
  6495. targetbb = mtransforms.Bbox.from_bounds(*target[nn])
  6496. assert_array_almost_equal(b.bounds, targetbb.bounds, decimal=2)
  6497. target = [
  6498. [150.0, 119.999, 930.0, 11.111],
  6499. [150.0, 1080.0, 930.0, 0.0],
  6500. [150.0, 119.9999, 11.111, 960.0],
  6501. [1068.8888, 119.9999, 11.111, 960.0]
  6502. ]
  6503. for nn, b in enumerate(bbspines):
  6504. targetbb = mtransforms.Bbox.from_bounds(*target[nn])
  6505. assert_array_almost_equal(b.bounds, targetbb.bounds, decimal=2)
  6506. target = [150.0, 119.99999999999997, 930.0, 960.0]
  6507. targetbb = mtransforms.Bbox.from_bounds(*target)
  6508. assert_array_almost_equal(bbax.bounds, targetbb.bounds, decimal=2)
  6509. target = [85.5138, 75.88888, 1021.11, 1017.11]
  6510. targetbb = mtransforms.Bbox.from_bounds(*target)
  6511. assert_array_almost_equal(bbtb.bounds, targetbb.bounds, decimal=2)
  6512. # test that get_position roundtrips to get_window_extent
  6513. axbb = ax.get_position().transformed(fig.transFigure).bounds
  6514. assert_array_almost_equal(axbb, ax.get_window_extent().bounds, decimal=2)
  6515. def test_nodecorator():
  6516. with rc_context({'_internal.classic_mode': False}):
  6517. fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
  6518. fig.canvas.draw()
  6519. ax.set(xticklabels=[], yticklabels=[])
  6520. bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
  6521. # test the axis bboxes
  6522. for nn, b in enumerate(bbaxis):
  6523. assert b is None
  6524. target = [
  6525. [150.0, 119.999, 930.0, 11.111],
  6526. [150.0, 1080.0, 930.0, 0.0],
  6527. [150.0, 119.9999, 11.111, 960.0],
  6528. [1068.8888, 119.9999, 11.111, 960.0]
  6529. ]
  6530. for nn, b in enumerate(bbspines):
  6531. targetbb = mtransforms.Bbox.from_bounds(*target[nn])
  6532. assert_allclose(b.bounds, targetbb.bounds, atol=1e-2)
  6533. target = [150.0, 119.99999999999997, 930.0, 960.0]
  6534. targetbb = mtransforms.Bbox.from_bounds(*target)
  6535. assert_allclose(bbax.bounds, targetbb.bounds, atol=1e-2)
  6536. target = [150., 120., 930., 960.]
  6537. targetbb = mtransforms.Bbox.from_bounds(*target)
  6538. assert_allclose(bbtb.bounds, targetbb.bounds, atol=1e-2)
  6539. def test_displaced_spine():
  6540. with rc_context({'_internal.classic_mode': False}):
  6541. fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
  6542. ax.set(xticklabels=[], yticklabels=[])
  6543. ax.spines.bottom.set_position(('axes', -0.1))
  6544. fig.canvas.draw()
  6545. bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
  6546. targets = [
  6547. [150., 24., 930., 11.111111],
  6548. [150.0, 1080.0, 930.0, 0.0],
  6549. [150.0, 119.9999, 11.111, 960.0],
  6550. [1068.8888, 119.9999, 11.111, 960.0]
  6551. ]
  6552. for target, bbspine in zip(targets, bbspines):
  6553. targetbb = mtransforms.Bbox.from_bounds(*target)
  6554. assert_allclose(bbspine.bounds, targetbb.bounds, atol=1e-2)
  6555. target = [150.0, 119.99999999999997, 930.0, 960.0]
  6556. targetbb = mtransforms.Bbox.from_bounds(*target)
  6557. assert_allclose(bbax.bounds, targetbb.bounds, atol=1e-2)
  6558. target = [150., 24., 930., 1056.]
  6559. targetbb = mtransforms.Bbox.from_bounds(*target)
  6560. assert_allclose(bbtb.bounds, targetbb.bounds, atol=1e-2)
  6561. def test_tickdirs():
  6562. """
  6563. Switch the tickdirs and make sure the bboxes switch with them
  6564. """
  6565. targets = [[[150.0, 120.0, 930.0, 11.1111],
  6566. [150.0, 120.0, 11.111, 960.0]],
  6567. [[150.0, 108.8889, 930.0, 11.111111111111114],
  6568. [138.889, 120, 11.111, 960.0]],
  6569. [[150.0, 114.44444444444441, 930.0, 11.111111111111114],
  6570. [144.44444444444446, 119.999, 11.111, 960.0]]]
  6571. for dnum, dirs in enumerate(['in', 'out', 'inout']):
  6572. with rc_context({'_internal.classic_mode': False}):
  6573. fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
  6574. ax.tick_params(direction=dirs)
  6575. fig.canvas.draw()
  6576. bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
  6577. for nn, num in enumerate([0, 2]):
  6578. targetbb = mtransforms.Bbox.from_bounds(*targets[dnum][nn])
  6579. assert_allclose(
  6580. bbspines[num].bounds, targetbb.bounds, atol=1e-2)
  6581. def test_minor_accountedfor():
  6582. with rc_context({'_internal.classic_mode': False}):
  6583. fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
  6584. fig.canvas.draw()
  6585. ax.tick_params(which='both', direction='out')
  6586. bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
  6587. bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
  6588. targets = [[150.0, 108.88888888888886, 930.0, 11.111111111111114],
  6589. [138.8889, 119.9999, 11.1111, 960.0]]
  6590. for n in range(2):
  6591. targetbb = mtransforms.Bbox.from_bounds(*targets[n])
  6592. assert_allclose(
  6593. bbspines[n * 2].bounds, targetbb.bounds, atol=1e-2)
  6594. fig, ax = plt.subplots(dpi=200, figsize=(6, 6))
  6595. fig.canvas.draw()
  6596. ax.tick_params(which='both', direction='out')
  6597. ax.minorticks_on()
  6598. ax.tick_params(axis='both', which='minor', length=30)
  6599. fig.canvas.draw()
  6600. bbaxis, bbspines, bbax, bbtb = color_boxes(fig, ax)
  6601. targets = [[150.0, 36.66666666666663, 930.0, 83.33333333333334],
  6602. [66.6667, 120.0, 83.3333, 960.0]]
  6603. for n in range(2):
  6604. targetbb = mtransforms.Bbox.from_bounds(*targets[n])
  6605. assert_allclose(
  6606. bbspines[n * 2].bounds, targetbb.bounds, atol=1e-2)
  6607. @check_figures_equal(extensions=["png"])
  6608. def test_axis_bool_arguments(fig_test, fig_ref):
  6609. # Test if False and "off" give the same
  6610. fig_test.add_subplot(211).axis(False)
  6611. fig_ref.add_subplot(211).axis("off")
  6612. # Test if True after False gives the same as "on"
  6613. ax = fig_test.add_subplot(212)
  6614. ax.axis(False)
  6615. ax.axis(True)
  6616. fig_ref.add_subplot(212).axis("on")
  6617. def test_axis_extent_arg():
  6618. fig, ax = plt.subplots()
  6619. xmin = 5
  6620. xmax = 10
  6621. ymin = 15
  6622. ymax = 20
  6623. extent = ax.axis([xmin, xmax, ymin, ymax])
  6624. # test that the docstring is correct
  6625. assert tuple(extent) == (xmin, xmax, ymin, ymax)
  6626. # test that limits were set per the docstring
  6627. assert (xmin, xmax) == ax.get_xlim()
  6628. assert (ymin, ymax) == ax.get_ylim()
  6629. def test_axis_extent_arg2():
  6630. # Same as test_axis_extent_arg, but with keyword arguments
  6631. fig, ax = plt.subplots()
  6632. xmin = 5
  6633. xmax = 10
  6634. ymin = 15
  6635. ymax = 20
  6636. extent = ax.axis(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
  6637. # test that the docstring is correct
  6638. assert tuple(extent) == (xmin, xmax, ymin, ymax)
  6639. # test that limits were set per the docstring
  6640. assert (xmin, xmax) == ax.get_xlim()
  6641. assert (ymin, ymax) == ax.get_ylim()
  6642. def test_hist_auto_bins():
  6643. _, bins, _ = plt.hist([[1, 2, 3], [3, 4, 5, 6]], bins='auto')
  6644. assert bins[0] <= 1
  6645. assert bins[-1] >= 6
  6646. def test_hist_nan_data():
  6647. fig, (ax1, ax2) = plt.subplots(2)
  6648. data = [1, 2, 3]
  6649. nan_data = data + [np.nan]
  6650. bins, edges, _ = ax1.hist(data)
  6651. with np.errstate(invalid='ignore'):
  6652. nanbins, nanedges, _ = ax2.hist(nan_data)
  6653. np.testing.assert_allclose(bins, nanbins)
  6654. np.testing.assert_allclose(edges, nanedges)
  6655. def test_hist_range_and_density():
  6656. _, bins, _ = plt.hist(np.random.rand(10), "auto",
  6657. range=(0, 1), density=True)
  6658. assert bins[0] == 0
  6659. assert bins[-1] == 1
  6660. def test_bar_errbar_zorder():
  6661. # Check that the zorder of errorbars is always greater than the bar they
  6662. # are plotted on
  6663. fig, ax = plt.subplots()
  6664. x = [1, 2, 3]
  6665. barcont = ax.bar(x=x, height=x, yerr=x, capsize=5, zorder=3)
  6666. data_line, caplines, barlinecols = barcont.errorbar.lines
  6667. for bar in barcont.patches:
  6668. for capline in caplines:
  6669. assert capline.zorder > bar.zorder
  6670. for barlinecol in barlinecols:
  6671. assert barlinecol.zorder > bar.zorder
  6672. def test_set_ticks_inverted():
  6673. fig, ax = plt.subplots()
  6674. ax.invert_xaxis()
  6675. ax.set_xticks([.3, .7])
  6676. assert ax.get_xlim() == (1, 0)
  6677. ax.set_xticks([-1])
  6678. assert ax.get_xlim() == (1, -1)
  6679. def test_aspect_nonlinear_adjustable_box():
  6680. fig = plt.figure(figsize=(10, 10)) # Square.
  6681. ax = fig.add_subplot()
  6682. ax.plot([.4, .6], [.4, .6]) # Set minpos to keep logit happy.
  6683. ax.set(xscale="log", xlim=(1, 10),
  6684. yscale="logit", ylim=(1/11, 1/1001),
  6685. aspect=1, adjustable="box")
  6686. ax.margins(0)
  6687. pos = fig.transFigure.transform_bbox(ax.get_position())
  6688. assert pos.height / pos.width == pytest.approx(2)
  6689. def test_aspect_nonlinear_adjustable_datalim():
  6690. fig = plt.figure(figsize=(10, 10)) # Square.
  6691. ax = fig.add_axes([.1, .1, .8, .8]) # Square.
  6692. ax.plot([.4, .6], [.4, .6]) # Set minpos to keep logit happy.
  6693. ax.set(xscale="log", xlim=(1, 100),
  6694. yscale="logit", ylim=(1 / 101, 1 / 11),
  6695. aspect=1, adjustable="datalim")
  6696. ax.margins(0)
  6697. ax.apply_aspect()
  6698. assert ax.get_xlim() == pytest.approx([1*10**(1/2), 100/10**(1/2)])
  6699. assert ax.get_ylim() == (1 / 101, 1 / 11)
  6700. def test_box_aspect():
  6701. # Test if axes with box_aspect=1 has same dimensions
  6702. # as axes with aspect equal and adjustable="box"
  6703. fig1, ax1 = plt.subplots()
  6704. axtwin = ax1.twinx()
  6705. axtwin.plot([12, 344])
  6706. ax1.set_box_aspect(1)
  6707. assert ax1.get_box_aspect() == 1.0
  6708. fig2, ax2 = plt.subplots()
  6709. ax2.margins(0)
  6710. ax2.plot([0, 2], [6, 8])
  6711. ax2.set_aspect("equal", adjustable="box")
  6712. fig1.canvas.draw()
  6713. fig2.canvas.draw()
  6714. bb1 = ax1.get_position()
  6715. bbt = axtwin.get_position()
  6716. bb2 = ax2.get_position()
  6717. assert_array_equal(bb1.extents, bb2.extents)
  6718. assert_array_equal(bbt.extents, bb2.extents)
  6719. def test_box_aspect_custom_position():
  6720. # Test if axes with custom position and box_aspect
  6721. # behaves the same independent of the order of setting those.
  6722. fig1, ax1 = plt.subplots()
  6723. ax1.set_position([0.1, 0.1, 0.9, 0.2])
  6724. fig1.canvas.draw()
  6725. ax1.set_box_aspect(1.)
  6726. fig2, ax2 = plt.subplots()
  6727. ax2.set_box_aspect(1.)
  6728. fig2.canvas.draw()
  6729. ax2.set_position([0.1, 0.1, 0.9, 0.2])
  6730. fig1.canvas.draw()
  6731. fig2.canvas.draw()
  6732. bb1 = ax1.get_position()
  6733. bb2 = ax2.get_position()
  6734. assert_array_equal(bb1.extents, bb2.extents)
  6735. def test_bbox_aspect_axes_init():
  6736. # Test that box_aspect can be given to axes init and produces
  6737. # all equal square axes.
  6738. fig, axs = plt.subplots(2, 3, subplot_kw=dict(box_aspect=1),
  6739. constrained_layout=True)
  6740. fig.canvas.draw()
  6741. renderer = fig.canvas.get_renderer()
  6742. sizes = []
  6743. for ax in axs.flat:
  6744. bb = ax.get_window_extent(renderer)
  6745. sizes.extend([bb.width, bb.height])
  6746. assert_allclose(sizes, sizes[0])
  6747. def test_set_aspect_negative():
  6748. fig, ax = plt.subplots()
  6749. with pytest.raises(ValueError, match="must be finite and positive"):
  6750. ax.set_aspect(-1)
  6751. with pytest.raises(ValueError, match="must be finite and positive"):
  6752. ax.set_aspect(0)
  6753. with pytest.raises(ValueError, match="must be finite and positive"):
  6754. ax.set_aspect(np.inf)
  6755. with pytest.raises(ValueError, match="must be finite and positive"):
  6756. ax.set_aspect(-np.inf)
  6757. def test_redraw_in_frame():
  6758. fig, ax = plt.subplots(1, 1)
  6759. ax.plot([1, 2, 3])
  6760. fig.canvas.draw()
  6761. ax.redraw_in_frame()
  6762. def test_invisible_axes_events():
  6763. # invisible axes should not respond to events...
  6764. fig, ax = plt.subplots()
  6765. assert fig.canvas.inaxes((200, 200)) is not None
  6766. ax.set_visible(False)
  6767. assert fig.canvas.inaxes((200, 200)) is None
  6768. def test_xtickcolor_is_not_markercolor():
  6769. plt.rcParams['lines.markeredgecolor'] = 'white'
  6770. ax = plt.axes()
  6771. ticks = ax.xaxis.get_major_ticks()
  6772. for tick in ticks:
  6773. assert tick.tick1line.get_markeredgecolor() != 'white'
  6774. def test_ytickcolor_is_not_markercolor():
  6775. plt.rcParams['lines.markeredgecolor'] = 'white'
  6776. ax = plt.axes()
  6777. ticks = ax.yaxis.get_major_ticks()
  6778. for tick in ticks:
  6779. assert tick.tick1line.get_markeredgecolor() != 'white'
  6780. @pytest.mark.parametrize('axis', ('x', 'y'))
  6781. @pytest.mark.parametrize('auto', (True, False, None))
  6782. def test_unautoscale(axis, auto):
  6783. fig, ax = plt.subplots()
  6784. x = np.arange(100)
  6785. y = np.linspace(-.1, .1, 100)
  6786. ax.scatter(y, x)
  6787. get_autoscale_on = getattr(ax, f'get_autoscale{axis}_on')
  6788. set_lim = getattr(ax, f'set_{axis}lim')
  6789. get_lim = getattr(ax, f'get_{axis}lim')
  6790. post_auto = get_autoscale_on() if auto is None else auto
  6791. set_lim((-0.5, 0.5), auto=auto)
  6792. assert post_auto == get_autoscale_on()
  6793. fig.canvas.draw()
  6794. assert_array_equal(get_lim(), (-0.5, 0.5))
  6795. @check_figures_equal(extensions=["png"])
  6796. def test_polar_interpolation_steps_variable_r(fig_test, fig_ref):
  6797. l, = fig_test.add_subplot(projection="polar").plot([0, np.pi/2], [1, 2])
  6798. l.get_path()._interpolation_steps = 100
  6799. fig_ref.add_subplot(projection="polar").plot(
  6800. np.linspace(0, np.pi/2, 101), np.linspace(1, 2, 101))
  6801. @mpl.style.context('default')
  6802. def test_autoscale_tiny_sticky():
  6803. fig, ax = plt.subplots()
  6804. ax.bar(0, 1e-9)
  6805. fig.canvas.draw()
  6806. assert ax.get_ylim() == (0, 1.05e-9)
  6807. def test_xtickcolor_is_not_xticklabelcolor():
  6808. plt.rcParams['xtick.color'] = 'yellow'
  6809. plt.rcParams['xtick.labelcolor'] = 'blue'
  6810. ax = plt.axes()
  6811. ticks = ax.xaxis.get_major_ticks()
  6812. for tick in ticks:
  6813. assert tick.tick1line.get_color() == 'yellow'
  6814. assert tick.label1.get_color() == 'blue'
  6815. def test_ytickcolor_is_not_yticklabelcolor():
  6816. plt.rcParams['ytick.color'] = 'yellow'
  6817. plt.rcParams['ytick.labelcolor'] = 'blue'
  6818. ax = plt.axes()
  6819. ticks = ax.yaxis.get_major_ticks()
  6820. for tick in ticks:
  6821. assert tick.tick1line.get_color() == 'yellow'
  6822. assert tick.label1.get_color() == 'blue'
  6823. def test_xaxis_offsetText_color():
  6824. plt.rcParams['xtick.labelcolor'] = 'blue'
  6825. ax = plt.axes()
  6826. assert ax.xaxis.offsetText.get_color() == 'blue'
  6827. plt.rcParams['xtick.color'] = 'yellow'
  6828. plt.rcParams['xtick.labelcolor'] = 'inherit'
  6829. ax = plt.axes()
  6830. assert ax.xaxis.offsetText.get_color() == 'yellow'
  6831. def test_yaxis_offsetText_color():
  6832. plt.rcParams['ytick.labelcolor'] = 'green'
  6833. ax = plt.axes()
  6834. assert ax.yaxis.offsetText.get_color() == 'green'
  6835. plt.rcParams['ytick.color'] = 'red'
  6836. plt.rcParams['ytick.labelcolor'] = 'inherit'
  6837. ax = plt.axes()
  6838. assert ax.yaxis.offsetText.get_color() == 'red'
  6839. @pytest.mark.parametrize('size', [size for size in mfont_manager.font_scalings
  6840. if size is not None] + [8, 10, 12])
  6841. @mpl.style.context('default')
  6842. def test_relative_ticklabel_sizes(size):
  6843. mpl.rcParams['xtick.labelsize'] = size
  6844. mpl.rcParams['ytick.labelsize'] = size
  6845. fig, ax = plt.subplots()
  6846. fig.canvas.draw()
  6847. for name, axis in zip(['x', 'y'], [ax.xaxis, ax.yaxis]):
  6848. for tick in axis.get_major_ticks():
  6849. assert tick.label1.get_size() == axis._get_tick_label_size(name)
  6850. def test_multiplot_autoscale():
  6851. fig = plt.figure()
  6852. ax1, ax2 = fig.subplots(2, 1, sharex='all')
  6853. ax1.plot([18000, 18250, 18500, 18750], [2, 3, 2, 3])
  6854. ax2.axhspan(-5, 5)
  6855. xlim = ax1.get_xlim()
  6856. assert np.allclose(xlim, [18000, 18800])
  6857. def test_sharing_does_not_link_positions():
  6858. fig = plt.figure()
  6859. ax0 = fig.add_subplot(221)
  6860. ax1 = fig.add_axes([.6, .6, .3, .3], sharex=ax0)
  6861. init_pos = ax1.get_position()
  6862. fig.subplots_adjust(left=0)
  6863. assert (ax1.get_position().get_points() == init_pos.get_points()).all()
  6864. @check_figures_equal(extensions=["pdf"])
  6865. def test_2dcolor_plot(fig_test, fig_ref):
  6866. color = np.array([0.1, 0.2, 0.3])
  6867. # plot with 1D-color:
  6868. axs = fig_test.subplots(5)
  6869. axs[0].plot([1, 2], [1, 2], c=color.reshape(-1))
  6870. with pytest.warns(match="argument looks like a single numeric RGB"):
  6871. axs[1].scatter([1, 2], [1, 2], c=color.reshape(-1))
  6872. axs[2].step([1, 2], [1, 2], c=color.reshape(-1))
  6873. axs[3].hist(np.arange(10), color=color.reshape(-1))
  6874. axs[4].bar(np.arange(10), np.arange(10), color=color.reshape(-1))
  6875. # plot with 2D-color:
  6876. axs = fig_ref.subplots(5)
  6877. axs[0].plot([1, 2], [1, 2], c=color.reshape((1, -1)))
  6878. axs[1].scatter([1, 2], [1, 2], c=color.reshape((1, -1)))
  6879. axs[2].step([1, 2], [1, 2], c=color.reshape((1, -1)))
  6880. axs[3].hist(np.arange(10), color=color.reshape((1, -1)))
  6881. axs[4].bar(np.arange(10), np.arange(10), color=color.reshape((1, -1)))
  6882. @check_figures_equal(extensions=['png'])
  6883. def test_shared_axes_clear(fig_test, fig_ref):
  6884. x = np.arange(0.0, 2*np.pi, 0.01)
  6885. y = np.sin(x)
  6886. axs = fig_ref.subplots(2, 2, sharex=True, sharey=True)
  6887. for ax in axs.flat:
  6888. ax.plot(x, y)
  6889. axs = fig_test.subplots(2, 2, sharex=True, sharey=True)
  6890. for ax in axs.flat:
  6891. ax.clear()
  6892. ax.plot(x, y)
  6893. def test_shared_axes_retick():
  6894. fig, axs = plt.subplots(2, 2, sharex='all', sharey='all')
  6895. for ax in axs.flat:
  6896. ax.plot([0, 2], 'o-')
  6897. axs[0, 0].set_xticks([-0.5, 0, 1, 1.5]) # should affect all axes xlims
  6898. for ax in axs.flat:
  6899. assert ax.get_xlim() == axs[0, 0].get_xlim()
  6900. axs[0, 0].set_yticks([-0.5, 0, 2, 2.5]) # should affect all axes ylims
  6901. for ax in axs.flat:
  6902. assert ax.get_ylim() == axs[0, 0].get_ylim()
  6903. @pytest.mark.parametrize('ha', ['left', 'center', 'right'])
  6904. def test_ylabel_ha_with_position(ha):
  6905. fig = Figure()
  6906. ax = fig.subplots()
  6907. ax.set_ylabel("test", y=1, ha=ha)
  6908. ax.yaxis.set_label_position("right")
  6909. assert ax.yaxis.label.get_ha() == ha
  6910. def test_bar_label_location_vertical():
  6911. ax = plt.gca()
  6912. xs, heights = [1, 2], [3, -4]
  6913. rects = ax.bar(xs, heights)
  6914. labels = ax.bar_label(rects)
  6915. assert labels[0].xy == (xs[0], heights[0])
  6916. assert labels[0].get_horizontalalignment() == 'center'
  6917. assert labels[0].get_verticalalignment() == 'bottom'
  6918. assert labels[1].xy == (xs[1], heights[1])
  6919. assert labels[1].get_horizontalalignment() == 'center'
  6920. assert labels[1].get_verticalalignment() == 'top'
  6921. def test_bar_label_location_vertical_yinverted():
  6922. ax = plt.gca()
  6923. ax.invert_yaxis()
  6924. xs, heights = [1, 2], [3, -4]
  6925. rects = ax.bar(xs, heights)
  6926. labels = ax.bar_label(rects)
  6927. assert labels[0].xy == (xs[0], heights[0])
  6928. assert labels[0].get_horizontalalignment() == 'center'
  6929. assert labels[0].get_verticalalignment() == 'top'
  6930. assert labels[1].xy == (xs[1], heights[1])
  6931. assert labels[1].get_horizontalalignment() == 'center'
  6932. assert labels[1].get_verticalalignment() == 'bottom'
  6933. def test_bar_label_location_horizontal():
  6934. ax = plt.gca()
  6935. ys, widths = [1, 2], [3, -4]
  6936. rects = ax.barh(ys, widths)
  6937. labels = ax.bar_label(rects)
  6938. assert labels[0].xy == (widths[0], ys[0])
  6939. assert labels[0].get_horizontalalignment() == 'left'
  6940. assert labels[0].get_verticalalignment() == 'center'
  6941. assert labels[1].xy == (widths[1], ys[1])
  6942. assert labels[1].get_horizontalalignment() == 'right'
  6943. assert labels[1].get_verticalalignment() == 'center'
  6944. def test_bar_label_location_horizontal_yinverted():
  6945. ax = plt.gca()
  6946. ax.invert_yaxis()
  6947. ys, widths = [1, 2], [3, -4]
  6948. rects = ax.barh(ys, widths)
  6949. labels = ax.bar_label(rects)
  6950. assert labels[0].xy == (widths[0], ys[0])
  6951. assert labels[0].get_horizontalalignment() == 'left'
  6952. assert labels[0].get_verticalalignment() == 'center'
  6953. assert labels[1].xy == (widths[1], ys[1])
  6954. assert labels[1].get_horizontalalignment() == 'right'
  6955. assert labels[1].get_verticalalignment() == 'center'
  6956. def test_bar_label_location_horizontal_xinverted():
  6957. ax = plt.gca()
  6958. ax.invert_xaxis()
  6959. ys, widths = [1, 2], [3, -4]
  6960. rects = ax.barh(ys, widths)
  6961. labels = ax.bar_label(rects)
  6962. assert labels[0].xy == (widths[0], ys[0])
  6963. assert labels[0].get_horizontalalignment() == 'right'
  6964. assert labels[0].get_verticalalignment() == 'center'
  6965. assert labels[1].xy == (widths[1], ys[1])
  6966. assert labels[1].get_horizontalalignment() == 'left'
  6967. assert labels[1].get_verticalalignment() == 'center'
  6968. def test_bar_label_location_horizontal_xyinverted():
  6969. ax = plt.gca()
  6970. ax.invert_xaxis()
  6971. ax.invert_yaxis()
  6972. ys, widths = [1, 2], [3, -4]
  6973. rects = ax.barh(ys, widths)
  6974. labels = ax.bar_label(rects)
  6975. assert labels[0].xy == (widths[0], ys[0])
  6976. assert labels[0].get_horizontalalignment() == 'right'
  6977. assert labels[0].get_verticalalignment() == 'center'
  6978. assert labels[1].xy == (widths[1], ys[1])
  6979. assert labels[1].get_horizontalalignment() == 'left'
  6980. assert labels[1].get_verticalalignment() == 'center'
  6981. def test_bar_label_location_center():
  6982. ax = plt.gca()
  6983. ys, widths = [1, 2], [3, -4]
  6984. rects = ax.barh(ys, widths)
  6985. labels = ax.bar_label(rects, label_type='center')
  6986. assert labels[0].xy == (0.5, 0.5)
  6987. assert labels[0].get_horizontalalignment() == 'center'
  6988. assert labels[0].get_verticalalignment() == 'center'
  6989. assert labels[1].xy == (0.5, 0.5)
  6990. assert labels[1].get_horizontalalignment() == 'center'
  6991. assert labels[1].get_verticalalignment() == 'center'
  6992. @image_comparison(['test_centered_bar_label_nonlinear.svg'])
  6993. def test_centered_bar_label_nonlinear():
  6994. _, ax = plt.subplots()
  6995. bar_container = ax.barh(['c', 'b', 'a'], [1_000, 5_000, 7_000])
  6996. ax.set_xscale('log')
  6997. ax.set_xlim(1, None)
  6998. ax.bar_label(bar_container, label_type='center')
  6999. ax.set_axis_off()
  7000. def test_centered_bar_label_label_beyond_limits():
  7001. fig, ax = plt.subplots()
  7002. last = 0
  7003. for label, value in zip(['a', 'b', 'c'], [10, 20, 50]):
  7004. bar_container = ax.barh('col', value, label=label, left=last)
  7005. ax.bar_label(bar_container, label_type='center')
  7006. last += value
  7007. ax.set_xlim(None, 20)
  7008. fig.draw_without_rendering()
  7009. def test_bar_label_location_errorbars():
  7010. ax = plt.gca()
  7011. xs, heights = [1, 2], [3, -4]
  7012. rects = ax.bar(xs, heights, yerr=1)
  7013. labels = ax.bar_label(rects)
  7014. assert labels[0].xy == (xs[0], heights[0] + 1)
  7015. assert labels[0].get_horizontalalignment() == 'center'
  7016. assert labels[0].get_verticalalignment() == 'bottom'
  7017. assert labels[1].xy == (xs[1], heights[1] - 1)
  7018. assert labels[1].get_horizontalalignment() == 'center'
  7019. assert labels[1].get_verticalalignment() == 'top'
  7020. @pytest.mark.parametrize('fmt', [
  7021. '%.2f', '{:.2f}', '{:.2f}'.format
  7022. ])
  7023. def test_bar_label_fmt(fmt):
  7024. ax = plt.gca()
  7025. rects = ax.bar([1, 2], [3, -4])
  7026. labels = ax.bar_label(rects, fmt=fmt)
  7027. assert labels[0].get_text() == '3.00'
  7028. assert labels[1].get_text() == '-4.00'
  7029. def test_bar_label_fmt_error():
  7030. ax = plt.gca()
  7031. rects = ax.bar([1, 2], [3, -4])
  7032. with pytest.raises(TypeError, match='str or callable'):
  7033. _ = ax.bar_label(rects, fmt=10)
  7034. def test_bar_label_labels():
  7035. ax = plt.gca()
  7036. rects = ax.bar([1, 2], [3, -4])
  7037. labels = ax.bar_label(rects, labels=['A', 'B'])
  7038. assert labels[0].get_text() == 'A'
  7039. assert labels[1].get_text() == 'B'
  7040. def test_bar_label_nan_ydata():
  7041. ax = plt.gca()
  7042. bars = ax.bar([2, 3], [np.nan, 1])
  7043. labels = ax.bar_label(bars)
  7044. assert [l.get_text() for l in labels] == ['', '1']
  7045. assert labels[0].xy == (2, 0)
  7046. assert labels[0].get_verticalalignment() == 'bottom'
  7047. def test_bar_label_nan_ydata_inverted():
  7048. ax = plt.gca()
  7049. ax.yaxis_inverted()
  7050. bars = ax.bar([2, 3], [np.nan, 1])
  7051. labels = ax.bar_label(bars)
  7052. assert [l.get_text() for l in labels] == ['', '1']
  7053. assert labels[0].xy == (2, 0)
  7054. assert labels[0].get_verticalalignment() == 'bottom'
  7055. def test_nan_barlabels():
  7056. fig, ax = plt.subplots()
  7057. bars = ax.bar([1, 2, 3], [np.nan, 1, 2], yerr=[0.2, 0.4, 0.6])
  7058. labels = ax.bar_label(bars)
  7059. assert [l.get_text() for l in labels] == ['', '1', '2']
  7060. assert np.allclose(ax.get_ylim(), (0.0, 3.0))
  7061. fig, ax = plt.subplots()
  7062. bars = ax.bar([1, 2, 3], [0, 1, 2], yerr=[0.2, np.nan, 0.6])
  7063. labels = ax.bar_label(bars)
  7064. assert [l.get_text() for l in labels] == ['0', '1', '2']
  7065. assert np.allclose(ax.get_ylim(), (-0.5, 3.0))
  7066. fig, ax = plt.subplots()
  7067. bars = ax.bar([1, 2, 3], [np.nan, 1, 2], yerr=[np.nan, np.nan, 0.6])
  7068. labels = ax.bar_label(bars)
  7069. assert [l.get_text() for l in labels] == ['', '1', '2']
  7070. assert np.allclose(ax.get_ylim(), (0.0, 3.0))
  7071. def test_patch_bounds(): # PR 19078
  7072. fig, ax = plt.subplots()
  7073. ax.add_patch(mpatches.Wedge((0, -1), 1.05, 60, 120, width=0.1))
  7074. bot = 1.9*np.sin(15*np.pi/180)**2
  7075. np.testing.assert_array_almost_equal_nulp(
  7076. np.array((-0.525, -(bot+0.05), 1.05, bot+0.1)), ax.dataLim.bounds, 16)
  7077. @mpl.style.context('default')
  7078. def test_warn_ignored_scatter_kwargs():
  7079. with pytest.warns(UserWarning,
  7080. match=r"You passed a edgecolor/edgecolors"):
  7081. plt.scatter([0], [0], marker="+", s=500, facecolor="r", edgecolor="b")
  7082. def test_artist_sublists():
  7083. fig, ax = plt.subplots()
  7084. lines = [ax.plot(np.arange(i, i + 5))[0] for i in range(6)]
  7085. col = ax.scatter(np.arange(5), np.arange(5))
  7086. im = ax.imshow(np.zeros((5, 5)))
  7087. patch = ax.add_patch(mpatches.Rectangle((0, 0), 5, 5))
  7088. text = ax.text(0, 0, 'foo')
  7089. # Get items, which should not be mixed.
  7090. assert list(ax.collections) == [col]
  7091. assert list(ax.images) == [im]
  7092. assert list(ax.lines) == lines
  7093. assert list(ax.patches) == [patch]
  7094. assert not ax.tables
  7095. assert list(ax.texts) == [text]
  7096. # Get items should work like lists/tuple.
  7097. assert ax.lines[0] is lines[0]
  7098. assert ax.lines[-1] is lines[-1]
  7099. with pytest.raises(IndexError, match='out of range'):
  7100. ax.lines[len(lines) + 1]
  7101. # Adding to other lists should produce a regular list.
  7102. assert ax.lines + [1, 2, 3] == [*lines, 1, 2, 3]
  7103. assert [1, 2, 3] + ax.lines == [1, 2, 3, *lines]
  7104. # Adding to other tuples should produce a regular tuples.
  7105. assert ax.lines + (1, 2, 3) == (*lines, 1, 2, 3)
  7106. assert (1, 2, 3) + ax.lines == (1, 2, 3, *lines)
  7107. # Lists should be empty after removing items.
  7108. col.remove()
  7109. assert not ax.collections
  7110. im.remove()
  7111. assert not ax.images
  7112. patch.remove()
  7113. assert not ax.patches
  7114. assert not ax.tables
  7115. text.remove()
  7116. assert not ax.texts
  7117. for ln in ax.lines:
  7118. ln.remove()
  7119. assert len(ax.lines) == 0
  7120. def test_empty_line_plots():
  7121. # Incompatible nr columns, plot "nothing"
  7122. x = np.ones(10)
  7123. y = np.ones((10, 0))
  7124. _, ax = plt.subplots()
  7125. line = ax.plot(x, y)
  7126. assert len(line) == 0
  7127. # Ensure plot([],[]) creates line
  7128. _, ax = plt.subplots()
  7129. line = ax.plot([], [])
  7130. assert len(line) == 1
  7131. @pytest.mark.parametrize('fmt, match', (
  7132. ("f", r"'f' is not a valid format string \(unrecognized character 'f'\)"),
  7133. ("o+", r"'o\+' is not a valid format string \(two marker symbols\)"),
  7134. (":-", r"':-' is not a valid format string \(two linestyle symbols\)"),
  7135. ("rk", r"'rk' is not a valid format string \(two color symbols\)"),
  7136. (":o-r", r"':o-r' is not a valid format string \(two linestyle symbols\)"),
  7137. ("C", r"'C' is not a valid format string \('C' must be followed by a number\)"),
  7138. (".C", r"'.C' is not a valid format string \('C' must be followed by a number\)"),
  7139. ))
  7140. @pytest.mark.parametrize("data", [None, {"string": range(3)}])
  7141. def test_plot_format_errors(fmt, match, data):
  7142. fig, ax = plt.subplots()
  7143. if data is not None:
  7144. match = match.replace("not", "neither a data key nor")
  7145. with pytest.raises(ValueError, match=r"\A" + match + r"\Z"):
  7146. ax.plot("string", fmt, data=data)
  7147. def test_plot_format():
  7148. fig, ax = plt.subplots()
  7149. line = ax.plot([1, 2, 3], '1.0')
  7150. assert line[0].get_color() == (1.0, 1.0, 1.0, 1.0)
  7151. assert line[0].get_marker() == 'None'
  7152. fig, ax = plt.subplots()
  7153. line = ax.plot([1, 2, 3], '1')
  7154. assert line[0].get_marker() == '1'
  7155. fig, ax = plt.subplots()
  7156. line = ax.plot([1, 2], [1, 2], '1.0', "1")
  7157. fig.canvas.draw()
  7158. assert line[0].get_color() == (1.0, 1.0, 1.0, 1.0)
  7159. assert ax.get_yticklabels()[0].get_text() == '1'
  7160. fig, ax = plt.subplots()
  7161. line = ax.plot([1, 2], [1, 2], '1', "1.0")
  7162. fig.canvas.draw()
  7163. assert line[0].get_marker() == '1'
  7164. assert ax.get_yticklabels()[0].get_text() == '1.0'
  7165. fig, ax = plt.subplots()
  7166. line = ax.plot([1, 2, 3], 'k3')
  7167. assert line[0].get_marker() == '3'
  7168. assert line[0].get_color() == 'k'
  7169. fig, ax = plt.subplots()
  7170. line = ax.plot([1, 2, 3], '.C12:')
  7171. assert line[0].get_marker() == '.'
  7172. assert line[0].get_color() == mcolors.to_rgba('C12')
  7173. assert line[0].get_linestyle() == ':'
  7174. def test_automatic_legend():
  7175. fig, ax = plt.subplots()
  7176. ax.plot("a", "b", data={"d": 2})
  7177. leg = ax.legend()
  7178. fig.canvas.draw()
  7179. assert leg.get_texts()[0].get_text() == 'a'
  7180. assert ax.get_yticklabels()[0].get_text() == 'a'
  7181. fig, ax = plt.subplots()
  7182. ax.plot("a", "b", "c", data={"d": 2})
  7183. leg = ax.legend()
  7184. fig.canvas.draw()
  7185. assert leg.get_texts()[0].get_text() == 'b'
  7186. assert ax.get_xticklabels()[0].get_text() == 'a'
  7187. assert ax.get_yticklabels()[0].get_text() == 'b'
  7188. def test_plot_errors():
  7189. with pytest.raises(TypeError, match=r"plot\(\) got an unexpected keyword"):
  7190. plt.plot([1, 2, 3], x=1)
  7191. with pytest.raises(ValueError, match=r"plot\(\) with multiple groups"):
  7192. plt.plot([1, 2, 3], [1, 2, 3], [2, 3, 4], [2, 3, 4], label=['1', '2'])
  7193. with pytest.raises(ValueError, match="x and y must have same first"):
  7194. plt.plot([1, 2, 3], [1])
  7195. with pytest.raises(ValueError, match="x and y can be no greater than"):
  7196. plt.plot(np.ones((2, 2, 2)))
  7197. with pytest.raises(ValueError, match="Using arbitrary long args with"):
  7198. plt.plot("a", "b", "c", "d", data={"a": 2})
  7199. def test_clim():
  7200. ax = plt.figure().add_subplot()
  7201. for plot_method in [
  7202. partial(ax.scatter, range(3), range(3), c=range(3)),
  7203. partial(ax.imshow, [[0, 1], [2, 3]]),
  7204. partial(ax.pcolor, [[0, 1], [2, 3]]),
  7205. partial(ax.pcolormesh, [[0, 1], [2, 3]]),
  7206. partial(ax.pcolorfast, [[0, 1], [2, 3]]),
  7207. ]:
  7208. clim = (7, 8)
  7209. norm = plot_method(clim=clim).norm
  7210. assert (norm.vmin, norm.vmax) == clim
  7211. def test_bezier_autoscale():
  7212. # Check that bezier curves autoscale to their curves, and not their
  7213. # control points
  7214. verts = [[-1, 0],
  7215. [0, -1],
  7216. [1, 0],
  7217. [1, 0]]
  7218. codes = [mpath.Path.MOVETO,
  7219. mpath.Path.CURVE3,
  7220. mpath.Path.CURVE3,
  7221. mpath.Path.CLOSEPOLY]
  7222. p = mpath.Path(verts, codes)
  7223. fig, ax = plt.subplots()
  7224. ax.add_patch(mpatches.PathPatch(p))
  7225. ax.autoscale()
  7226. # Bottom ylim should be at the edge of the curve (-0.5), and not include
  7227. # the control point (at -1)
  7228. assert ax.get_ylim()[0] == -0.5
  7229. def test_small_autoscale():
  7230. # Check that paths with small values autoscale correctly #24097.
  7231. verts = np.array([
  7232. [-5.45, 0.00], [-5.45, 0.00], [-5.29, 0.00], [-5.29, 0.00],
  7233. [-5.13, 0.00], [-5.13, 0.00], [-4.97, 0.00], [-4.97, 0.00],
  7234. [-4.81, 0.00], [-4.81, 0.00], [-4.65, 0.00], [-4.65, 0.00],
  7235. [-4.49, 0.00], [-4.49, 0.00], [-4.33, 0.00], [-4.33, 0.00],
  7236. [-4.17, 0.00], [-4.17, 0.00], [-4.01, 0.00], [-4.01, 0.00],
  7237. [-3.85, 0.00], [-3.85, 0.00], [-3.69, 0.00], [-3.69, 0.00],
  7238. [-3.53, 0.00], [-3.53, 0.00], [-3.37, 0.00], [-3.37, 0.00],
  7239. [-3.21, 0.00], [-3.21, 0.01], [-3.05, 0.01], [-3.05, 0.01],
  7240. [-2.89, 0.01], [-2.89, 0.01], [-2.73, 0.01], [-2.73, 0.02],
  7241. [-2.57, 0.02], [-2.57, 0.04], [-2.41, 0.04], [-2.41, 0.04],
  7242. [-2.25, 0.04], [-2.25, 0.06], [-2.09, 0.06], [-2.09, 0.08],
  7243. [-1.93, 0.08], [-1.93, 0.10], [-1.77, 0.10], [-1.77, 0.12],
  7244. [-1.61, 0.12], [-1.61, 0.14], [-1.45, 0.14], [-1.45, 0.17],
  7245. [-1.30, 0.17], [-1.30, 0.19], [-1.14, 0.19], [-1.14, 0.22],
  7246. [-0.98, 0.22], [-0.98, 0.25], [-0.82, 0.25], [-0.82, 0.27],
  7247. [-0.66, 0.27], [-0.66, 0.29], [-0.50, 0.29], [-0.50, 0.30],
  7248. [-0.34, 0.30], [-0.34, 0.32], [-0.18, 0.32], [-0.18, 0.33],
  7249. [-0.02, 0.33], [-0.02, 0.32], [0.13, 0.32], [0.13, 0.33], [0.29, 0.33],
  7250. [0.29, 0.31], [0.45, 0.31], [0.45, 0.30], [0.61, 0.30], [0.61, 0.28],
  7251. [0.77, 0.28], [0.77, 0.25], [0.93, 0.25], [0.93, 0.22], [1.09, 0.22],
  7252. [1.09, 0.19], [1.25, 0.19], [1.25, 0.17], [1.41, 0.17], [1.41, 0.15],
  7253. [1.57, 0.15], [1.57, 0.12], [1.73, 0.12], [1.73, 0.10], [1.89, 0.10],
  7254. [1.89, 0.08], [2.05, 0.08], [2.05, 0.07], [2.21, 0.07], [2.21, 0.05],
  7255. [2.37, 0.05], [2.37, 0.04], [2.53, 0.04], [2.53, 0.02], [2.69, 0.02],
  7256. [2.69, 0.02], [2.85, 0.02], [2.85, 0.01], [3.01, 0.01], [3.01, 0.01],
  7257. [3.17, 0.01], [3.17, 0.00], [3.33, 0.00], [3.33, 0.00], [3.49, 0.00],
  7258. [3.49, 0.00], [3.65, 0.00], [3.65, 0.00], [3.81, 0.00], [3.81, 0.00],
  7259. [3.97, 0.00], [3.97, 0.00], [4.13, 0.00], [4.13, 0.00], [4.29, 0.00],
  7260. [4.29, 0.00], [4.45, 0.00], [4.45, 0.00], [4.61, 0.00], [4.61, 0.00],
  7261. [4.77, 0.00], [4.77, 0.00], [4.93, 0.00], [4.93, 0.00],
  7262. ])
  7263. minx = np.min(verts[:, 0])
  7264. miny = np.min(verts[:, 1])
  7265. maxx = np.max(verts[:, 0])
  7266. maxy = np.max(verts[:, 1])
  7267. p = mpath.Path(verts)
  7268. fig, ax = plt.subplots()
  7269. ax.add_patch(mpatches.PathPatch(p))
  7270. ax.autoscale()
  7271. assert ax.get_xlim()[0] <= minx
  7272. assert ax.get_xlim()[1] >= maxx
  7273. assert ax.get_ylim()[0] <= miny
  7274. assert ax.get_ylim()[1] >= maxy
  7275. def test_get_xticklabel():
  7276. fig, ax = plt.subplots()
  7277. ax.plot(np.arange(10))
  7278. for ind in range(10):
  7279. assert ax.get_xticklabels()[ind].get_text() == f'{ind}'
  7280. assert ax.get_yticklabels()[ind].get_text() == f'{ind}'
  7281. def test_bar_leading_nan():
  7282. barx = np.arange(3, dtype=float)
  7283. barheights = np.array([0.5, 1.5, 2.0])
  7284. barstarts = np.array([0.77]*3)
  7285. barx[0] = np.nan
  7286. fig, ax = plt.subplots()
  7287. bars = ax.bar(barx, barheights, bottom=barstarts)
  7288. hbars = ax.barh(barx, barheights, left=barstarts)
  7289. for bar_set in (bars, hbars):
  7290. # the first bar should have a nan in the location
  7291. nanful, *rest = bar_set
  7292. assert (~np.isfinite(nanful.xy)).any()
  7293. assert np.isfinite(nanful.get_width())
  7294. for b in rest:
  7295. assert np.isfinite(b.xy).all()
  7296. assert np.isfinite(b.get_width())
  7297. @check_figures_equal(extensions=["png"])
  7298. def test_bar_all_nan(fig_test, fig_ref):
  7299. mpl.style.use("mpl20")
  7300. ax_test = fig_test.subplots()
  7301. ax_ref = fig_ref.subplots()
  7302. ax_test.bar([np.nan], [np.nan])
  7303. ax_test.bar([1], [1])
  7304. ax_ref.bar([1], [1]).remove()
  7305. ax_ref.bar([1], [1])
  7306. @image_comparison(["extent_units.png"], style="mpl20")
  7307. def test_extent_units():
  7308. _, axs = plt.subplots(2, 2)
  7309. date_first = np.datetime64('2020-01-01', 'D')
  7310. date_last = np.datetime64('2020-01-11', 'D')
  7311. arr = [[i+j for i in range(10)] for j in range(10)]
  7312. axs[0, 0].set_title('Date extents on y axis')
  7313. im = axs[0, 0].imshow(arr, origin='lower',
  7314. extent=[1, 11, date_first, date_last],
  7315. cmap=mpl.colormaps["plasma"])
  7316. axs[0, 1].set_title('Date extents on x axis (Day of Jan 2020)')
  7317. im = axs[0, 1].imshow(arr, origin='lower',
  7318. extent=[date_first, date_last, 1, 11],
  7319. cmap=mpl.colormaps["plasma"])
  7320. axs[0, 1].xaxis.set_major_formatter(mdates.DateFormatter('%d'))
  7321. im = axs[1, 0].imshow(arr, origin='lower',
  7322. extent=[date_first, date_last,
  7323. date_first, date_last],
  7324. cmap=mpl.colormaps["plasma"])
  7325. axs[1, 0].xaxis.set_major_formatter(mdates.DateFormatter('%d'))
  7326. axs[1, 0].set(xlabel='Day of Jan 2020')
  7327. im = axs[1, 1].imshow(arr, origin='lower',
  7328. cmap=mpl.colormaps["plasma"])
  7329. im.set_extent([date_last, date_first, date_last, date_first])
  7330. axs[1, 1].xaxis.set_major_formatter(mdates.DateFormatter('%d'))
  7331. axs[1, 1].set(xlabel='Day of Jan 2020')
  7332. with pytest.raises(TypeError, match=r"set_extent\(\) got an unexpected"):
  7333. im.set_extent([2, 12, date_first, date_last], clip=False)
  7334. def test_cla_clears_children_axes_and_fig():
  7335. fig, ax = plt.subplots()
  7336. lines = ax.plot([], [], [], [])
  7337. img = ax.imshow([[1]])
  7338. for art in lines + [img]:
  7339. assert art.axes is ax
  7340. assert art.get_figure() is fig
  7341. ax.clear()
  7342. for art in lines + [img]:
  7343. assert art.axes is None
  7344. assert art.get_figure() is None
  7345. def test_child_axes_removal():
  7346. fig, ax = plt.subplots()
  7347. marginal = ax.inset_axes([1, 0, .1, 1], sharey=ax)
  7348. marginal_twin = marginal.twinx()
  7349. marginal.remove()
  7350. ax.set(xlim=(-1, 1), ylim=(10, 20))
  7351. def test_scatter_color_repr_error():
  7352. def get_next_color(): # pragma: no cover
  7353. return 'blue' # currently unused
  7354. msg = (
  7355. r"'c' argument must be a color, a sequence of colors"
  7356. r", or a sequence of numbers, not 'red\\n'"
  7357. )
  7358. with pytest.raises(ValueError, match=msg):
  7359. c = 'red\n'
  7360. mpl.axes.Axes._parse_scatter_color_args(
  7361. c, None, kwargs={}, xsize=2, get_next_color_func=get_next_color)
  7362. def test_zorder_and_explicit_rasterization():
  7363. fig, ax = plt.subplots()
  7364. ax.set_rasterization_zorder(5)
  7365. ln, = ax.plot(range(5), rasterized=True, zorder=1)
  7366. with io.BytesIO() as b:
  7367. fig.savefig(b, format='pdf')
  7368. @image_comparison(["preset_clip_paths.png"], remove_text=True, style="mpl20",
  7369. tol=0 if platform.machine() == 'x86_64' else 0.027)
  7370. def test_preset_clip_paths():
  7371. fig, ax = plt.subplots()
  7372. poly = mpl.patches.Polygon(
  7373. [[1, 0], [0, 1], [-1, 0], [0, -1]], facecolor="#ddffdd",
  7374. edgecolor="#00ff00", linewidth=2, alpha=0.5)
  7375. ax.add_patch(poly)
  7376. line = mpl.lines.Line2D((-1, 1), (0.5, 0.5), clip_on=True, clip_path=poly)
  7377. line.set_path_effects([patheffects.withTickedStroke()])
  7378. ax.add_artist(line)
  7379. line = mpl.lines.Line2D((-1, 1), (-0.5, -0.5), color='r', clip_on=True,
  7380. clip_path=poly)
  7381. ax.add_artist(line)
  7382. poly2 = mpl.patches.Polygon(
  7383. [[-1, 1], [0, 1], [0, -0.25]], facecolor="#beefc0", alpha=0.3,
  7384. edgecolor="#faded0", linewidth=2, clip_on=True, clip_path=poly)
  7385. ax.add_artist(poly2)
  7386. # When text clipping works, the "Annotation" text should be clipped
  7387. ax.annotate('Annotation', (-0.75, -0.75), xytext=(0.1, 0.75),
  7388. arrowprops={'color': 'k'}, clip_on=True, clip_path=poly)
  7389. poly3 = mpl.patches.Polygon(
  7390. [[0, 0], [0, 0.5], [0.5, 0.5], [0.5, 0]], facecolor="g", edgecolor="y",
  7391. linewidth=2, alpha=0.3, clip_on=True, clip_path=poly)
  7392. fig.add_artist(poly3, clip=True)
  7393. ax.set_xlim(-1, 1)
  7394. ax.set_ylim(-1, 1)
  7395. @mpl.style.context('default')
  7396. def test_rc_axes_label_formatting():
  7397. mpl.rcParams['axes.labelcolor'] = 'red'
  7398. mpl.rcParams['axes.labelsize'] = 20
  7399. mpl.rcParams['axes.labelweight'] = 'bold'
  7400. ax = plt.axes()
  7401. assert ax.xaxis.label.get_color() == 'red'
  7402. assert ax.xaxis.label.get_fontsize() == 20
  7403. assert ax.xaxis.label.get_fontweight() == 'bold'
  7404. @check_figures_equal(extensions=["png"])
  7405. def test_ecdf(fig_test, fig_ref):
  7406. data = np.array([0, -np.inf, -np.inf, np.inf, 1, 1, 2])
  7407. weights = range(len(data))
  7408. axs_test = fig_test.subplots(1, 2)
  7409. for ax, orientation in zip(axs_test, ["vertical", "horizontal"]):
  7410. l0 = ax.ecdf(data, orientation=orientation)
  7411. l1 = ax.ecdf("d", "w", data={"d": np.ma.array(data), "w": weights},
  7412. orientation=orientation,
  7413. complementary=True, compress=True, ls=":")
  7414. assert len(l0.get_xdata()) == (~np.isnan(data)).sum() + 1
  7415. assert len(l1.get_xdata()) == len({*data[~np.isnan(data)]}) + 1
  7416. axs_ref = fig_ref.subplots(1, 2)
  7417. axs_ref[0].plot([-np.inf, -np.inf, -np.inf, 0, 1, 1, 2, np.inf],
  7418. np.arange(8) / 7, ds="steps-post")
  7419. axs_ref[0].plot([-np.inf, 0, 1, 2, np.inf, np.inf],
  7420. np.array([21, 20, 18, 14, 3, 0]) / 21,
  7421. ds="steps-pre", ls=":")
  7422. axs_ref[1].plot(np.arange(8) / 7,
  7423. [-np.inf, -np.inf, -np.inf, 0, 1, 1, 2, np.inf],
  7424. ds="steps-pre")
  7425. axs_ref[1].plot(np.array([21, 20, 18, 14, 3, 0]) / 21,
  7426. [-np.inf, 0, 1, 2, np.inf, np.inf],
  7427. ds="steps-post", ls=":")
  7428. def test_ecdf_invalid():
  7429. with pytest.raises(ValueError):
  7430. plt.ecdf([1, np.nan])
  7431. with pytest.raises(ValueError):
  7432. plt.ecdf(np.ma.array([1, 2], mask=[True, False]))
  7433. def test_fill_between_axes_limits():
  7434. fig, ax = plt.subplots()
  7435. x = np.arange(0, 4 * np.pi, 0.01)
  7436. y = 0.1*np.sin(x)
  7437. threshold = 0.075
  7438. ax.plot(x, y, color='black')
  7439. original_lims = (ax.get_xlim(), ax.get_ylim())
  7440. ax.axhline(threshold, color='green', lw=2, alpha=0.7)
  7441. ax.fill_between(x, 0, 1, where=y > threshold,
  7442. color='green', alpha=0.5, transform=ax.get_xaxis_transform())
  7443. assert (ax.get_xlim(), ax.get_ylim()) == original_lims
  7444. def test_tick_param_labelfont():
  7445. fig, ax = plt.subplots()
  7446. ax.plot([1, 2, 3, 4], [1, 2, 3, 4])
  7447. ax.set_xlabel('X label in Impact font', fontname='Impact')
  7448. ax.set_ylabel('Y label in xkcd script', fontname='xkcd script')
  7449. ax.tick_params(color='r', labelfontfamily='monospace')
  7450. plt.title('Title in sans-serif')
  7451. for text in ax.get_xticklabels():
  7452. assert text.get_fontfamily()[0] == 'monospace'
  7453. def test_set_secondary_axis_color():
  7454. fig, ax = plt.subplots()
  7455. sax = ax.secondary_xaxis("top", color="red")
  7456. assert mcolors.same_color(sax.spines["bottom"].get_edgecolor(), "red")
  7457. assert mcolors.same_color(sax.spines["top"].get_edgecolor(), "red")
  7458. assert mcolors.same_color(sax.xaxis.get_tick_params()["color"], "red")
  7459. assert mcolors.same_color(sax.xaxis.get_tick_params()["labelcolor"], "red")
  7460. assert mcolors.same_color(sax.xaxis.label.get_color(), "red")
  7461. def test_xylim_changed_shared():
  7462. fig, axs = plt.subplots(2, sharex=True, sharey=True)
  7463. events = []
  7464. axs[1].callbacks.connect("xlim_changed", events.append)
  7465. axs[1].callbacks.connect("ylim_changed", events.append)
  7466. axs[0].set(xlim=[1, 3], ylim=[2, 4])
  7467. assert events == [axs[1], axs[1]]
  7468. @image_comparison(["axhvlinespan_interpolation.png"], style="default")
  7469. def test_axhvlinespan_interpolation():
  7470. ax = plt.figure().add_subplot(projection="polar")
  7471. ax.set_axis_off()
  7472. ax.axvline(.1, c="C0")
  7473. ax.axvspan(.2, .3, fc="C1")
  7474. ax.axvspan(.4, .5, .1, .2, fc="C2")
  7475. ax.axhline(1, c="C0", alpha=.5)
  7476. ax.axhspan(.8, .9, fc="C1", alpha=.5)
  7477. ax.axhspan(.6, .7, .8, .9, fc="C2", alpha=.5)
  7478. @check_figures_equal(extensions=["png"])
  7479. @pytest.mark.parametrize("which", ("x", "y"))
  7480. def test_axes_clear_behavior(fig_ref, fig_test, which):
  7481. """Test that the given tick params are not reset by ax.clear()."""
  7482. ax_test = fig_test.subplots()
  7483. ax_ref = fig_ref.subplots()
  7484. # the following tick params values are chosen to each create a visual difference
  7485. # from their defaults
  7486. target = {
  7487. "direction": "in",
  7488. "length": 10,
  7489. "width": 10,
  7490. "color": "xkcd:wine red",
  7491. "pad": 0,
  7492. "labelfontfamily": "serif",
  7493. "zorder": 7,
  7494. "labelrotation": 45,
  7495. "labelcolor": "xkcd:shocking pink",
  7496. # this overrides color + labelcolor, skip
  7497. # colors: ,
  7498. "grid_color": "xkcd:fluorescent green",
  7499. "grid_alpha": 0.5,
  7500. "grid_linewidth": 3,
  7501. "grid_linestyle": ":",
  7502. "bottom": False,
  7503. "top": True,
  7504. "left": False,
  7505. "right": True,
  7506. "labelbottom": True,
  7507. "labeltop": True,
  7508. "labelleft": True,
  7509. "labelright": True,
  7510. }
  7511. ax_ref.tick_params(axis=which, **target)
  7512. ax_test.tick_params(axis=which, **target)
  7513. ax_test.clear()
  7514. ax_ref.grid(True)
  7515. ax_test.grid(True)
  7516. @pytest.mark.skipif(
  7517. sys.version_info[:3] == (3, 13, 0) and sys.version_info.releaselevel != "final",
  7518. reason="https://github.com/python/cpython/issues/124538",
  7519. )
  7520. def test_axes_clear_reference_cycle():
  7521. def assert_not_in_reference_cycle(start):
  7522. # Breadth first search. Return True if we encounter the starting node
  7523. to_visit = deque([start])
  7524. explored = set()
  7525. while len(to_visit) > 0:
  7526. parent = to_visit.popleft()
  7527. for child in gc.get_referents(parent):
  7528. if id(child) in explored:
  7529. continue
  7530. assert child is not start
  7531. explored.add(id(child))
  7532. to_visit.append(child)
  7533. fig = Figure()
  7534. ax = fig.add_subplot()
  7535. points = np.random.rand(1000)
  7536. ax.plot(points, points)
  7537. ax.scatter(points, points)
  7538. ax_children = ax.get_children()
  7539. fig.clear() # This should break the reference cycle
  7540. # Care most about the objects that scale with number of points
  7541. big_artists = [
  7542. a for a in ax_children
  7543. if isinstance(a, (Line2D, PathCollection))
  7544. ]
  7545. assert len(big_artists) > 0
  7546. for big_artist in big_artists:
  7547. assert_not_in_reference_cycle(big_artist)
  7548. assert len(ax_children) > 0
  7549. for child in ax_children:
  7550. # Make sure this doesn't raise because the child is already removed.
  7551. try:
  7552. child.remove()
  7553. except NotImplementedError:
  7554. pass # not implemented is expected for some artists
  7555. def test_boxplot_tick_labels():
  7556. # Test the renamed `tick_labels` parameter.
  7557. # Test for deprecation of old name `labels`.
  7558. np.random.seed(19680801)
  7559. data = np.random.random((10, 3))
  7560. fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True)
  7561. # Should get deprecation warning for `labels`
  7562. with pytest.warns(mpl.MatplotlibDeprecationWarning,
  7563. match='has been renamed \'tick_labels\''):
  7564. axs[0].boxplot(data, labels=['A', 'B', 'C'])
  7565. assert [l.get_text() for l in axs[0].get_xticklabels()] == ['A', 'B', 'C']
  7566. # Test the new tick_labels parameter
  7567. axs[1].boxplot(data, tick_labels=['A', 'B', 'C'])
  7568. assert [l.get_text() for l in axs[1].get_xticklabels()] == ['A', 'B', 'C']
  7569. @needs_usetex
  7570. @check_figures_equal(extensions=['png'])
  7571. def test_latex_pie_percent(fig_test, fig_ref):
  7572. data = [20, 10, 70]
  7573. ax = fig_test.subplots()
  7574. ax.pie(data, autopct="%1.0f%%", textprops={'usetex': True})
  7575. ax1 = fig_ref.subplots()
  7576. ax1.pie(data, autopct=r"%1.0f\%%", textprops={'usetex': True})
  7577. @check_figures_equal(extensions=['png'])
  7578. def test_violinplot_orientation(fig_test, fig_ref):
  7579. # Test the `orientation : {'vertical', 'horizontal'}`
  7580. # parameter and deprecation of `vert: bool`.
  7581. fig, axs = plt.subplots(nrows=1, ncols=3)
  7582. np.random.seed(19680801)
  7583. all_data = [np.random.normal(0, std, 100) for std in range(6, 10)]
  7584. axs[0].violinplot(all_data) # Default vertical plot.
  7585. # xticks and yticks should be at their default position.
  7586. assert all(axs[0].get_xticks() == np.array(
  7587. [0.5, 1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5]))
  7588. assert all(axs[0].get_yticks() == np.array(
  7589. [-30., -20., -10., 0., 10., 20., 30.]))
  7590. # Horizontal plot using new `orientation` keyword.
  7591. axs[1].violinplot(all_data, orientation='horizontal')
  7592. # xticks and yticks should be swapped.
  7593. assert all(axs[1].get_xticks() == np.array(
  7594. [-30., -20., -10., 0., 10., 20., 30.]))
  7595. assert all(axs[1].get_yticks() == np.array(
  7596. [0.5, 1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5]))
  7597. plt.close()
  7598. # Compare images between a figure that
  7599. # uses vert and one that uses orientation.
  7600. ax_ref = fig_ref.subplots()
  7601. with pytest.warns(PendingDeprecationWarning, match='vert: bool'):
  7602. ax_ref.violinplot(all_data, vert=False)
  7603. ax_test = fig_test.subplots()
  7604. ax_test.violinplot(all_data, orientation='horizontal')
  7605. @check_figures_equal(extensions=['png'])
  7606. def test_boxplot_orientation(fig_test, fig_ref):
  7607. # Test the `orientation : {'vertical', 'horizontal'}`
  7608. # parameter and deprecation of `vert: bool`.
  7609. fig, axs = plt.subplots(nrows=1, ncols=2)
  7610. np.random.seed(19680801)
  7611. all_data = [np.random.normal(0, std, 100) for std in range(6, 10)]
  7612. axs[0].boxplot(all_data) # Default vertical plot.
  7613. # xticks and yticks should be at their default position.
  7614. assert all(axs[0].get_xticks() == np.array(
  7615. [1, 2, 3, 4]))
  7616. assert all(axs[0].get_yticks() == np.array(
  7617. [-30., -20., -10., 0., 10., 20., 30.]))
  7618. # Horizontal plot using new `orientation` keyword.
  7619. axs[1].boxplot(all_data, orientation='horizontal')
  7620. # xticks and yticks should be swapped.
  7621. assert all(axs[1].get_xticks() == np.array(
  7622. [-30., -20., -10., 0., 10., 20., 30.]))
  7623. assert all(axs[1].get_yticks() == np.array(
  7624. [1, 2, 3, 4]))
  7625. plt.close()
  7626. # Deprecation of `vert: bool` keyword and
  7627. # 'boxplot.vertical' rcparam.
  7628. with pytest.warns(mpl.MatplotlibDeprecationWarning,
  7629. match='was deprecated in Matplotlib 3.10'):
  7630. # Compare images between a figure that
  7631. # uses vert and one that uses orientation.
  7632. with mpl.rc_context({'boxplot.vertical': False}):
  7633. ax_ref = fig_ref.subplots()
  7634. ax_ref.boxplot(all_data)
  7635. ax_test = fig_test.subplots()
  7636. ax_test.boxplot(all_data, orientation='horizontal')
  7637. @image_comparison(["use_colorizer_keyword.png"],
  7638. tol=0 if platform.machine() == 'x86_64' else 0.05)
  7639. def test_use_colorizer_keyword():
  7640. # test using the colorizer keyword
  7641. np.random.seed(0)
  7642. rand_x = np.random.random(100)
  7643. rand_y = np.random.random(100)
  7644. c = np.arange(25, dtype='float32').reshape((5, 5))
  7645. fig, axes = plt.subplots(3, 4)
  7646. norm = mpl.colors.Normalize(4, 20)
  7647. cl = mpl.colorizer.Colorizer(norm=norm, cmap='RdBu')
  7648. axes[0, 0].scatter(c, c, c=c, colorizer=cl)
  7649. axes[0, 1].hexbin(rand_x, rand_y, colorizer=cl, gridsize=(2, 2))
  7650. axes[0, 2].imshow(c, colorizer=cl)
  7651. axes[0, 3].pcolor(c, colorizer=cl)
  7652. axes[1, 0].pcolormesh(c, colorizer=cl)
  7653. axes[1, 1].pcolorfast(c, colorizer=cl) # style = image
  7654. axes[1, 2].pcolorfast((0, 1, 2, 3, 4, 5), (0, 1, 2, 3, 5, 6), c,
  7655. colorizer=cl) # style = pcolorimage
  7656. axes[1, 3].pcolorfast(c.T, c, c[:4, :4], colorizer=cl) # style = quadmesh
  7657. axes[2, 0].contour(c, colorizer=cl)
  7658. axes[2, 1].contourf(c, colorizer=cl)
  7659. axes[2, 2].tricontour(c.T.ravel(), c.ravel(), c.ravel(), colorizer=cl)
  7660. axes[2, 3].tricontourf(c.T.ravel(), c.ravel(), c.ravel(), colorizer=cl)
  7661. fig.figimage(np.repeat(np.repeat(c, 15, axis=0), 15, axis=1), colorizer=cl)
  7662. remove_ticks_and_titles(fig)
  7663. def test_wrong_use_colorizer():
  7664. # test using the colorizer keyword and norm or cmap
  7665. np.random.seed(0)
  7666. rand_x = np.random.random(100)
  7667. rand_y = np.random.random(100)
  7668. c = np.arange(25, dtype='float32').reshape((5, 5))
  7669. fig, axes = plt.subplots(3, 4)
  7670. norm = mpl.colors.Normalize(4, 20)
  7671. cl = mpl.colorizer.Colorizer(norm=norm, cmap='RdBu')
  7672. match_str = "The `colorizer` keyword cannot be used simultaneously"
  7673. kwrds = [{'vmin': 0}, {'vmax': 0}, {'norm': 'log'}, {'cmap': 'viridis'}]
  7674. for kwrd in kwrds:
  7675. with pytest.raises(ValueError, match=match_str):
  7676. axes[0, 0].scatter(c, c, c=c, colorizer=cl, **kwrd)
  7677. for kwrd in kwrds:
  7678. with pytest.raises(ValueError, match=match_str):
  7679. axes[0, 0].scatter(c, c, c=c, colorizer=cl, **kwrd)
  7680. for kwrd in kwrds:
  7681. with pytest.raises(ValueError, match=match_str):
  7682. axes[0, 1].hexbin(rand_x, rand_y, colorizer=cl, gridsize=(2, 2), **kwrd)
  7683. for kwrd in kwrds:
  7684. with pytest.raises(ValueError, match=match_str):
  7685. axes[0, 2].imshow(c, colorizer=cl, **kwrd)
  7686. for kwrd in kwrds:
  7687. with pytest.raises(ValueError, match=match_str):
  7688. axes[0, 3].pcolor(c, colorizer=cl, **kwrd)
  7689. for kwrd in kwrds:
  7690. with pytest.raises(ValueError, match=match_str):
  7691. axes[1, 0].pcolormesh(c, colorizer=cl, **kwrd)
  7692. for kwrd in kwrds:
  7693. with pytest.raises(ValueError, match=match_str):
  7694. axes[1, 1].pcolorfast(c, colorizer=cl, **kwrd) # style = image
  7695. for kwrd in kwrds:
  7696. with pytest.raises(ValueError, match=match_str):
  7697. axes[1, 2].pcolorfast((0, 1, 2, 3, 4, 5), (0, 1, 2, 3, 5, 6), c,
  7698. colorizer=cl, **kwrd) # style = pcolorimage
  7699. for kwrd in kwrds:
  7700. with pytest.raises(ValueError, match=match_str):
  7701. axes[1, 3].pcolorfast(c.T, c, c[:4, :4], colorizer=cl, **kwrd) # quadmesh
  7702. for kwrd in kwrds:
  7703. with pytest.raises(ValueError, match=match_str):
  7704. axes[2, 0].contour(c, colorizer=cl, **kwrd)
  7705. for kwrd in kwrds:
  7706. with pytest.raises(ValueError, match=match_str):
  7707. axes[2, 1].contourf(c, colorizer=cl, **kwrd)
  7708. for kwrd in kwrds:
  7709. with pytest.raises(ValueError, match=match_str):
  7710. axes[2, 2].tricontour(c.T.ravel(), c.ravel(), c.ravel(), colorizer=cl,
  7711. **kwrd)
  7712. for kwrd in kwrds:
  7713. with pytest.raises(ValueError, match=match_str):
  7714. axes[2, 3].tricontourf(c.T.ravel(), c.ravel(), c.ravel(), colorizer=cl,
  7715. **kwrd)
  7716. for kwrd in kwrds:
  7717. with pytest.raises(ValueError, match=match_str):
  7718. fig.figimage(c, colorizer=cl, **kwrd)
  7719. def test_bar_color_precedence():
  7720. # Test the precedence of 'color' and 'facecolor' in bar plots
  7721. fig, ax = plt.subplots()
  7722. # case 1: no color specified
  7723. bars = ax.bar([1, 2, 3], [4, 5, 6])
  7724. for bar in bars:
  7725. assert mcolors.same_color(bar.get_facecolor(), 'blue')
  7726. # case 2: Only 'color'
  7727. bars = ax.bar([11, 12, 13], [4, 5, 6], color='red')
  7728. for bar in bars:
  7729. assert mcolors.same_color(bar.get_facecolor(), 'red')
  7730. # case 3: Only 'facecolor'
  7731. bars = ax.bar([21, 22, 23], [4, 5, 6], facecolor='yellow')
  7732. for bar in bars:
  7733. assert mcolors.same_color(bar.get_facecolor(), 'yellow')
  7734. # case 4: 'facecolor' and 'color'
  7735. bars = ax.bar([31, 32, 33], [4, 5, 6], color='red', facecolor='green')
  7736. for bar in bars:
  7737. assert mcolors.same_color(bar.get_facecolor(), 'green')
  7738. @check_figures_equal(extensions=['png'])
  7739. def test_axes_set_position_external_bbox_unchanged(fig_test, fig_ref):
  7740. # From #29410: Modifying Axes' position also alters the original Bbox
  7741. # object used for initialization
  7742. bbox = mtransforms.Bbox([[0.0, 0.0], [1.0, 1.0]])
  7743. ax_test = fig_test.add_axes(bbox)
  7744. ax_test.set_position([0.25, 0.25, 0.5, 0.5])
  7745. assert (bbox.x0, bbox.y0, bbox.width, bbox.height) == (0.0, 0.0, 1.0, 1.0)
  7746. ax_ref = fig_ref.add_axes([0.25, 0.25, 0.5, 0.5])
  7747. def test_caps_color():
  7748. # Creates a simple plot with error bars and a specified ecolor
  7749. x = np.linspace(0, 10, 10)
  7750. mpl.rcParams['lines.markeredgecolor'] = 'green'
  7751. ecolor = 'red'
  7752. fig, ax = plt.subplots()
  7753. errorbars = ax.errorbar(x, np.sin(x), yerr=0.1, ecolor=ecolor)
  7754. # Tests if the caps have the specified color
  7755. for cap in errorbars[2]:
  7756. assert mcolors.same_color(cap.get_edgecolor(), ecolor)
  7757. def test_caps_no_ecolor():
  7758. # Creates a simple plot with error bars without specifying ecolor
  7759. x = np.linspace(0, 10, 10)
  7760. mpl.rcParams['lines.markeredgecolor'] = 'green'
  7761. fig, ax = plt.subplots()
  7762. errorbars = ax.errorbar(x, np.sin(x), yerr=0.1)
  7763. # Tests if the caps have the default color (blue)
  7764. for cap in errorbars[2]:
  7765. assert mcolors.same_color(cap.get_edgecolor(), "blue")